]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'omap-for-v3.11/fixes-for-merge-window' of git://git.kernel.org/pub/scm...
authorOlof Johansson <olof@lixom.net>
Fri, 12 Jul 2013 17:59:39 +0000 (10:59 -0700)
committerOlof Johansson <olof@lixom.net>
Fri, 12 Jul 2013 17:59:39 +0000 (10:59 -0700)
Omap fixes and minor defconfig updates that would be good to
get in before -rc1.

* tag 'omap-for-v3.11/fixes-for-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap:
  ARM: OMAP2+: omap2plus_defconfig: Enable appended DTB support
  ARM: OMAP2+: Enable TI_EDMA in omap2plus_defconfig
  ARM: OMAP2+: omap2plus_defconfig: enable DRA752 thermal support by default
  ARM: OMAP2+: omap2plus_defconfig: enable TI bandgap driver
  ARM: OMAP2+: devices: remove duplicated include from devices.c
  ARM: OMAP3: igep0020: Set DSS pins in correct mux mode.
  ARM: OMAP2+: N900: enable N900-specific drivers even if device tree is enabled
  ARM: OMAP2+: Cocci spatch "ptr_ret.spatch"
  ARM: OMAP2+: Remove obsolete Makefile line
  ARM: OMAP5: Enable Cortex A15 errata 798181
  ARM: scu: provide inline dummy functions when SCU is not present
  ARM: OMAP4: sleep: build OMAP4 specific functions only for OMAP4
  ARM: OMAP2+: timer: initialize before using oh_name

Signed-off-by: Olof Johansson <olof@lixom.net>
Add/move/change conflicts in arch/arm/mach-omap2/Kconfig resolved.

2265 files changed:
Documentation/ABI/testing/sysfs-bus-acpi [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-event_source-devices-events
Documentation/ABI/testing/sysfs-bus-event_source-devices-format
Documentation/ABI/testing/sysfs-class-devfreq
Documentation/ABI/testing/sysfs-devices-online [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-sun
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/ABI/testing/sysfs-firmware-acpi
Documentation/CodingStyle
Documentation/DocBook/device-drivers.tmpl
Documentation/DocBook/genericirq.tmpl
Documentation/DocBook/kernel-locking.tmpl
Documentation/RCU/checklist.txt
Documentation/RCU/torture.txt
Documentation/RCU/trace.txt
Documentation/RCU/whatisRCU.txt
Documentation/accounting/getdelays.c
Documentation/acpi/apei/einj.txt
Documentation/acpi/namespace.txt [new file with mode: 0644]
Documentation/acpi/video_extension.txt [new file with mode: 0644]
Documentation/arm64/memory.txt
Documentation/cgroups/cpusets.txt
Documentation/cgroups/memory.txt
Documentation/cpu-freq/cpu-drivers.txt
Documentation/cpu-hotplug.txt
Documentation/crypto/async-tx-api.txt
Documentation/devices.txt
Documentation/devicetree/bindings/arm/l2cc.txt
Documentation/devicetree/bindings/ata/ahci-platform.txt
Documentation/devicetree/bindings/clock/nspire-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/rockchip.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/silabs,si5351.txt
Documentation/devicetree/bindings/clock/sunxi.txt
Documentation/devicetree/bindings/clock/sunxi/sun4i-a10-gates.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/sunxi/sun5i-a13-gates.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/vt8500.txt
Documentation/devicetree/bindings/gpio/gpio-xilinx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/hwmon/g762.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/ina2xx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/leds/leds-lp55xx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/arizona.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/max77693.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/img,tz1090-pdc-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/ste,abx500.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pps/pps-gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/lp872x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/max8973-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/regulator.txt
Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/adi,adau1701.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mxs-saif.txt
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5640.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/sgtl5000.txt
Documentation/devicetree/bindings/sound/spdif-receiver.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/spdif-transmitter.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/ssm2518.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/ti,tas5086.txt
Documentation/devicetree/bindings/sound/wm8962.txt
Documentation/devicetree/bindings/spi/omap-spi.txt
Documentation/filesystems/Locking
Documentation/filesystems/proc.txt
Documentation/filesystems/vfs.txt
Documentation/hwmon/ds1621
Documentation/hwmon/g762 [new file with mode: 0644]
Documentation/hwmon/ina2xx
Documentation/i2c/busses/i2c-piix4
Documentation/ioctl/ioctl-number.txt
Documentation/kdump/kdump.txt
Documentation/kernel-parameters.txt
Documentation/kernel-per-CPU-kthreads.txt
Documentation/pinctrl.txt
Documentation/power/pm_qos_interface.txt
Documentation/power/runtime_pm.txt
Documentation/power/video_extension.txt [deleted file]
Documentation/rapidio/rapidio.txt
Documentation/rapidio/sysfs.txt
Documentation/rt-mutex-design.txt
Documentation/rtc.txt
Documentation/scheduler/sched-domains.txt
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/spinlocks.txt
Documentation/sysctl/kernel.txt
Documentation/timers/NO_HZ.txt
Documentation/trace/events-nmi.txt [new file with mode: 0644]
Documentation/trace/events-power.txt
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/mmu.txt
Documentation/virtual/uml/UserModeLinux-HOWTO.txt
Documentation/vm/pagemap.txt
Documentation/vm/soft-dirty.txt [new file with mode: 0644]
Documentation/ww-mutex-design.txt [new file with mode: 0644]
Documentation/x86/early-microcode.txt
MAINTAINERS
arch/Kconfig
arch/alpha/include/asm/mmzone.h
arch/alpha/include/uapi/asm/fcntl.h
arch/alpha/kernel/sys_nautilus.c
arch/alpha/mm/init.c
arch/alpha/mm/numa.c
arch/arc/Kconfig
arch/arc/Makefile
arch/arc/configs/fpga_defconfig
arch/arc/configs/nsimosci_defconfig
arch/arc/configs/tb10x_defconfig
arch/arc/include/asm/arcregs.h
arch/arc/include/asm/bug.h
arch/arc/include/asm/cache.h
arch/arc/include/asm/cacheflush.h
arch/arc/include/asm/defines.h [deleted file]
arch/arc/include/asm/entry.h
arch/arc/include/asm/irq.h
arch/arc/include/asm/irqflags.h
arch/arc/include/asm/kgdb.h
arch/arc/include/asm/kprobes.h
arch/arc/include/asm/mmu.h
arch/arc/include/asm/page.h
arch/arc/include/asm/pgtable.h
arch/arc/include/asm/processor.h
arch/arc/include/asm/ptrace.h
arch/arc/include/asm/syscall.h
arch/arc/include/asm/tlb-mmu1.h
arch/arc/include/asm/tlb.h
arch/arc/include/asm/unaligned.h
arch/arc/include/uapi/asm/ptrace.h
arch/arc/kernel/asm-offsets.c
arch/arc/kernel/ctx_sw.c
arch/arc/kernel/entry.S
arch/arc/kernel/head.S
arch/arc/kernel/irq.c
arch/arc/kernel/kgdb.c
arch/arc/kernel/kprobes.c
arch/arc/kernel/process.c
arch/arc/kernel/ptrace.c
arch/arc/kernel/setup.c
arch/arc/kernel/smp.c
arch/arc/kernel/stacktrace.c
arch/arc/kernel/time.c
arch/arc/kernel/traps.c
arch/arc/kernel/troubleshoot.c
arch/arc/kernel/unaligned.c
arch/arc/kernel/unwind.c
arch/arc/kernel/vmlinux.lds.S
arch/arc/mm/cache_arc700.c
arch/arc/mm/fault.c
arch/arc/mm/init.c
arch/arc/mm/tlb.c
arch/arc/mm/tlbex.S
arch/arc/plat-arcfpga/platform.c
arch/arm/Kconfig
arch/arm/Kconfig-nommu
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/atags_to_fdt.c
arch/arm/boot/compressed/head.S
arch/arm/boot/dts/atlas6.dtsi
arch/arm/boot/dts/bcm11351.dtsi
arch/arm/boot/dts/ecx-common.dtsi
arch/arm/boot/dts/prima2.dtsi
arch/arm/common/mcpm_head.S
arch/arm/common/mcpm_platsmp.c
arch/arm/configs/omap2plus_defconfig
arch/arm/include/asm/arch_timer.h
arch/arm/include/asm/cp15.h
arch/arm/include/asm/cputype.h
arch/arm/include/asm/div64.h
arch/arm/include/asm/glue-proc.h
arch/arm/include/asm/hugetlb-3level.h [new file with mode: 0644]
arch/arm/include/asm/hugetlb.h [new file with mode: 0644]
arch/arm/include/asm/io.h
arch/arm/include/asm/kvm_arm.h
arch/arm/include/asm/kvm_asm.h
arch/arm/include/asm/kvm_emulate.h
arch/arm/include/asm/kvm_host.h
arch/arm/include/asm/memory.h
arch/arm/include/asm/mmu_context.h
arch/arm/include/asm/mpu.h [new file with mode: 0644]
arch/arm/include/asm/page.h
arch/arm/include/asm/pgtable-3level-hwdef.h
arch/arm/include/asm/pgtable-3level.h
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/proc-fns.h
arch/arm/include/asm/smp.h
arch/arm/include/asm/smp_plat.h
arch/arm/include/asm/smp_scu.h
arch/arm/include/asm/spinlock.h
arch/arm/include/asm/suspend.h
arch/arm/include/asm/thread_info.h
arch/arm/include/asm/tlb.h
arch/arm/include/asm/tlbflush.h
arch/arm/include/asm/tls.h
arch/arm/include/asm/xen/page.h
arch/arm/include/debug/vexpress.S
arch/arm/include/uapi/asm/hwcap.h
arch/arm/kernel/Makefile
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/head-nommu.S
arch/arm/kernel/head.S
arch/arm/kernel/hyp-stub.S
arch/arm/kernel/perf_event.c
arch/arm/kernel/process.c
arch/arm/kernel/psci_smp.c
arch/arm/kernel/ptrace.c
arch/arm/kernel/setup.c
arch/arm/kernel/signal.c
arch/arm/kernel/sleep.S
arch/arm/kernel/smp.c
arch/arm/kernel/smp_tlb.c
arch/arm/kernel/suspend.c
arch/arm/kernel/traps.c
arch/arm/kvm/Kconfig
arch/arm/kvm/Makefile
arch/arm/kvm/arm.c
arch/arm/kvm/coproc.c
arch/arm/kvm/handle_exit.c
arch/arm/kvm/interrupts.S
arch/arm/kvm/interrupts_head.S
arch/arm/kvm/mmio.c
arch/arm/kvm/mmu.c
arch/arm/kvm/psci.c
arch/arm/kvm/reset.c
arch/arm/mach-davinci/Kconfig
arch/arm/mach-davinci/da850.c
arch/arm/mach-ebsa110/core.c
arch/arm/mach-exynos/Kconfig
arch/arm/mach-imx/mach-mx31moboard.c
arch/arm/mach-imx/mm-imx3.c
arch/arm/mach-iop13xx/io.c
arch/arm/mach-iop13xx/setup.c
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-msm/common.h
arch/arm/mach-msm/io.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-rx51-video.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/fb.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/omap_device.c
arch/arm/mach-omap2/pmu.c
arch/arm/mach-omap2/sleep44xx.S
arch/arm/mach-omap2/smartreflex-class3.c
arch/arm/mach-omap2/timer.c
arch/arm/mach-pxa/Kconfig
arch/arm/mach-s3c24xx/cpufreq-utils.c
arch/arm/mach-s3c24xx/pll-s3c2410.c
arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c
arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/common.c
arch/arm/mach-ux500/cpu.c
arch/arm/mach-virt/Kconfig
arch/arm/mm/Kconfig
arch/arm/mm/Makefile
arch/arm/mm/cache-l2x0.c
arch/arm/mm/context.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/fault.c
arch/arm/mm/flush.c
arch/arm/mm/fsr-3level.c
arch/arm/mm/hugetlbpage.c [new file with mode: 0644]
arch/arm/mm/init.c
arch/arm/mm/ioremap.c
arch/arm/mm/mmu.c
arch/arm/mm/nommu.c
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7-3level.S
arch/arm/mm/proc-v7.S
arch/arm/plat-iop/adma.c
arch/arm/plat-orion/common.c
arch/arm/plat-orion/gpio.c
arch/arm/plat-samsung/include/plat/cpu-freq-core.h
arch/arm/plat-versatile/headsmp.S
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/boot/dts/Makefile
arch/arm64/boot/dts/apm-mustang.dts [new file with mode: 0644]
arch/arm64/boot/dts/apm-storm.dtsi [new file with mode: 0644]
arch/arm64/configs/defconfig
arch/arm64/include/asm/arch_timer.h
arch/arm64/include/asm/cacheflush.h
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/debug-monitors.h
arch/arm64/include/asm/device.h
arch/arm64/include/asm/dma-mapping.h
arch/arm64/include/asm/hugetlb.h [new file with mode: 0644]
arch/arm64/include/asm/hypervisor.h [new file with mode: 0644]
arch/arm64/include/asm/io.h
arch/arm64/include/asm/kvm_arm.h [new file with mode: 0644]
arch/arm64/include/asm/kvm_asm.h [new file with mode: 0644]
arch/arm64/include/asm/kvm_coproc.h [new file with mode: 0644]
arch/arm64/include/asm/kvm_emulate.h [new file with mode: 0644]
arch/arm64/include/asm/kvm_host.h [new file with mode: 0644]
arch/arm64/include/asm/kvm_mmio.h [new file with mode: 0644]
arch/arm64/include/asm/kvm_mmu.h [new file with mode: 0644]
arch/arm64/include/asm/kvm_psci.h [new file with mode: 0644]
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/ptrace.h
arch/arm64/include/asm/spinlock.h
arch/arm64/include/asm/sync_bitops.h [new file with mode: 0644]
arch/arm64/include/asm/timex.h
arch/arm64/include/asm/tlb.h
arch/arm64/include/asm/tlbflush.h
arch/arm64/include/asm/uaccess.h
arch/arm64/include/asm/xen/events.h [new file with mode: 0644]
arch/arm64/include/asm/xen/hypercall.h [new file with mode: 0644]
arch/arm64/include/asm/xen/hypervisor.h [new file with mode: 0644]
arch/arm64/include/asm/xen/interface.h [new file with mode: 0644]
arch/arm64/include/asm/xen/page.h [new file with mode: 0644]
arch/arm64/include/uapi/asm/kvm.h [new file with mode: 0644]
arch/arm64/kernel/asm-offsets.c
arch/arm64/kernel/debug-monitors.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/time.c
arch/arm64/kernel/traps.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/Makefile [new file with mode: 0644]
arch/arm64/kvm/emulate.c [new file with mode: 0644]
arch/arm64/kvm/guest.c [new file with mode: 0644]
arch/arm64/kvm/handle_exit.c [new file with mode: 0644]
arch/arm64/kvm/hyp-init.S [new file with mode: 0644]
arch/arm64/kvm/hyp.S [new file with mode: 0644]
arch/arm64/kvm/inject_fault.c [new file with mode: 0644]
arch/arm64/kvm/regmap.c [new file with mode: 0644]
arch/arm64/kvm/reset.c [new file with mode: 0644]
arch/arm64/kvm/sys_regs.c [new file with mode: 0644]
arch/arm64/kvm/sys_regs.h [new file with mode: 0644]
arch/arm64/kvm/sys_regs_generic_v8.c [new file with mode: 0644]
arch/arm64/mm/Makefile
arch/arm64/mm/fault.c
arch/arm64/mm/flush.c
arch/arm64/mm/hugetlbpage.c [new file with mode: 0644]
arch/arm64/mm/init.c
arch/arm64/mm/mm.h
arch/arm64/mm/mmu.c
arch/arm64/xen/Makefile [new file with mode: 0644]
arch/arm64/xen/hypercall.S [new file with mode: 0644]
arch/avr32/kernel/process.c
arch/avr32/kernel/setup.c
arch/avr32/kernel/vmlinux.lds.S
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mm/init.c
arch/blackfin/mach-bf527/boards/ad7160eval.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-bf609/boards/ezkit.c
arch/blackfin/mm/init.c
arch/c6x/include/asm/Kbuild
arch/c6x/kernel/vmlinux.lds.S
arch/c6x/mm/init.c
arch/cris/Kconfig
arch/cris/arch-v10/kernel/kgdb.c
arch/cris/arch-v32/drivers/Kconfig
arch/cris/include/arch-v10/arch/bitops.h
arch/cris/include/asm/Kbuild
arch/cris/include/asm/io.h
arch/cris/include/asm/linkage.h [deleted file]
arch/cris/include/asm/page.h
arch/cris/mm/init.c
arch/frv/include/asm/uaccess.h
arch/frv/kernel/head.S
arch/frv/kernel/setup.c
arch/frv/kernel/traps.c
arch/frv/mm/init.c
arch/h8300/Kconfig
arch/h8300/Kconfig.cpu
arch/h8300/boot/compressed/Makefile
arch/h8300/boot/compressed/misc.c
arch/h8300/include/asm/Kbuild
arch/h8300/include/asm/barrier.h
arch/h8300/include/asm/linkage.h [deleted file]
arch/h8300/include/asm/tlb.h
arch/h8300/kernel/entry.S
arch/h8300/kernel/syscalls.S
arch/h8300/kernel/vmlinux.lds.S
arch/h8300/lib/abs.S
arch/h8300/lib/memcpy.S
arch/h8300/lib/memset.S
arch/h8300/mm/init.c
arch/h8300/platform/h8300h/aki3068net/crt0_ram.S
arch/h8300/platform/h8300h/generic/crt0_ram.S
arch/h8300/platform/h8300h/generic/crt0_rom.S
arch/h8300/platform/h8300h/h8max/crt0_ram.S
arch/h8300/platform/h8s/edosk2674/crt0_ram.S
arch/h8300/platform/h8s/edosk2674/crt0_rom.S
arch/h8300/platform/h8s/generic/crt0_ram.S
arch/h8300/platform/h8s/generic/crt0_rom.S
arch/hexagon/mm/init.c
arch/ia64/hp/common/sba_iommu.c
arch/ia64/hp/sim/simscsi.c
arch/ia64/include/asm/mutex.h
arch/ia64/include/asm/pci.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/efi.c
arch/ia64/kernel/err_inject.c
arch/ia64/kernel/head.S
arch/ia64/kernel/mca.c
arch/ia64/kernel/numa.c
arch/ia64/kernel/palinfo.c
arch/ia64/kernel/pci-dma.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/topology.c
arch/ia64/kernel/traps.c
arch/ia64/kvm/Makefile
arch/ia64/mm/contig.c
arch/ia64/mm/discontig.c
arch/ia64/mm/init.c
arch/ia64/mm/numa.c
arch/ia64/pci/pci.c
arch/ia64/sn/kernel/io_init.c
arch/ia64/sn/kernel/setup.c
arch/ia64/xen/hypervisor.c
arch/m32r/include/asm/uaccess.h
arch/m32r/mm/discontig.c
arch/m32r/mm/init.c
arch/m68k/Kconfig.debug
arch/m68k/configs/multi_defconfig
arch/m68k/configs/q40_defconfig
arch/m68k/include/asm/parport.h
arch/m68k/include/asm/string.h
arch/m68k/include/asm/uaccess_mm.h
arch/m68k/kernel/asm-offsets.c
arch/m68k/kernel/ints.c
arch/m68k/lib/Makefile
arch/m68k/lib/string.c [deleted file]
arch/m68k/lib/uaccess.c
arch/m68k/math-emu/fp_arith.c
arch/m68k/mm/init.c
arch/m68k/platform/coldfire/pci.c
arch/m68k/sun3/sun3dvma.c
arch/metag/kernel/perf/perf_event.c
arch/metag/mm/init.c
arch/microblaze/include/asm/page.h
arch/microblaze/include/asm/uaccess.h
arch/microblaze/mm/init.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/kernel/crash_dump.c
arch/mips/kernel/mips-mt-fpaff.c
arch/mips/kernel/scall32-o32.S
arch/mips/loongson/lemote-2f/clock.c
arch/mips/mm/init.c
arch/mips/pci/pci-lantiq.c
arch/mips/sgi-ip27/ip27-memory.c
arch/mn10300/include/asm/uaccess.h
arch/mn10300/mm/init.c
arch/openrisc/include/asm/Kbuild
arch/openrisc/mm/init.c
arch/parisc/include/uapi/asm/fcntl.h
arch/parisc/mm/init.c
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/mmu_context.h
arch/powerpc/include/asm/mutex.h
arch/powerpc/include/asm/uaccess.h
arch/powerpc/kernel/crash_dump.c
arch/powerpc/kernel/kvm.c
arch/powerpc/kernel/pci_of_scan.c
arch/powerpc/kernel/proc_powerpc.c
arch/powerpc/kvm/Makefile
arch/powerpc/kvm/book3s_64_mmu.c
arch/powerpc/kvm/book3s_64_mmu_host.c
arch/powerpc/kvm/book3s_64_slb.S
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/emulate.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/mem.c
arch/powerpc/perf/power7-pmu.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/pasemi/Makefile
arch/powerpc/platforms/powermac/Makefile
arch/s390/appldata/appldata_mem.c
arch/s390/appldata/appldata_net_sum.c
arch/s390/hypfs/hypfs_diag.c
arch/s390/include/asm/airq.h
arch/s390/include/asm/dma-mapping.h
arch/s390/include/asm/facility.h
arch/s390/include/asm/io.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/pci.h
arch/s390/include/asm/perf_event.h
arch/s390/include/asm/pgalloc.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/ptrace.h
arch/s390/include/uapi/asm/Kbuild
arch/s390/include/uapi/asm/chsc.h
arch/s390/include/uapi/asm/dasd.h
arch/s390/include/uapi/asm/sclp_ctl.h [new file with mode: 0644]
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry.h
arch/s390/kernel/entry64.S
arch/s390/kernel/irq.c
arch/s390/kernel/perf_event.c
arch/s390/kernel/s390_ksyms.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kvm/Makefile
arch/s390/kvm/diag.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/priv.c
arch/s390/kvm/sigp.c
arch/s390/mm/init.c
arch/s390/mm/pgtable.c
arch/s390/oprofile/hwsampler.h
arch/s390/pci/pci.c
arch/s390/pci/pci_clp.c
arch/s390/pci/pci_debug.c
arch/s390/pci/pci_dma.c
arch/s390/pci/pci_sysfs.c
arch/score/include/asm/Kbuild
arch/score/include/asm/dma-mapping.h [deleted file]
arch/score/kernel/vmlinux.lds.S
arch/score/mm/init.c
arch/sh/include/asm/mutex-llsc.h
arch/sh/mm/init.c
arch/sparc/include/uapi/asm/fcntl.h
arch/sparc/kernel/leon_smp.c
arch/sparc/kernel/pci.c
arch/sparc/mm/init_32.c
arch/sparc/mm/init_64.c
arch/tile/include/asm/processor.h
arch/tile/include/asm/sections.h
arch/tile/include/asm/uaccess.h
arch/tile/kernel/setup.c
arch/tile/kernel/stack.c
arch/tile/kernel/vmlinux.lds.S
arch/tile/mm/init.c
arch/um/include/asm/common.lds.S
arch/um/kernel/dyn.lds.S
arch/um/kernel/mem.c
arch/um/kernel/sysrq.c
arch/um/kernel/uml.lds.S
arch/unicore32/boot/compressed/Makefile
arch/unicore32/include/asm/memory.h
arch/unicore32/kernel/pci.c
arch/unicore32/mm/init.c
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/Makefile
arch/x86/boot/compressed/eboot.c
arch/x86/boot/compressed/head_64.S
arch/x86/boot/tools/build.c
arch/x86/configs/kvm_guest.config [new file with mode: 0644]
arch/x86/ia32/ia32_signal.c
arch/x86/include/asm/acpi.h
arch/x86/include/asm/apic.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/desc.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/entry_arch.h
arch/x86/include/asm/fixmap.h
arch/x86/include/asm/fpu-internal.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/microcode_amd.h [new file with mode: 0644]
arch/x86/include/asm/microcode_intel.h
arch/x86/include/asm/mshyperv.h
arch/x86/include/asm/mutex_32.h
arch/x86/include/asm/mutex_64.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/sighandling.h
arch/x86/include/asm/special_insns.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/tlbflush.h
arch/x86/include/asm/trace/irq_vectors.h [new file with mode: 0644]
arch/x86/include/asm/uaccess_64.h
arch/x86/include/asm/uv/uv_bau.h
arch/x86/include/uapi/asm/msr-index.h
arch/x86/include/uapi/asm/processor-flags.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/acpi/sleep.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cyrix.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce-inject.c
arch/x86/kernel/cpu/mcheck/mce-severity.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/mce_intel.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/mcheck/threshold.c
arch/x86/kernel/cpu/mtrr/cyrix.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_iommu.c [new file with mode: 0644]
arch/x86/kernel/cpu/perf_event_amd_iommu.h [new file with mode: 0644]
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_uncore.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/cpu/proc.c
arch/x86/kernel/doublefault.c [moved from arch/x86/kernel/doublefault_32.c with 84% similarity]
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/i387.c
arch/x86/kernel/irq.c
arch/x86/kernel/irq_work.c
arch/x86/kernel/microcode_amd.c
arch/x86/kernel/microcode_amd_early.c [new file with mode: 0644]
arch/x86/kernel/microcode_core_early.c
arch/x86/kernel/microcode_intel_early.c
arch/x86/kernel/nmi.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/relocate_kernel_32.S
arch/x86/kernel/relocate_kernel_64.S
arch/x86/kernel/setup.c
arch/x86/kernel/signal.c
arch/x86/kernel/smp.c
arch/x86/kernel/tboot.c
arch/x86/kernel/tracepoint.c [new file with mode: 0644]
arch/x86/kernel/traps.c
arch/x86/kernel/xsave.c
arch/x86/kvm/Makefile
arch/x86/kvm/emulate.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/mmu.h
arch/x86/kvm/mmutrace.h
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/Makefile
arch/x86/lguest/boot.c
arch/x86/lguest/head_32.S [moved from arch/x86/lguest/i386_head.S with 100% similarity]
arch/x86/mm/highmem_32.c
arch/x86/mm/hugetlbpage.c
arch/x86/mm/init.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/numa_32.c
arch/x86/pci/acpi.c
arch/x86/platform/efi/efi.c
arch/x86/vdso/vdso32-setup.c
arch/x86/xen/enlighten.c
arch/x86/xen/smp.c
arch/x86/xen/spinlock.c
arch/x86/xen/time.c
arch/xtensa/mm/init.c
block/blk-core.c
block/blk-ioc.c
block/blk-timeout.c
block/compat_ioctl.c
block/genhd.c
crypto/algapi.c
crypto/async_tx/Kconfig
crypto/async_tx/Makefile
crypto/async_tx/async_memset.c [deleted file]
crypto/pcrypt.c
drivers/acpi/Makefile
drivers/acpi/acpi_cmos_rtc.c [new file with mode: 0644]
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_memhotplug.c
drivers/acpi/acpi_processor.c [new file with mode: 0644]
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acmacros.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/acpredef.h
drivers/acpi/acpica/acstruct.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/dscontrol.c
drivers/acpi/acpica/dsfield.c
drivers/acpi/acpica/dsinit.c
drivers/acpi/acpica/dsmthdat.c
drivers/acpi/acpica/dsobject.c
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/dsutils.c
drivers/acpi/acpica/dswexec.c
drivers/acpi/acpica/dswload.c
drivers/acpi/acpica/dswload2.c
drivers/acpi/acpica/evglock.c
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evgpeinit.c
drivers/acpi/acpica/evhandler.c
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/evxfgpe.c
drivers/acpi/acpica/evxfregn.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/exconvrt.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/exdebug.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/exfield.c
drivers/acpi/acpica/exfldio.c
drivers/acpi/acpica/exmisc.c
drivers/acpi/acpica/exoparg1.c
drivers/acpi/acpica/exoparg2.c
drivers/acpi/acpica/exoparg3.c
drivers/acpi/acpica/exoparg6.c
drivers/acpi/acpica/exprep.c
drivers/acpi/acpica/exregion.c
drivers/acpi/acpica/exresnte.c
drivers/acpi/acpica/exresolv.c
drivers/acpi/acpica/exresop.c
drivers/acpi/acpica/exstore.c
drivers/acpi/acpica/exstoren.c
drivers/acpi/acpica/hwacpi.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/hwxface.c
drivers/acpi/acpica/hwxfsleep.c
drivers/acpi/acpica/nsaccess.c
drivers/acpi/acpica/nsarguments.c [new file with mode: 0644]
drivers/acpi/acpica/nsconvert.c
drivers/acpi/acpica/nsdump.c
drivers/acpi/acpica/nseval.c
drivers/acpi/acpica/nsinit.c
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/nsprepkg.c
drivers/acpi/acpica/nsrepair.c
drivers/acpi/acpica/nsrepair2.c
drivers/acpi/acpica/nsutils.c
drivers/acpi/acpica/nsxfeval.c
drivers/acpi/acpica/psargs.c
drivers/acpi/acpica/psloop.c
drivers/acpi/acpica/psobject.c
drivers/acpi/acpica/psparse.c
drivers/acpi/acpica/pstree.c
drivers/acpi/acpica/psxface.c
drivers/acpi/acpica/rscalc.c
drivers/acpi/acpica/rscreate.c
drivers/acpi/acpica/rsdump.c
drivers/acpi/acpica/rsmisc.c
drivers/acpi/acpica/rsutils.c
drivers/acpi/acpica/rsxface.c
drivers/acpi/acpica/tbinstal.c
drivers/acpi/acpica/tbprint.c [new file with mode: 0644]
drivers/acpi/acpica/tbutils.c
drivers/acpi/acpica/tbxfload.c
drivers/acpi/acpica/utbuffer.c [new file with mode: 0644]
drivers/acpi/acpica/utcopy.c
drivers/acpi/acpica/utdebug.c
drivers/acpi/acpica/utdelete.c
drivers/acpi/acpica/uterror.c [new file with mode: 0644]
drivers/acpi/acpica/uteval.c
drivers/acpi/acpica/utexcep.c
drivers/acpi/acpica/utids.c
drivers/acpi/acpica/utmisc.c
drivers/acpi/acpica/utobject.c
drivers/acpi/acpica/utpredef.c
drivers/acpi/acpica/utstring.c
drivers/acpi/acpica/uttrack.c
drivers/acpi/acpica/utxferror.c
drivers/acpi/apei/einj.c
drivers/acpi/apei/erst.c
drivers/acpi/apei/ghes.c
drivers/acpi/battery.c
drivers/acpi/bus.c
drivers/acpi/device_pm.c
drivers/acpi/ec.c
drivers/acpi/ec_sys.c
drivers/acpi/glue.c
drivers/acpi/internal.h
drivers/acpi/osl.c
drivers/acpi/pci_root.c
drivers/acpi/processor_driver.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_perflib.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/sysfs.c
drivers/acpi/video.c
drivers/amba/bus.c
drivers/ata/Kconfig
drivers/ata/acard-ahci.c
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_platform.c
drivers/ata/ata_piix.c
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-pmp.c
drivers/ata/libata-scsi.c
drivers/ata/libata-transport.c
drivers/ata/libata-zpodd.c
drivers/ata/pata_ali.c
drivers/ata/pata_amd.c
drivers/ata/pata_arasan_cf.c
drivers/ata/pata_artop.c
drivers/ata/pata_at91.c
drivers/ata/pata_atp867x.c
drivers/ata/pata_bf54x.c
drivers/ata/pata_cmd640.c
drivers/ata/pata_cmd64x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_cs5530.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt3x3.c
drivers/ata/pata_imx.c
drivers/ata/pata_it821x.c
drivers/ata/pata_macio.c
drivers/ata/pata_mpc52xx.c
drivers/ata/pata_ninja32.c
drivers/ata/pata_ns87415.c
drivers/ata/pata_pdc2027x.c
drivers/ata/pata_pxa.c
drivers/ata/pata_rdc.c
drivers/ata/pata_rz1000.c
drivers/ata/pata_serverworks.c
drivers/ata/pata_sil680.c
drivers/ata/pata_sis.c
drivers/ata/pata_sl82c105.c
drivers/ata/pata_triflex.c
drivers/ata/pata_via.c
drivers/ata/sata_fsl.c
drivers/ata/sata_highbank.c
drivers/ata/sata_inic162x.c
drivers/ata/sata_nv.c
drivers/ata/sata_rcar.c
drivers/ata/sata_sil.c
drivers/ata/sata_sil24.c
drivers/base/attribute_container.c
drivers/base/core.c
drivers/base/cpu.c
drivers/base/memory.c
drivers/base/pinctrl.c
drivers/base/platform.c
drivers/base/power/domain.c
drivers/base/power/generic_ops.c
drivers/base/power/opp.c
drivers/base/power/qos.c
drivers/base/power/runtime.c
drivers/base/power/wakeup.c
drivers/base/regmap/internal.h
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap.c
drivers/block/aoe/aoe.h
drivers/block/aoe/aoecmd.c
drivers/block/aoe/aoedev.c
drivers/block/aoe/aoenet.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/nbd.c
drivers/block/swim.c
drivers/block/virtio_blk.c
drivers/block/xen-blkback/xenbus.c
drivers/cdrom/cdrom.c
drivers/cdrom/gdrom.c
drivers/char/agp/alpha-agp.c
drivers/char/agp/parisc-agp.c
drivers/char/mem.c
drivers/char/ps3flash.c
drivers/char/tile-srom.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_i2c_infineon.c
drivers/char/tpm/tpm_tis.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/clk-divider.c
drivers/clk/clk-gate.c
drivers/clk/clk-mux.c
drivers/clk/clk-nspire.c [new file with mode: 0644]
drivers/clk/clk-ppc-corenet.c [new file with mode: 0644]
drivers/clk/clk-si5351.c
drivers/clk/clk-si5351.h
drivers/clk/clk-twl6040.c
drivers/clk/clk-vt8500.c
drivers/clk/clk-wm831x.c
drivers/clk/clk.c
drivers/clk/rockchip/Makefile [new file with mode: 0644]
drivers/clk/rockchip/clk-rockchip.c [new file with mode: 0644]
drivers/clk/samsung/clk-exynos4.c
drivers/clk/samsung/clk.h
drivers/clk/sunxi/clk-sunxi.c
drivers/clk/tegra/clk-pll.c
drivers/clk/tegra/clk-tegra114.c
drivers/clk/tegra/clk-tegra20.c
drivers/clk/tegra/clk-tegra30.c
drivers/clk/tegra/clk.c
drivers/clk/tegra/clk.h
drivers/clk/ux500/abx500-clk.c
drivers/clk/ux500/u8540_clk.c
drivers/clk/ux500/u9540_clk.c
drivers/clk/versatile/clk-vexpress-osc.c
drivers/clk/x86/clk-lpt.c
drivers/clocksource/arm_arch_timer.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Kconfig.powerpc
drivers/cpufreq/Kconfig.x86
drivers/cpufreq/Makefile
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/arm_big_little.c
drivers/cpufreq/blackfin-cpufreq.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_governor.c
drivers/cpufreq/cpufreq_governor.h
drivers/cpufreq/cpufreq_performance.c
drivers/cpufreq/cpufreq_powersave.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/cpufreq_userspace.c
drivers/cpufreq/davinci-cpufreq.c
drivers/cpufreq/dbx500-cpufreq.c
drivers/cpufreq/e_powersaver.c
drivers/cpufreq/exynos-cpufreq.c
drivers/cpufreq/freq_table.c
drivers/cpufreq/ia64-acpi-cpufreq.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/kirkwood-cpufreq.c
drivers/cpufreq/longhaul.c
drivers/cpufreq/loongson2_cpufreq.c
drivers/cpufreq/omap-cpufreq.c
drivers/cpufreq/p4-clockmod.c
drivers/cpufreq/pasemi-cpufreq.c [moved from arch/powerpc/platforms/pasemi/cpufreq.c with 98% similarity]
drivers/cpufreq/pcc-cpufreq.c
drivers/cpufreq/pmac32-cpufreq.c [moved from arch/powerpc/platforms/powermac/cpufreq_32.c with 100% similarity]
drivers/cpufreq/pmac64-cpufreq.c [moved from arch/powerpc/platforms/powermac/cpufreq_64.c with 100% similarity]
drivers/cpufreq/powernow-k6.c
drivers/cpufreq/powernow-k7.c
drivers/cpufreq/powernow-k8.c
drivers/cpufreq/ppc-corenet-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/ppc_cbe_cpufreq.c
drivers/cpufreq/pxa2xx-cpufreq.c
drivers/cpufreq/pxa3xx-cpufreq.c
drivers/cpufreq/s3c2416-cpufreq.c
drivers/cpufreq/s3c24xx-cpufreq.c
drivers/cpufreq/s3c64xx-cpufreq.c
drivers/cpufreq/sc520_freq.c
drivers/cpufreq/sparc-us2e-cpufreq.c
drivers/cpufreq/sparc-us3-cpufreq.c
drivers/cpufreq/spear-cpufreq.c
drivers/cpufreq/speedstep-centrino.c
drivers/cpufreq/tegra-cpufreq.c
drivers/cpuidle/Kconfig
drivers/cpuidle/Makefile
drivers/cpuidle/cpuidle-zynq.c [new file with mode: 0644]
drivers/cpuidle/cpuidle.c
drivers/cpuidle/driver.c
drivers/devfreq/Kconfig
drivers/devfreq/Makefile
drivers/devfreq/devfreq.c
drivers/devfreq/exynos/Makefile [new file with mode: 0644]
drivers/devfreq/exynos/exynos4_bus.c [moved from drivers/devfreq/exynos4_bus.c with 99% similarity]
drivers/devfreq/exynos/exynos5_bus.c [new file with mode: 0644]
drivers/devfreq/exynos/exynos_ppmu.c [new file with mode: 0644]
drivers/devfreq/exynos/exynos_ppmu.h [new file with mode: 0644]
drivers/dma/dmaengine.c
drivers/dma/intel_mid_dma.c
drivers/dma/ioat/dma.c
drivers/dma/ioat/dma_v2.h
drivers/dma/ioat/dma_v3.c
drivers/dma/ioat/hw.h
drivers/dma/iop-adma.c
drivers/dma/mv_xor.c
drivers/dma/mv_xor.h
drivers/dma/pl330.c
drivers/dma/ppc4xx/adma.c
drivers/edac/amd64_edac_inj.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/i7core_edac.c
drivers/edac/mce_amd.c
drivers/edac/mce_amd_inj.c
drivers/extcon/extcon-class.c
drivers/firmware/dmi_scan.c
drivers/firmware/efi/efi-pstore.c
drivers/gpio/Kconfig
drivers/gpio/devres.c
drivers/gpio/gpio-bt8xx.c
drivers/gpio/gpio-grgpio.c
drivers/gpio/gpio-ich.c
drivers/gpio/gpio-langwell.c
drivers/gpio/gpio-lynxpoint.c
drivers/gpio/gpio-ml-ioh.c
drivers/gpio/gpio-msm-v1.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpio-rdc321x.c
drivers/gpio/gpio-sta2x11.c
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-sx150x.c
drivers/gpio/gpio-tc3589x.c
drivers/gpio/gpio-timberdale.c
drivers/gpio/gpio-vx855.c
drivers/gpio/gpio-xilinx.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/radeon/mkregtable.c
drivers/hsi/hsi.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru3.c
drivers/hwmon/adm1021.c
drivers/hwmon/adt7470.c
drivers/hwmon/coretemp.c
drivers/hwmon/ds1621.c
drivers/hwmon/g762.c [new file with mode: 0644]
drivers/hwmon/i5k_amb.c
drivers/hwmon/iio_hwmon.c
drivers/hwmon/ina2xx.c
drivers/hwmon/nct6775.c
drivers/hwmon/ntc_thermistor.c
drivers/hwmon/w83627ehf.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/i2c-core.c
drivers/ide/ide-cd.c
drivers/ide/ide-gd.c
drivers/ide/ide-probe.c
drivers/ide/ide-tape.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/hw/qib/qib_file_ops.c
drivers/input/keyboard/cros_ec_keyb.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_proto.h
drivers/iommu/amd_iommu_types.h
drivers/iommu/irq_remapping.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/exynos-combiner.c
drivers/irqchip/irq-nvic.c [new file with mode: 0644]
drivers/irqchip/irq-orion.c [new file with mode: 0644]
drivers/irqchip/irq-tb10x.c [new file with mode: 0644]
drivers/isdn/mISDN/dsp_pipeline.c
drivers/leds/Kconfig
drivers/leds/led-class.c
drivers/leds/leds-88pm860x.c
drivers/leds/leds-atmel-pwm.c
drivers/leds/leds-gpio.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-mc13783.c
drivers/leds/leds-ns2.c
drivers/leds/leds-renesas-tpu.c
drivers/leds/leds-sunfire.c
drivers/leds/leds-wm831x-status.c
drivers/lguest/x86/core.c
drivers/media/i2c/tvaudio.c
drivers/media/pci/cx18/cx18-driver.c
drivers/media/pci/ivtv/ivtv-driver.c
drivers/media/platform/Kconfig
drivers/media/platform/vivi.c
drivers/memstick/host/jmb38x_ms.c
drivers/memstick/host/r592.c
drivers/message/i2o/driver.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/arizona-core.c
drivers/mfd/arizona-i2c.c
drivers/mfd/arizona-spi.c
drivers/mfd/arizona.h
drivers/mfd/db8500-prcmu.c
drivers/mfd/dbx500-prcmu-regs.h
drivers/mfd/stmpe.c
drivers/mfd/timberdale.c
drivers/mfd/twl4030-irq.c
drivers/mfd/wm5102-tables.c
drivers/mfd/wm5110-tables.c
drivers/misc/atmel-ssc.c
drivers/misc/sgi-gru/grufault.c
drivers/mmc/core/bus.c
drivers/mmc/core/sdio_bus.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/cdev.c
drivers/net/ethernet/brocade/bna/bnad_debugfs.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_mdio.c
drivers/net/phy/phy.c
drivers/net/rionet.c
drivers/net/wireless/airo.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/ti/wlcore/debugfs.c
drivers/parisc/eisa_eeprom.c
drivers/parport/Kconfig
drivers/parport/share.c
drivers/pci/bus.c
drivers/pci/hotplug/cpqphp_sysfs.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/s390_pci_hpc.c
drivers/pci/hotplug/shpchp_core.c
drivers/pci/ioapic.c
drivers/pci/iov.c
drivers/pci/msi.c
drivers/pci/pci-acpi.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.c
drivers/pci/pcie/aer/aerdrv.h
drivers/pci/pcie/aer/aerdrv_acpi.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/aspm.c
drivers/pci/pcie/pme.c
drivers/pci/probe.c
drivers/pci/proc.c
drivers/pci/quirks.c
drivers/pci/xen-pcifront.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/core.c
drivers/pinctrl/mvebu/pinctrl-dove.c
drivers/pinctrl/pinconf-generic.c
drivers/pinctrl/pinconf.c
drivers/pinctrl/pinconf.h
drivers/pinctrl/pinctrl-abx500.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-baytrail.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-bcm2835.c
drivers/pinctrl/pinctrl-coh901.c
drivers/pinctrl/pinctrl-exynos.c
drivers/pinctrl/pinctrl-exynos5440.c
drivers/pinctrl/pinctrl-imx.c
drivers/pinctrl/pinctrl-imx.h
drivers/pinctrl/pinctrl-mxs.c
drivers/pinctrl/pinctrl-nomadik.c
drivers/pinctrl/pinctrl-rockchip.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-samsung.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/pinctrl-st.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-sunxi-pins.h [new file with mode: 0644]
drivers/pinctrl/pinctrl-sunxi.c
drivers/pinctrl/pinctrl-sunxi.h
drivers/pinctrl/pinctrl-tz1090-pdc.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-tz1090.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-u300.c
drivers/pinctrl/pinctrl-vf610.c [new file with mode: 0644]
drivers/pinctrl/sh-pfc/core.c
drivers/pinctrl/sh-pfc/pinctrl.c
drivers/pinctrl/sirf/Makefile [new file with mode: 0644]
drivers/pinctrl/sirf/pinctrl-atlas6.c [new file with mode: 0644]
drivers/pinctrl/sirf/pinctrl-prima2.c [moved from drivers/pinctrl/pinctrl-sirf.c with 50% similarity]
drivers/pinctrl/sirf/pinctrl-sirf.c [new file with mode: 0644]
drivers/pinctrl/sirf/pinctrl-sirf.h [new file with mode: 0644]
drivers/pinctrl/spear/pinctrl-plgpio.c
drivers/pinctrl/vt8500/pinctrl-wmt.c
drivers/platform/x86/wmi.c
drivers/pnp/isapnp/proc.c
drivers/pnp/manager.c
drivers/power/avs/smartreflex.c
drivers/pps/clients/pps-gpio.c
drivers/rapidio/Kconfig
drivers/rapidio/Makefile
drivers/rapidio/devices/Kconfig
drivers/rapidio/devices/Makefile
drivers/rapidio/devices/tsi721.c
drivers/rapidio/rio-driver.c
drivers/rapidio/rio-scan.c
drivers/rapidio/rio-sysfs.c
drivers/rapidio/rio.c
drivers/rapidio/rio.h
drivers/rapidio/switches/Kconfig
drivers/rapidio/switches/Makefile
drivers/rapidio/switches/idt_gen2.c
drivers/rapidio/switches/idtcps.c
drivers/rapidio/switches/tsi500.c [deleted file]
drivers/rapidio/switches/tsi568.c
drivers/rapidio/switches/tsi57x.c
drivers/regulator/88pm8607.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/ab8500-ext.c
drivers/regulator/ab8500.c
drivers/regulator/core.c
drivers/regulator/isl6271a-regulator.c
drivers/regulator/lp3971.c
drivers/regulator/lp3972.c
drivers/regulator/lp872x.c
drivers/regulator/lp8755.c
drivers/regulator/lp8788-buck.c
drivers/regulator/lp8788-ldo.c
drivers/regulator/max77686.c
drivers/regulator/max77693.c [new file with mode: 0644]
drivers/regulator/max8925-regulator.c
drivers/regulator/max8973-regulator.c
drivers/regulator/mc13783-regulator.c
drivers/regulator/mc13892-regulator.c
drivers/regulator/of_regulator.c
drivers/regulator/pcap-regulator.c
drivers/regulator/pcf50633-regulator.c
drivers/regulator/s2mps11.c
drivers/regulator/ti-abb-regulator.c [new file with mode: 0644]
drivers/regulator/tps62360-regulator.c
drivers/regulator/tps65217-regulator.c
drivers/regulator/virtual.c
drivers/regulator/wm831x-dcdc.c
drivers/regulator/wm831x-isink.c
drivers/regulator/wm831x-ldo.c
drivers/regulator/wm8400-regulator.c
drivers/regulator/wm8994-regulator.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/class.c
drivers/rtc/interface.c
drivers/rtc/rtc-88pm80x.c
drivers/rtc/rtc-88pm860x.c
drivers/rtc/rtc-ab3100.c
drivers/rtc/rtc-ab8500.c
drivers/rtc/rtc-at32ap700x.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-au1xxx.c
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-bq32k.c
drivers/rtc/rtc-bq4802.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-coh901331.c
drivers/rtc/rtc-da9052.c
drivers/rtc/rtc-da9055.c
drivers/rtc/rtc-davinci.c
drivers/rtc/rtc-dm355evm.c
drivers/rtc/rtc-ds1216.c
drivers/rtc/rtc-ds1286.c
drivers/rtc/rtc-ds1302.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-ds1390.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-ds1672.c
drivers/rtc/rtc-ds3234.c
drivers/rtc/rtc-efi.c
drivers/rtc/rtc-em3027.c
drivers/rtc/rtc-ep93xx.c
drivers/rtc/rtc-fm3130.c
drivers/rtc/rtc-generic.c
drivers/rtc/rtc-hid-sensor-time.c
drivers/rtc/rtc-isl12022.c
drivers/rtc/rtc-jz4740.c
drivers/rtc/rtc-lp8788.c
drivers/rtc/rtc-lpc32xx.c
drivers/rtc/rtc-ls1x.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-m41t93.c
drivers/rtc/rtc-m41t94.c
drivers/rtc/rtc-m48t35.c
drivers/rtc/rtc-m48t59.c
drivers/rtc/rtc-m48t86.c
drivers/rtc/rtc-max6900.c
drivers/rtc/rtc-max6902.c
drivers/rtc/rtc-max77686.c
drivers/rtc/rtc-max8907.c
drivers/rtc/rtc-max8925.c
drivers/rtc/rtc-max8997.c
drivers/rtc/rtc-max8998.c
drivers/rtc/rtc-mc13xxx.c
drivers/rtc/rtc-mpc5121.c
drivers/rtc/rtc-msm6242.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-nuc900.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-palmas.c
drivers/rtc/rtc-pcap.c
drivers/rtc/rtc-pcf2123.c
drivers/rtc/rtc-pcf2127.c [new file with mode: 0644]
drivers/rtc/rtc-pcf8523.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-pcf8583.c
drivers/rtc/rtc-pm8xxx.c
drivers/rtc/rtc-ps3.c
drivers/rtc/rtc-puv3.c
drivers/rtc/rtc-pxa.c
drivers/rtc/rtc-rc5t583.c
drivers/rtc/rtc-rp5c01.c
drivers/rtc/rtc-rs5c313.c
drivers/rtc/rtc-rs5c348.c
drivers/rtc/rtc-rv3029c2.c
drivers/rtc/rtc-rx4581.c
drivers/rtc/rtc-rx8025.c
drivers/rtc/rtc-rx8581.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-sh.c
drivers/rtc/rtc-sirfsoc.c [new file with mode: 0644]
drivers/rtc/rtc-snvs.c
drivers/rtc/rtc-spear.c
drivers/rtc/rtc-starfire.c
drivers/rtc/rtc-stmp3xxx.c
drivers/rtc/rtc-sun4v.c
drivers/rtc/rtc-sysfs.c
drivers/rtc/rtc-tile.c
drivers/rtc/rtc-tps80031.c
drivers/rtc/rtc-twl.c
drivers/rtc/rtc-v3020.c
drivers/rtc/rtc-vr41xx.c
drivers/rtc/rtc-vt8500.c
drivers/rtc/rtc-wm831x.c
drivers/rtc/rtc-x1205.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_erp.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/char/Makefile
drivers/s390/char/sclp.c
drivers/s390/char/sclp.h
drivers/s390/char/sclp_cmd.c
drivers/s390/char/sclp_con.c
drivers/s390/char/sclp_ctl.c [new file with mode: 0644]
drivers/s390/char/sclp_vt220.c
drivers/s390/char/tape_class.c
drivers/s390/char/vmwatchdog.c
drivers/s390/cio/airq.c
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/cio.c
drivers/s390/cio/qdio.h
drivers/s390/cio/qdio_main.c
drivers/s390/cio/qdio_setup.c
drivers/s390/cio/qdio_thinint.c
drivers/s390/crypto/ap_bus.c
drivers/s390/net/claw.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/lcs.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l3_sys.c
drivers/scsi/a3000.c
drivers/scsi/a4000t.c
drivers/scsi/aacraid/commctrl.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/bfa/bfad_debugfs.c
drivers/scsi/fnic/fnic_debugfs.c
drivers/scsi/ipr.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/megaraid.c
drivers/scsi/osd/osd_uld.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi_pm.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/sd.c
drivers/sh/clk/core.c
drivers/sh/pm_runtime.c
drivers/spi/spi-altera.c
drivers/spi/spi-ath79.c
drivers/spi/spi-atmel.c
drivers/spi/spi-au1550.c
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-bfin-sport.c
drivers/spi/spi-bfin5xx.c
drivers/spi/spi-clps711x.c
drivers/spi/spi-coldfire-qspi.c
drivers/spi/spi-davinci.c
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-dw.c
drivers/spi/spi-ep93xx.c
drivers/spi/spi-fsl-espi.c
drivers/spi/spi-fsl-lib.c
drivers/spi/spi-fsl-spi.c
drivers/spi/spi-gpio.c
drivers/spi/spi-imx.c
drivers/spi/spi-mpc512x-psc.c
drivers/spi/spi-mpc52xx-psc.c
drivers/spi/spi-mpc52xx.c
drivers/spi/spi-mxs.c
drivers/spi/spi-nuc900.c
drivers/spi/spi-oc-tiny.c
drivers/spi/spi-omap-100k.c
drivers/spi/spi-omap-uwire.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-orion.c
drivers/spi/spi-pl022.c
drivers/spi/spi-ppc4xx.c
drivers/spi/spi-pxa2xx-dma.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-rspi.c
drivers/spi/spi-s3c24xx.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sh-hspi.c
drivers/spi/spi-sh.c
drivers/spi/spi-sirf.c
drivers/spi/spi-tegra114.c
drivers/spi/spi-tegra20-sflash.c
drivers/spi/spi-tegra20-slink.c
drivers/spi/spi-ti-ssp.c
drivers/spi/spi-topcliff-pch.c
drivers/spi/spi-txx9.c
drivers/spi/spi-xcomm.c
drivers/spi/spi-xilinx.c
drivers/spi/spi.c
drivers/staging/android/binder.c
drivers/staging/android/logger.c
drivers/staging/android/timed_output.c
drivers/staging/comedi/comedi_fops.c
drivers/staging/dgrp/dgrp_sysfs.c
drivers/staging/media/solo6x10/Kconfig
drivers/staging/rtl8712/os_intfs.c
drivers/staging/tidspbridge/rmgr/drv_interface.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/mfd.c
drivers/tty/vt/vc_screen.c
drivers/uio/uio.c
drivers/usb/atm/usbatm.c
drivers/usb/core/driver.c
drivers/usb/core/port.c
drivers/usb/misc/sisusbvga/Kconfig
drivers/uwb/lc-dev.c
drivers/video/backlight/atmel-pwm-bl.c
drivers/video/backlight/backlight.c
drivers/video/backlight/ep93xx_bl.c
drivers/video/backlight/lcd.c
drivers/video/backlight/lp8788_bl.c
drivers/video/backlight/pcf50633-backlight.c
drivers/video/console/Kconfig
drivers/video/console/Makefile
drivers/video/console/fbcon.c
drivers/video/output.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_ring.c
drivers/w1/slaves/w1_ds2408.c
drivers/xen/balloon.c
drivers/xen/cpu_hotplug.c
drivers/xen/events.c
drivers/xen/evtchn.c
drivers/xen/gntalloc.c
drivers/xen/gntdev.c
drivers/xen/grant-table.c
drivers/xen/manage.c
drivers/xen/mcelog.c
drivers/xen/pcpu.c
drivers/xen/privcmd.c
drivers/xen/swiotlb-xen.c
drivers/xen/tmem.c
drivers/xen/xen-acpi-cpuhotplug.c
drivers/xen/xen-acpi-memhotplug.c
drivers/xen/xen-acpi-pad.c
drivers/xen/xen-acpi-processor.c
drivers/xen/xen-balloon.c
drivers/xen/xen-pciback/conf_space_header.c
drivers/xen/xen-pciback/pci_stub.c
drivers/xen/xen-pciback/pciback_ops.c
drivers/xen/xen-pciback/vpci.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xen-selfballoon.c
drivers/xen/xenbus/xenbus_comms.c
drivers/xen/xenbus/xenbus_dev_backend.c
drivers/xen/xenbus/xenbus_dev_frontend.c
drivers/xen/xenbus/xenbus_probe.c
drivers/xen/xenbus/xenbus_probe_backend.c
drivers/xen/xenbus/xenbus_probe_frontend.c
drivers/xen/xenbus/xenbus_xs.c
drivers/xen/xencomm.c
drivers/xen/xenfs/super.c
drivers/zorro/proc.c
fs/adfs/dir.c
fs/affs/namei.c
fs/afs/flock.c
fs/aio.c
fs/block_dev.c
fs/btrfs/file.c
fs/btrfs/ioctl.c
fs/buffer.c
fs/cachefiles/rdwr.c
fs/ceph/file.c
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/cifs/Kconfig
fs/cifs/cifs_debug.c
fs/cifs/cifs_unicode.h
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/misc.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/smb2glob.h
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h
fs/cifs/smb2transport.c
fs/cifs/smbfsctl.h
fs/cifs/transport.c
fs/coda/dir.c
fs/configfs/file.c
fs/coredump.c
fs/dcache.c
fs/ecryptfs/crypto.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/efivarfs/super.c
fs/eventpoll.c
fs/exec.c
fs/ext2/namei.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext4/file.c
fs/ext4/namei.c
fs/fat/misc.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/file_table.c
fs/fuse/file.c
fs/fuse/inode.c
fs/gfs2/dentry.c
fs/gfs2/file.c
fs/hfs/hfs_fs.h
fs/hfs/string.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/unicode.c
fs/hpfs/dentry.c
fs/hppfs/hppfs.c
fs/inode.c
fs/internal.h
fs/isofs/inode.c
fs/isofs/namei.c
fs/jfs/namei.c
fs/lockd/svc.c
fs/lockd/svclock.c
fs/lockd/svcsubs.c
fs/locks.c
fs/minix/dir.c
fs/minix/namei.c
fs/namei.c
fs/ncpfs/dir.c
fs/ncpfs/inode.c
fs/ncpfs/mmap.c
fs/nfs/callback.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfsd/nfs4state.c
fs/nilfs2/alloc.c
fs/nilfs2/alloc.h
fs/nilfs2/ifile.c
fs/nilfs2/ifile.h
fs/nilfs2/inode.c
fs/nilfs2/segment.c
fs/nilfs2/super.c
fs/nilfs2/the_nilfs.c
fs/nilfs2/the_nilfs.h
fs/notify/fanotify/fanotify_user.c
fs/ocfs2/alloc.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/quorum.c
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dlm/dlmlock.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/file.c
fs/ocfs2/journal.h
fs/ocfs2/namei.c
fs/ocfs2/ocfs2.h
fs/ocfs2/suballoc.c
fs/ocfs2/super.c
fs/ocfs2/xattr.c
fs/open.c
fs/proc/base.c
fs/proc/fd.c
fs/proc/internal.h
fs/proc/kcore.c
fs/proc/namespaces.c
fs/proc/proc_sysctl.c
fs/proc/task_mmu.c
fs/proc/uptime.c
fs/proc/vmcore.c
fs/pstore/inode.c
fs/pstore/platform.c
fs/pstore/ram.c
fs/pstore/ram_core.c
fs/read_write.c
fs/select.c
fs/splice.c
fs/sysv/namei.c
fs/udf/namei.c
fs/xfs/xfs_file.c
include/acpi/acconfig.h
include/acpi/acoutput.h
include/acpi/acpi_bus.h
include/acpi/acpixf.h
include/acpi/processor.h
include/asm-generic/mutex-dec.h
include/asm-generic/mutex-null.h
include/asm-generic/mutex-xchg.h
include/asm-generic/pgtable.h
include/asm-generic/sections.h
include/asm-generic/uaccess.h
include/asm-generic/vmlinux.lds.h
include/clocksource/arm_arch_timer.h
include/dt-bindings/pinctrl/rockchip.h [new file with mode: 0644]
include/kvm/arm_arch_timer.h [moved from arch/arm/include/asm/kvm_arch_timer.h with 92% similarity]
include/kvm/arm_vgic.h [moved from arch/arm/include/asm/kvm_vgic.h with 100% similarity]
include/linux/acpi.h
include/linux/aer.h
include/linux/async_tx.h
include/linux/backlight.h
include/linux/bootmem.h
include/linux/buffer_head.h
include/linux/cgroup.h
include/linux/clk-provider.h
include/linux/clk/tegra.h
include/linux/completion.h
include/linux/cpufreq.h
include/linux/cpuidle.h
include/linux/dcache.h
include/linux/debug_locks.h
include/linux/devfreq.h
include/linux/device.h
include/linux/dmaengine.h
include/linux/efi.h
include/linux/err.h
include/linux/freezer.h
include/linux/fs.h
include/linux/fsnotify.h
include/linux/hardirq.h
include/linux/huge_mm.h
include/linux/hugetlb.h
include/linux/irq.h
include/linux/irqdomain.h
include/linux/kernel.h
include/linux/kvm_host.h
include/linux/lcd.h
include/linux/libata.h
include/linux/memcontrol.h
include/linux/memory_hotplug.h
include/linux/mfd/abx500/ab8500-sysctrl.h
include/linux/mfd/arizona/core.h
include/linux/mfd/arizona/pdata.h
include/linux/mfd/arizona/registers.h
include/linux/mfd/dbx500-prcmu.h
include/linux/mfd/max77693-private.h
include/linux/mfd/max77693.h
include/linux/mfd/mc13xxx.h
include/linux/mfd/twl6040.h
include/linux/mfd/wm8994/pdata.h
include/linux/mfd/wm8994/registers.h
include/linux/mm.h
include/linux/mman.h
include/linux/mmzone.h
include/linux/mod_devicetable.h
include/linux/msi.h
include/linux/mutex-debug.h
include/linux/mutex.h
include/linux/nbd.h
include/linux/pageblock-flags.h
include/linux/pagevec.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/percpu-refcount.h [new file with mode: 0644]
include/linux/perf_event.h
include/linux/pid.h
include/linux/pinctrl/consumer.h
include/linux/pinctrl/devinfo.h
include/linux/pinctrl/pinconf-generic.h
include/linux/pinctrl/pinconf.h
include/linux/pinctrl/pinctrl.h
include/linux/platform_data/clk-ux500.h
include/linux/platform_data/g762.h [new file with mode: 0644]
include/linux/platform_data/si5351.h
include/linux/platform_data/ssm2518.h [new file with mode: 0644]
include/linux/pm_runtime.h
include/linux/power/smartreflex.h
include/linux/rcupdate.h
include/linux/rcutiny.h
include/linux/rcutree.h
include/linux/regmap.h
include/linux/regulator/ab8500.h
include/linux/regulator/consumer.h
include/linux/rio.h
include/linux/rio_ids.h
include/linux/sched.h
include/linux/security.h
include/linux/smp.h
include/linux/spi/spi.h
include/linux/spi/xilinx_spi.h
include/linux/spinlock_up.h
include/linux/srcu.h
include/linux/suspend.h
include/linux/swap.h
include/linux/tpm.h
include/linux/tracepoint.h
include/linux/virtio.h
include/linux/vmalloc.h
include/linux/workqueue.h
include/sound/control.h
include/sound/core.h
include/sound/pcm.h
include/sound/rt5640.h [new file with mode: 0644]
include/sound/soc-dapm.h
include/sound/soc.h
include/trace/define_trace.h
include/trace/events/nmi.h [new file with mode: 0644]
include/trace/events/pagemap.h [new file with mode: 0644]
include/trace/events/power.h
include/trace/events/regmap.h
include/trace/ftrace.h
include/uapi/asm-generic/fcntl.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/const.h
include/uapi/linux/kvm.h
include/uapi/linux/pci_regs.h
include/uapi/linux/perf_event.h
include/uapi/linux/ptrace.h
include/uapi/linux/virtio_console.h
include/uapi/linux/virtio_pci.h
include/uapi/sound/asound.h
include/xen/acpi.h
include/xen/events.h
include/xen/hvm.h
include/xen/interface/io/protocols.h
init/Kconfig
init/do_mounts.c
init/main.c
kernel/Kconfig.locks
kernel/cgroup.c
kernel/cpuset.c
kernel/events/core.c
kernel/events/hw_breakpoint.c
kernel/exit.c
kernel/fork.c
kernel/freezer.c
kernel/futex.c
kernel/hrtimer.c
kernel/irq/chip.c
kernel/irq/generic-chip.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/kmod.c
kernel/kprobes.c
kernel/lockdep.c
kernel/mutex.c
kernel/pid.c
kernel/power/Kconfig
kernel/power/main.c
kernel/power/process.c
kernel/power/qos.c
kernel/power/snapshot.c
kernel/power/suspend.c
kernel/ptrace.c
kernel/rcupdate.c
kernel/rcutiny.c
kernel/rcutiny_plugin.h
kernel/rcutorture.c
kernel/rcutree.c
kernel/rcutree.h
kernel/rcutree_plugin.h
kernel/resource.c
kernel/rtmutex.c
kernel/sched/Makefile
kernel/sched/auto_group.c
kernel/sched/core.c
kernel/sched/cputime.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/proc.c [new file with mode: 0644]
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/stats.h
kernel/sched/stop_task.c
kernel/signal.c
kernel/softirq.c
kernel/sys.c
kernel/sysctl.c
kernel/time.c
kernel/workqueue.c
kernel/workqueue_internal.h
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/debug_locks.c
lib/dump_stack.c
lib/fonts/Kconfig [new file with mode: 0644]
lib/fonts/Makefile [new file with mode: 0644]
lib/fonts/font_10x18.c [moved from drivers/video/console/font_10x18.c with 100% similarity]
lib/fonts/font_6x11.c [moved from drivers/video/console/font_6x11.c with 100% similarity]
lib/fonts/font_7x14.c [moved from drivers/video/console/font_7x14.c with 100% similarity]
lib/fonts/font_8x16.c [moved from drivers/video/console/font_8x16.c with 100% similarity]
lib/fonts/font_8x8.c [moved from drivers/video/console/font_8x8.c with 100% similarity]
lib/fonts/font_acorn_8x8.c [moved from drivers/video/console/font_acorn_8x8.c with 100% similarity]
lib/fonts/font_mini_4x6.c [moved from drivers/video/console/font_mini_4x6.c with 100% similarity]
lib/fonts/font_pearl_8x8.c [moved from drivers/video/console/font_pearl_8x8.c with 100% similarity]
lib/fonts/font_sun12x22.c [moved from drivers/video/console/font_sun12x22.c with 100% similarity]
lib/fonts/font_sun8x16.c [moved from drivers/video/console/font_sun8x16.c with 100% similarity]
lib/fonts/fonts.c [moved from drivers/video/console/fonts.c with 98% similarity]
lib/idr.c
lib/locking-selftest.c
lib/percpu-refcount.c [new file with mode: 0644]
lib/percpu_counter.c
mm/Kconfig
mm/backing-dev.c
mm/bootmem.c
mm/huge_memory.c
mm/hugetlb.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/mm_init.c
mm/mmap.c
mm/mremap.c
mm/nobootmem.c
mm/nommu.c
mm/page_alloc.c
mm/page_io.c
mm/rmap.c
mm/shmem.c
mm/sparse.c
mm/swap.c
mm/swapfile.c
mm/vmalloc.c
mm/vmscan.c
net/bluetooth/hci_core.c
net/ipv4/inet_fragment.c
net/mac80211/main.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/sched.c
net/sunrpc/svc.c
net/unix/af_unix.c
scripts/checkpatch.pl
scripts/mod/devicetable-offsets.c
scripts/mod/file2alias.c
scripts/mod/modpost.c
scripts/sortextable.c
security/apparmor/audit.c
security/apparmor/context.c
security/apparmor/domain.c
security/apparmor/include/apparmor.h
security/apparmor/include/context.h
security/apparmor/include/file.h
security/apparmor/include/match.h
security/apparmor/include/policy.h
security/apparmor/include/procattr.h
security/apparmor/include/sid.h
security/apparmor/ipc.c
security/apparmor/lib.c
security/apparmor/lsm.c
security/apparmor/match.c
security/apparmor/path.c
security/apparmor/policy.c
security/apparmor/policy_unpack.c
security/apparmor/procattr.c
security/apparmor/resource.c
security/device_cgroup.c
security/integrity/Kconfig
security/integrity/Makefile
security/integrity/evm/evm_main.c
security/integrity/ima/Kconfig
security/integrity/ima/Makefile
security/integrity/ima/ima.h
security/integrity/ima/ima_main.c
security/integrity/integrity.h
security/integrity/integrity_audit.c [moved from security/integrity/ima/ima_audit.c with 85% similarity]
security/selinux/hooks.c
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c
sound/arm/aaci.c
sound/arm/pxa2xx-ac97.c
sound/core/Kconfig
sound/core/init.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/vmaster.c
sound/drivers/aloop.c
sound/drivers/dummy.c
sound/drivers/ml403-ac97cr.c
sound/drivers/mpu401/mpu401.c
sound/drivers/mtpav.c
sound/drivers/pcsp/pcsp.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/drivers/vx/vx_core.c
sound/firewire/amdtp.h
sound/firewire/scs1x.c
sound/i2c/other/ak4xxx-adda.c
sound/isa/ad1848/ad1848.c
sound/isa/adlib.c
sound/isa/cmi8328.c
sound/isa/cmi8330.c
sound/isa/cs423x/cs4231.c
sound/isa/cs423x/cs4236.c
sound/isa/es1688/es1688.c
sound/isa/es18xx.c
sound/isa/galaxy/galaxy.c
sound/isa/gus/gusclassic.c
sound/isa/gus/gusextreme.c
sound/isa/gus/gusmax.c
sound/isa/gus/interwave.c
sound/isa/msnd/msnd_pinnacle.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/jazz16.c
sound/isa/sb/sb16.c
sound/isa/sb/sb8.c
sound/isa/sc6000.c
sound/isa/sscape.c
sound/isa/wavefront/wavefront.c
sound/oss/kahlua.c
sound/parisc/harmony.c
sound/pci/ac97/ac97_codec.c
sound/pci/ad1889.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/asihpi/asihpi.c
sound/pci/asihpi/hpioctl.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.c
sound/pci/aw2/aw2-alsa.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs5530.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/ctxfi/xfi.c
sound/pci/echoaudio/echoaudio.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/Kconfig
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/lola/lola.c
sound/pci/lx6464es/lx6464es.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen_lib.c
sound/pci/pcxhr/pcxhr.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sis7019.c
sound/pci/sonicvibes.c
sound/pci/trident/trident.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci_main.c
sound/ppc/powermac.c
sound/sh/aica.c
sound/sh/sh_dac_audio.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/au1x/ac97c.c
sound/soc/au1x/psc-ac97.c
sound/soc/blackfin/Kconfig
sound/soc/blackfin/Makefile
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97-pcm.h [deleted file]
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bf5xx-ad193x.c
sound/soc/blackfin/bf5xx-ad1980.c
sound/soc/blackfin/bf5xx-ad73311.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/blackfin/bf5xx-i2s-pcm.h
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-sport.c
sound/soc/blackfin/bf5xx-sport.h
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/blackfin/bf5xx-tdm-pcm.c [deleted file]
sound/soc/blackfin/bf5xx-tdm-pcm.h [deleted file]
sound/soc/blackfin/bf5xx-tdm.c [deleted file]
sound/soc/blackfin/bf5xx-tdm.h [deleted file]
sound/soc/cirrus/Kconfig
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/cirrus/ep93xx-pcm.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ab8500-codec.h
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/bt-sco.c [moved from sound/soc/codecs/dfbmcs320.c with 53% similarity]
sound/soc/codecs/hdmi.c [moved from sound/soc/codecs/omap-hdmi.c with 69% similarity]
sound/soc/codecs/jz4740.c
sound/soc/codecs/max98090.c
sound/soc/codecs/rt5640.c [new file with mode: 0644]
sound/soc/codecs/rt5640.h [new file with mode: 0644]
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sgtl5000.h
sound/soc/codecs/si476x.c
sound/soc/codecs/sn95031.c
sound/soc/codecs/spdif_receiver.c
sound/soc/codecs/spdif_transmitter.c [moved from sound/soc/codecs/spdif_transciever.c with 88% similarity]
sound/soc/codecs/ssm2518.c [new file with mode: 0644]
sound/soc/codecs/ssm2518.h [new file with mode: 0644]
sound/soc/codecs/stac9766.c
sound/soc/codecs/tas5086.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/wm0010.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8991.h
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm8995.h
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/Kconfig
sound/soc/davinci/Makefile
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-sffsdr.c [deleted file]
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/eukrea-tlv320.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-audmux.c
sound/soc/fsl/imx-mc13783.c
sound/soc/fsl/imx-pcm-dma.c
sound/soc/fsl/imx-pcm-fiq.c
sound/soc/fsl/imx-pcm.c [deleted file]
sound/soc/fsl/imx-pcm.h
sound/soc/fsl/imx-sgtl5000.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/imx-ssi.h
sound/soc/fsl/imx-wm8962.c [new file with mode: 0644]
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/fsl/mx27vis-aic32x4.c
sound/soc/fsl/phycore-ac97.c
sound/soc/fsl/wm1133-ev1.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/mid-x86/mfld_machine.c
sound/soc/mxs/mxs-pcm.c
sound/soc/mxs/mxs-pcm.h
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-saif.h
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/omap-hdmi-card.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/rx51.c
sound/soc/pxa/Kconfig
sound/soc/pxa/Makefile
sound/soc/pxa/mmp-pcm.c
sound/soc/pxa/mmp-sspa.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-ac97.h
sound/soc/pxa/saarb.c [deleted file]
sound/soc/pxa/tavorevb3.c [deleted file]
sound/soc/pxa/zylonite.c
sound/soc/samsung/Kconfig
sound/soc/samsung/ac97.c
sound/soc/samsung/bells.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/smdk_wm8580pcm.c
sound/soc/samsung/smdk_wm8994pcm.c
sound/soc/sh/fsi.c
sound/soc/sh/hac.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/soc-utils.c
sound/soc/spear/Kconfig [new file with mode: 0644]
sound/soc/spear/Makefile [new file with mode: 0644]
sound/soc/spear/spdif_in.c
sound/soc/spear/spdif_out.c
sound/soc/spear/spear_pcm.c
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra30_ahub.c
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra_asoc_utils.c
sound/soc/tegra/tegra_rt5640.c [new file with mode: 0644]
sound/soc/txx9/txx9aclc-ac97.c
sound/soc/ux500/mop500.c
sound/soc/ux500/mop500_ab8500.c
sound/soc/ux500/ux500_msp_dai.c
sound/soc/ux500/ux500_msp_dai.h
sound/soc/ux500/ux500_msp_i2s.c
sound/soc/ux500/ux500_msp_i2s.h
sound/soc/ux500/ux500_pcm.c
sound/sound_core.c
sound/sparc/dbri.c
sound/spi/at73c213.c
sound/usb/6fire/chip.c
sound/usb/6fire/pcm.c
sound/usb/Kconfig
sound/usb/Makefile
sound/usb/caiaq/audio.c
sound/usb/caiaq/device.c
sound/usb/card.h
sound/usb/clock.c
sound/usb/format.c
sound/usb/format.h
sound/usb/hiface/Makefile [new file with mode: 0644]
sound/usb/hiface/chip.c [new file with mode: 0644]
sound/usb/hiface/chip.h [new file with mode: 0644]
sound/usb/hiface/pcm.c [new file with mode: 0644]
sound/usb/hiface/pcm.h [new file with mode: 0644]
sound/usb/midi.c
sound/usb/misc/ua101.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/stream.c
sound/usb/usbaudio.h
sound/usb/usx2y/usbusx2y.c
sound/usb/usx2y/usbusx2yaudio.c
tools/lib/lk/Makefile
tools/perf/Documentation/perf-archive.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-top.txt
tools/perf/Makefile
tools/perf/builtin-diff.c
tools/perf/builtin-kvm.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-top.c
tools/perf/config/Makefile [new file with mode: 0644]
tools/perf/tests/attr/base-record
tools/perf/tests/attr/base-stat
tools/perf/tests/attr/test-record-data
tools/perf/tests/bp_signal.c
tools/perf/tests/bp_signal_overflow.c
tools/perf/tests/builtin-test.c
tools/perf/tests/make [new file with mode: 0644]
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/hists.c
tools/perf/ui/stdio/hist.c
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/map.c
tools/perf/util/session.h
tools/perf/util/setup.py
tools/perf/util/sort.c
tools/perf/util/sort.h
tools/perf/util/stat.c
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/top.c
tools/perf/util/top.h
tools/perf/util/util.h
tools/testing/selftests/cpu-hotplug/Makefile
tools/testing/selftests/kcmp/.gitignore [new file with mode: 0644]
tools/testing/selftests/kcmp/Makefile
tools/testing/selftests/memory-hotplug/Makefile
tools/testing/selftests/vm/.gitignore [new file with mode: 0644]
tools/testing/selftests/vm/Makefile
tools/testing/selftests/vm/hugetlbfstest.c [new file with mode: 0644]
tools/testing/selftests/vm/run_vmtests
virt/kvm/arm/arch_timer.c [moved from arch/arm/kvm/arch_timer.c with 90% similarity]
virt/kvm/arm/vgic.c [moved from arch/arm/kvm/vgic.c with 100% similarity]
virt/kvm/eventfd.c
virt/kvm/kvm_main.c

diff --git a/Documentation/ABI/testing/sysfs-bus-acpi b/Documentation/ABI/testing/sysfs-bus-acpi
new file mode 100644 (file)
index 0000000..7fa9cbc
--- /dev/null
@@ -0,0 +1,58 @@
+What:          /sys/bus/acpi/devices/.../path
+Date:          December 2006
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+               This attribute indicates the full path of ACPI namespace
+               object associated with the device object.  For example,
+               \_SB_.PCI0.
+               This file is not present for device objects representing
+               fixed ACPI hardware features (like power and sleep
+               buttons).
+
+What:          /sys/bus/acpi/devices/.../modalias
+Date:          July 2007
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+               This attribute indicates the PNP IDs of the device object.
+               That is acpi:HHHHHHHH:[CCCCCCC:].  Where each HHHHHHHH or
+               CCCCCCCC contains device object's PNPID (_HID or _CID).
+
+What:          /sys/bus/acpi/devices/.../hid
+Date:          April 2005
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+               This attribute indicates the hardware ID (_HID) of the
+               device object.  For example, PNP0103.
+               This file is present for device objects having the _HID
+               control method.
+
+What:          /sys/bus/acpi/devices/.../description
+Date:          October 2012
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+               This attribute contains the output of the device object's
+               _STR control method, if present.
+
+What:          /sys/bus/acpi/devices/.../adr
+Date:          October 2012
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+               This attribute contains the output of the device object's
+               _ADR control method, which is present for ACPI device
+               objects representing devices having standard enumeration
+               algorithms, such as PCI.
+
+What:          /sys/bus/acpi/devices/.../uid
+Date:          October 2012
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+               This attribute contains the output of the device object's
+               _UID control method, if present.
+
+What:          /sys/bus/acpi/devices/.../eject
+Date:          December 2006
+Contact:       Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+               Writing 1 to this attribute will trigger hot removal of
+               this device object.  This file exists for every device
+               object that has _EJ0 method.
index 0adeb524c0d4798671e9f6034284fd7c6694e33b..8b25ffb42562f06d473b9633b3a5ef9fea506b10 100644 (file)
@@ -27,14 +27,36 @@ Description:        Generic performance monitoring events
                "basename".
 
 
-What:          /sys/devices/cpu/events/PM_LD_MISS_L1
-               /sys/devices/cpu/events/PM_LD_REF_L1
-               /sys/devices/cpu/events/PM_CYC
+What:          /sys/devices/cpu/events/PM_1PLUS_PPC_CMPL
                /sys/devices/cpu/events/PM_BRU_FIN
-               /sys/devices/cpu/events/PM_GCT_NOSLOT_CYC
                /sys/devices/cpu/events/PM_BRU_MPRED
-               /sys/devices/cpu/events/PM_INST_CMPL
                /sys/devices/cpu/events/PM_CMPLU_STALL
+               /sys/devices/cpu/events/PM_CMPLU_STALL_BRU
+               /sys/devices/cpu/events/PM_CMPLU_STALL_DCACHE_MISS
+               /sys/devices/cpu/events/PM_CMPLU_STALL_DFU
+               /sys/devices/cpu/events/PM_CMPLU_STALL_DIV
+               /sys/devices/cpu/events/PM_CMPLU_STALL_ERAT_MISS
+               /sys/devices/cpu/events/PM_CMPLU_STALL_FXU
+               /sys/devices/cpu/events/PM_CMPLU_STALL_IFU
+               /sys/devices/cpu/events/PM_CMPLU_STALL_LSU
+               /sys/devices/cpu/events/PM_CMPLU_STALL_REJECT
+               /sys/devices/cpu/events/PM_CMPLU_STALL_SCALAR
+               /sys/devices/cpu/events/PM_CMPLU_STALL_SCALAR_LONG
+               /sys/devices/cpu/events/PM_CMPLU_STALL_STORE
+               /sys/devices/cpu/events/PM_CMPLU_STALL_THRD
+               /sys/devices/cpu/events/PM_CMPLU_STALL_VECTOR
+               /sys/devices/cpu/events/PM_CMPLU_STALL_VECTOR_LONG
+               /sys/devices/cpu/events/PM_CYC
+               /sys/devices/cpu/events/PM_GCT_NOSLOT_BR_MPRED
+               /sys/devices/cpu/events/PM_GCT_NOSLOT_BR_MPRED_IC_MISS
+               /sys/devices/cpu/events/PM_GCT_NOSLOT_CYC
+               /sys/devices/cpu/events/PM_GCT_NOSLOT_IC_MISS
+               /sys/devices/cpu/events/PM_GRP_CMPL
+               /sys/devices/cpu/events/PM_INST_CMPL
+               /sys/devices/cpu/events/PM_LD_MISS_L1
+               /sys/devices/cpu/events/PM_LD_REF_L1
+               /sys/devices/cpu/events/PM_RUN_CYC
+               /sys/devices/cpu/events/PM_RUN_INST_CMPL
 
 Date:          2013/01/08
 
index 079afc71363d87de03aae46c580f4ac308460594..77f47ff5ee02b9beb661f5e61f1b967105a2ab01 100644 (file)
@@ -9,6 +9,12 @@ Description:
                we want to export, so that userspace can deal with sane
                name/value pairs.
 
+               Userspace must be prepared for the possibility that attributes
+               define overlapping bit ranges. For example:
+                       attr1 = 'config:0-23'
+                       attr2 = 'config:0-7'
+                       attr3 = 'config:12-35'
+
                Example: 'config1:1,6-10,44'
                Defines contents of attribute that occupies bits 1,6-10,44 of
                perf_event_attr::config1.
index 0ba6ea2f89d9b831bdebdcc2419727464a59d88c..ee39acacf6f8512cb81eedaf0d06685bbf004144 100644 (file)
@@ -78,3 +78,23 @@ Contact:     Nishanth Menon <nm@ti.com>
 Description:
                The /sys/class/devfreq/.../available_governors shows
                currently available governors in the system.
+
+What:          /sys/class/devfreq/.../min_freq
+Date:          January 2013
+Contact:       MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+               The /sys/class/devfreq/.../min_freq shows and stores
+               the minimum frequency requested by users. It is 0 if
+               the user does not care. min_freq overrides the
+               frequency requested by governors.
+
+What:          /sys/class/devfreq/.../max_freq
+Date:          January 2013
+Contact:       MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+               The /sys/class/devfreq/.../max_freq shows and stores
+               the maximum frequency requested by users. It is 0 if
+               the user does not care. max_freq overrides the
+               frequency requested by governors and min_freq.
+               The max_freq overrides min_freq because max_freq may be
+               used to throttle devices to avoid overheating.
diff --git a/Documentation/ABI/testing/sysfs-devices-online b/Documentation/ABI/testing/sysfs-devices-online
new file mode 100644 (file)
index 0000000..f990026
--- /dev/null
@@ -0,0 +1,20 @@
+What:          /sys/devices/.../online
+Date:          April 2013
+Contact:       Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+               The /sys/devices/.../online attribute is only present for
+               devices whose bus types provide .online() and .offline()
+               callbacks.  The number read from it (0 or 1) reflects the value
+               of the device's 'offline' field.  If that number is 1 and '0'
+               (or 'n', or 'N') is written to this file, the device bus type's
+               .offline() callback is executed for the device and (if
+               successful) its 'offline' field is updated accordingly.  In
+               turn, if that number is 0 and '1' (or 'y', or 'Y') is written to
+               this file, the device bus type's .online() callback is executed
+               for the device and (if successful) its 'offline' field is
+               updated as appropriate.
+
+               After a successful execution of the bus type's .offline()
+               callback the device cannot be used for any purpose until either
+               it is removed (i.e. device_del() is called for it), or its bus
+               type's .online() is exeucted successfully.
index 86be9848a77e2251bcd2e2cb7b904145147cbff3..625ce4b6375825a1e5908a9323b655c177799e17 100644 (file)
@@ -1,4 +1,4 @@
-Whatt:         /sys/devices/.../sun
+What         /sys/devices/.../sun
 Date:          October 2012
 Contact:       Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
 Description:
index 2447698aed41d73a98326f8ae67e89062ab29889..468e4d48f88437916117e3377147f51951db7982 100644 (file)
@@ -144,6 +144,21 @@ Description:       Discover and change clock speed of CPUs
                to learn how to control the knobs.
 
 
+What:          /sys/devices/system/cpu/cpu#/cpufreq/freqdomain_cpus
+Date:          June 2013
+Contact:       cpufreq@vger.kernel.org
+Description:   Discover CPUs in the same CPU frequency coordination domain
+
+               freqdomain_cpus is the list of CPUs (online+offline) that share
+               the same clock/freq domain (possibly at the hardware level).
+               That information may be hidden from the cpufreq core and the
+               value of related_cpus may be different from freqdomain_cpus. This
+               attribute is useful for user space DVFS controllers to get better
+               power/performance results for platforms using acpi-cpufreq.
+
+               This file is only present if the acpi-cpufreq driver is in use.
+
+
 What:          /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1}
 Date:          August 2008
 KernelVersion: 2.6.27
index ce9bee98b43be62f84937502ed6fdfae38d43b3d..b4436cca97a83612fd3305630f5e0807eb53caeb 100644 (file)
@@ -44,6 +44,16 @@ Description:
                or 0 (unset).  Attempts to write any other values to it will
                cause -EINVAL to be returned.
 
+What:          /sys/firmware/acpi/hotplug/force_remove
+Date:          May 2013
+Contact:       Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+               The number in this file (0 or 1) determines whether (1) or not
+               (0) the ACPI subsystem will allow devices to be hot-removed even
+               if they cannot be put offline gracefully (from the kernel's
+               viewpoint).  That number can be changed by writing a boolean
+               value to this file.
+
 What:          /sys/firmware/acpi/interrupts/
 Date:          February 2008
 Contact:       Len Brown <lenb@kernel.org>
index e00b8f0dde52e520d5bcc378aa0bbf4f506a6b23..7fe0546c504afdefc4be2f71279df7c377c03b46 100644 (file)
@@ -389,7 +389,8 @@ Albeit deprecated by some people, the equivalent of the goto statement is
 used frequently by compilers in form of the unconditional jump instruction.
 
 The goto statement comes in handy when a function exits from multiple
-locations and some common work such as cleanup has to be done.
+locations and some common work such as cleanup has to be done.  If there is no
+cleanup needed then just return directly.
 
 The rationale is:
 
index c36892c072dad4aaff9b2e34f3653ac88c915190..fca34192cf806902c4c21759a50c772f31c66f9d 100644 (file)
@@ -297,10 +297,10 @@ KAO -->
      </sect1>
      <sect1><title>Frame Buffer Fonts</title>
         <para>
-           Refer to the file drivers/video/console/fonts.c for more information.
+           Refer to the file lib/fonts/fonts.c for more information.
         </para>
 <!-- FIXME: Removed for now since no structured comments in source
-X!Idrivers/video/console/fonts.c
+X!Ilib/fonts/fonts.c
 -->
      </sect1>
   </chapter>
index b3422341d65c7ae07c14b743c328cae15c529d17..d16d21b7a3b7aec2884c2183005c337b3d075002 100644 (file)
@@ -464,6 +464,19 @@ if (desc->irq_data.chip->irq_eoi)
        protected via desc->lock, by the generic layer.
      </para>
   </chapter>
+
+  <chapter id="genericchip">
+     <title>Generic interrupt chip</title>
+     <para>
+       To avoid copies of identical implementations of irq chips the
+       core provides a configurable generic interrupt chip
+       implementation. Developers should check carefuly whether the
+       generic chip fits their needs before implementing the same
+       functionality slightly different themself.
+     </para>
+!Ekernel/irq/generic-chip.c
+  </chapter>
+
   <chapter id="structs">
      <title>Structures</title>
      <para>
index 67e7ab41c0a6592a747bd414e3bf5923f111ca6a..09e884e5b9f53d1ff32bbc785c61dcb6ec5e56e4 100644 (file)
@@ -1955,12 +1955,17 @@ machines due to caching.
    </sect1>
   </chapter>
 
-  <chapter id="apiref">
+  <chapter id="apiref-mutex">
    <title>Mutex API reference</title>
 !Iinclude/linux/mutex.h
 !Ekernel/mutex.c
   </chapter>
 
+  <chapter id="apiref-futex">
+   <title>Futex API reference</title>
+!Ikernel/futex.c
+  </chapter>
+
   <chapter id="references">
    <title>Further reading</title>
 
index 79e789b8b8ea22d680463a531a3e3d9990adb8ba..7703ec73a9bbb225a45258c4cde11c8cc9dd236f 100644 (file)
@@ -354,12 +354,6 @@ over a rather long period of time, but improvements are always welcome!
        using RCU rather than SRCU, because RCU is almost always faster
        and easier to use than is SRCU.
 
-       If you need to enter your read-side critical section in a
-       hardirq or exception handler, and then exit that same read-side
-       critical section in the task that was interrupted, then you need
-       to srcu_read_lock_raw() and srcu_read_unlock_raw(), which avoid
-       the lockdep checking that would otherwise this practice illegal.
-
        Also unlike other forms of RCU, explicit initialization
        and cleanup is required via init_srcu_struct() and
        cleanup_srcu_struct().  These are passed a "struct srcu_struct"
index 7dce8a17eac269cdff475a57377bf49963c1216a..d8a50238739719b49aa0f04077860326cf98cc4d 100644 (file)
@@ -182,12 +182,6 @@ torture_type       The type of RCU to test, with string values as follows:
                "srcu_expedited": srcu_read_lock(), srcu_read_unlock() and
                        synchronize_srcu_expedited().
 
-               "srcu_raw": srcu_read_lock_raw(), srcu_read_unlock_raw(),
-                       and call_srcu().
-
-               "srcu_raw_sync": srcu_read_lock_raw(), srcu_read_unlock_raw(),
-                       and synchronize_srcu().
-
                "sched": preempt_disable(), preempt_enable(), and
                        call_rcu_sched().
 
index c776968f446300db6ff7d43695c0828e222d6694..f3778f8952da1b9473897a4a2f392f049b9c544c 100644 (file)
@@ -530,113 +530,21 @@ o        "nos" counts the number of times we balked for other
        reasons, e.g., the grace period ended first.
 
 
-CONFIG_TINY_RCU and CONFIG_TINY_PREEMPT_RCU debugfs Files and Formats
+CONFIG_TINY_RCU debugfs Files and Formats
 
 These implementations of RCU provides a single debugfs file under the
 top-level directory RCU, namely rcu/rcudata, which displays fields in
-rcu_bh_ctrlblk, rcu_sched_ctrlblk and, for CONFIG_TINY_PREEMPT_RCU,
-rcu_preempt_ctrlblk.
+rcu_bh_ctrlblk and rcu_sched_ctrlblk.
 
 The output of "cat rcu/rcudata" is as follows:
 
-rcu_preempt: qlen=24 gp=1097669 g197/p197/c197 tasks=...
-             ttb=. btg=no ntb=184 neb=0 nnb=183 j=01f7 bt=0274
-             normal balk: nt=1097669 gt=0 bt=371 b=0 ny=25073378 nos=0
-             exp balk: bt=0 nos=0
 rcu_sched: qlen: 0
 rcu_bh: qlen: 0
 
-This is split into rcu_preempt, rcu_sched, and rcu_bh sections, with the
-rcu_preempt section appearing only in CONFIG_TINY_PREEMPT_RCU builds.
-The last three lines of the rcu_preempt section appear only in
-CONFIG_RCU_BOOST kernel builds.  The fields are as follows:
+This is split into rcu_sched and rcu_bh sections.  The field is as
+follows:
 
 o      "qlen" is the number of RCU callbacks currently waiting either
        for an RCU grace period or waiting to be invoked.  This is the
        only field present for rcu_sched and rcu_bh, due to the
        short-circuiting of grace period in those two cases.
-
-o      "gp" is the number of grace periods that have completed.
-
-o      "g197/p197/c197" displays the grace-period state, with the
-       "g" number being the number of grace periods that have started
-       (mod 256), the "p" number being the number of grace periods
-       that the CPU has responded to (also mod 256), and the "c"
-       number being the number of grace periods that have completed
-       (once again mode 256).
-
-       Why have both "gp" and "g"?  Because the data flowing into
-       "gp" is only present in a CONFIG_RCU_TRACE kernel.
-
-o      "tasks" is a set of bits.  The first bit is "T" if there are
-       currently tasks that have recently blocked within an RCU
-       read-side critical section, the second bit is "N" if any of the
-       aforementioned tasks are blocking the current RCU grace period,
-       and the third bit is "E" if any of the aforementioned tasks are
-       blocking the current expedited grace period.  Each bit is "."
-       if the corresponding condition does not hold.
-
-o      "ttb" is a single bit.  It is "B" if any of the blocked tasks
-       need to be priority boosted and "." otherwise.
-
-o      "btg" indicates whether boosting has been carried out during
-       the current grace period, with "exp" indicating that boosting
-       is in progress for an expedited grace period, "no" indicating
-       that boosting has not yet started for a normal grace period,
-       "begun" indicating that boosting has bebug for a normal grace
-       period, and "done" indicating that boosting has completed for
-       a normal grace period.
-
-o      "ntb" is the total number of tasks subjected to RCU priority boosting
-       periods since boot.
-
-o      "neb" is the number of expedited grace periods that have had
-       to resort to RCU priority boosting since boot.
-
-o      "nnb" is the number of normal grace periods that have had
-       to resort to RCU priority boosting since boot.
-
-o      "j" is the low-order 16 bits of the jiffies counter in hexadecimal.
-
-o      "bt" is the low-order 16 bits of the value that the jiffies counter
-       will have at the next time that boosting is scheduled to begin.
-
-o      In the line beginning with "normal balk", the fields are as follows:
-
-       o       "nt" is the number of times that the system balked from
-               boosting because there were no blocked tasks to boost.
-               Note that the system will balk from boosting even if the
-               grace period is overdue when the currently running task
-               is looping within an RCU read-side critical section.
-               There is no point in boosting in this case, because
-               boosting a running task won't make it run any faster.
-
-       o       "gt" is the number of times that the system balked
-               from boosting because, although there were blocked tasks,
-               none of them were preventing the current grace period
-               from completing.
-
-       o       "bt" is the number of times that the system balked
-               from boosting because boosting was already in progress.
-
-       o       "b" is the number of times that the system balked from
-               boosting because boosting had already completed for
-               the grace period in question.
-
-       o       "ny" is the number of times that the system balked from
-               boosting because it was not yet time to start boosting
-               the grace period in question.
-
-       o       "nos" is the number of times that the system balked from
-               boosting for inexplicable ("not otherwise specified")
-               reasons.  This can actually happen due to races involving
-               increments of the jiffies counter.
-
-o      In the line beginning with "exp balk", the fields are as follows:
-
-       o       "bt" is the number of times that the system balked from
-               boosting because there were no blocked tasks to boost.
-
-       o       "nos" is the number of times that the system balked from
-                boosting for inexplicable ("not otherwise specified")
-                reasons.
index 10df0b82f45939a91aec83c450b6713c6cafdc18..0f0fb7c432c2a3b7db062edfc4c6c8c94e7cae1e 100644 (file)
@@ -842,9 +842,7 @@ SRCU:       Critical sections       Grace period            Barrier
 
        srcu_read_lock          synchronize_srcu        srcu_barrier
        srcu_read_unlock        call_srcu
-       srcu_read_lock_raw      synchronize_srcu_expedited
-       srcu_read_unlock_raw
-       srcu_dereference
+       srcu_dereference        synchronize_srcu_expedited
 
 SRCU:  Initialization/cleanup
        init_srcu_struct
@@ -865,38 +863,32 @@ list can be helpful:
 
 a.     Will readers need to block?  If so, you need SRCU.
 
-b.     Is it necessary to start a read-side critical section in a
-       hardirq handler or exception handler, and then to complete
-       this read-side critical section in the task that was
-       interrupted?  If so, you need SRCU's srcu_read_lock_raw() and
-       srcu_read_unlock_raw() primitives.
-
-c.     What about the -rt patchset?  If readers would need to block
+b.     What about the -rt patchset?  If readers would need to block
        in an non-rt kernel, you need SRCU.  If readers would block
        in a -rt kernel, but not in a non-rt kernel, SRCU is not
        necessary.
 
-d.     Do you need to treat NMI handlers, hardirq handlers,
+c.     Do you need to treat NMI handlers, hardirq handlers,
        and code segments with preemption disabled (whether
        via preempt_disable(), local_irq_save(), local_bh_disable(),
        or some other mechanism) as if they were explicit RCU readers?
        If so, RCU-sched is the only choice that will work for you.
 
-e.     Do you need RCU grace periods to complete even in the face
+d.     Do you need RCU grace periods to complete even in the face
        of softirq monopolization of one or more of the CPUs?  For
        example, is your code subject to network-based denial-of-service
        attacks?  If so, you need RCU-bh.
 
-f.     Is your workload too update-intensive for normal use of
+e.     Is your workload too update-intensive for normal use of
        RCU, but inappropriate for other synchronization mechanisms?
        If so, consider SLAB_DESTROY_BY_RCU.  But please be careful!
 
-g.     Do you need read-side critical sections that are respected
+f.     Do you need read-side critical sections that are respected
        even though they are in the middle of the idle loop, during
        user-mode execution, or on an offlined CPU?  If so, SRCU is the
        only choice that will work for you.
 
-h.     Otherwise, use RCU.
+g.     Otherwise, use RCU.
 
 Of course, this all assumes that you have determined that RCU is in fact
 the right tool for your job.
index f8ebcde43b174640ae1ab1d8ac47426a10688614..c6a06b71594d4726ed6cfe5577dbaeda8cba1bb0 100644 (file)
@@ -272,7 +272,7 @@ int main(int argc, char *argv[])
        char *logfile = NULL;
        int loop = 0;
        int containerset = 0;
-       char containerpath[1024];
+       char *containerpath = NULL;
        int cfd = 0;
        int forking = 0;
        sigset_t sigset;
@@ -299,7 +299,7 @@ int main(int argc, char *argv[])
                        break;
                case 'C':
                        containerset = 1;
-                       strncpy(containerpath, optarg, strlen(optarg) + 1);
+                       containerpath = optarg;
                        break;
                case 'w':
                        logfile = strdup(optarg);
index e20b6daaced48d9f2ab39ef3749792fc34123003..a58b63da1a366ea5dddc8af574779ea68773610a 100644 (file)
@@ -47,11 +47,16 @@ directory apei/einj. The following files are provided.
 
 - param1
   This file is used to set the first error parameter value. Effect of
-  parameter depends on error_type specified.
+  parameter depends on error_type specified. For example, if error
+  type is memory related type, the param1 should be a valid physical
+  memory address.
 
 - param2
   This file is used to set the second error parameter value. Effect of
-  parameter depends on error_type specified.
+  parameter depends on error_type specified. For example, if error
+  type is memory related type, the param2 should be a physical memory
+  address mask. Linux requires page or narrower granularity, say,
+  0xfffffffffffff000.
 
 - notrigger
   The EINJ mechanism is a two step process. First inject the error, then
diff --git a/Documentation/acpi/namespace.txt b/Documentation/acpi/namespace.txt
new file mode 100644 (file)
index 0000000..260f6a3
--- /dev/null
@@ -0,0 +1,395 @@
+ACPI Device Tree - Representation of ACPI Namespace
+
+Copyright (C) 2013, Intel Corporation
+Author: Lv Zheng <lv.zheng@intel.com>
+
+
+Abstract:
+
+The Linux ACPI subsystem converts ACPI namespace objects into a Linux
+device tree under the /sys/devices/LNXSYSTEM:00 and updates it upon
+receiving ACPI hotplug notification events.  For each device object in this
+hierarchy there is a corresponding symbolic link in the
+/sys/bus/acpi/devices.
+This document illustrates the structure of the ACPI device tree.
+
+
+Credit:
+
+Thanks for the help from Zhang Rui <rui.zhang@intel.com> and Rafael J.
+Wysocki <rafael.j.wysocki@intel.com>.
+
+
+1. ACPI Definition Blocks
+
+   The ACPI firmware sets up RSDP (Root System Description Pointer) in the
+   system memory address space pointing to the XSDT (Extended System
+   Description Table).  The XSDT always points to the FADT (Fixed ACPI
+   Description Table) using its first entry, the data within the FADT
+   includes various fixed-length entries that describe fixed ACPI features
+   of the hardware.  The FADT contains a pointer to the DSDT
+   (Differentiated System Descripition Table).  The XSDT also contains
+   entries pointing to possibly multiple SSDTs (Secondary System
+   Description Table).
+
+   The DSDT and SSDT data is organized in data structures called definition
+   blocks that contain definitions of various objects, including ACPI
+   control methods, encoded in AML (ACPI Machine Language).  The data block
+   of the DSDT along with the contents of SSDTs represents a hierarchical
+   data structure called the ACPI namespace whose topology reflects the
+   structure of the underlying hardware platform.
+
+   The relationships between ACPI System Definition Tables described above
+   are illustrated in the following diagram.
+
+     +---------+    +-------+    +--------+    +------------------------+
+     |  RSDP   | +->| XSDT  | +->|  FADT  |    |  +-------------------+ |
+     +---------+ |  +-------+ |  +--------+  +-|->|       DSDT        | |
+     | Pointer | |  | Entry |-+  | ...... |  | |  +-------------------+ |
+     +---------+ |  +-------+    | X_DSDT |--+ |  | Definition Blocks | |
+     | Pointer |-+  | ..... |    | ...... |    |  +-------------------+ |
+     +---------+    +-------+    +--------+    |  +-------------------+ |
+                    | Entry |------------------|->|       SSDT        | |
+                    +- - - -+                  |  +-------------------| |
+                    | Entry | - - - - - - - -+ |  | Definition Blocks | |
+                    +- - - -+                | |  +-------------------+ |
+                                             | |  +- - - - - - - - - -+ |
+                                             +-|->|       SSDT        | |
+                                               |  +-------------------+ |
+                                               |  | Definition Blocks | |
+                                               |  +- - - - - - - - - -+ |
+                                               +------------------------+
+                                                           |
+                                              OSPM Loading |
+                                                          \|/
+                                                    +----------------+
+                                                    | ACPI Namespace |
+                                                    +----------------+
+
+                     Figure 1. ACPI Definition Blocks
+
+   NOTE: RSDP can also contain a pointer to the RSDT (Root System
+         Description Table).  Platforms provide RSDT to enable
+         compatibility with ACPI 1.0 operating systems.  The OS is expected
+         to use XSDT, if present.
+
+
+2. Example ACPI Namespace
+
+   All definition blocks are loaded into a single namespace.  The namespace
+   is a hierarchy of objects identified by names and paths.
+   The following naming conventions apply to object names in the ACPI
+   namespace:
+   1. All names are 32 bits long.
+   2. The first byte of a name must be one of 'A' - 'Z', '_'.
+   3. Each of the remaining bytes of a name must be one of 'A' - 'Z', '0'
+      - '9', '_'.
+   4. Names starting with '_' are reserved by the ACPI specification.
+   5. The '\' symbol represents the root of the namespace (i.e. names
+      prepended with '\' are relative to the namespace root).
+   6. The '^' symbol represents the parent of the current namespace node
+      (i.e. names prepended with '^' are relative to the parent of the
+      current namespace node).
+
+   The figure below shows an example ACPI namespace.
+
+   +------+
+   | \    |                     Root
+   +------+
+     |
+     | +------+
+     +-| _PR  |                 Scope(_PR): the processor namespace
+     | +------+
+     |   |
+     |   | +------+
+     |   +-| CPU0 |             Processor(CPU0): the first processor
+     |     +------+
+     |
+     | +------+
+     +-| _SB  |                 Scope(_SB): the system bus namespace
+     | +------+
+     |   |
+     |   | +------+
+     |   +-| LID0 |             Device(LID0); the lid device
+     |   | +------+
+     |   |   |
+     |   |   | +------+
+     |   |   +-| _HID |         Name(_HID, "PNP0C0D"): the hardware ID
+     |   |   | +------+
+     |   |   |
+     |   |   | +------+
+     |   |   +-| _STA |         Method(_STA): the status control method
+     |   |     +------+
+     |   |
+     |   | +------+
+     |   +-| PCI0 |             Device(PCI0); the PCI root bridge
+     |     +------+
+     |       |
+     |       | +------+
+     |       +-| _HID |         Name(_HID, "PNP0A08"): the hardware ID
+     |       | +------+
+     |       |
+     |       | +------+
+     |       +-| _CID |         Name(_CID, "PNP0A03"): the compatible ID
+     |       | +------+
+     |       |
+     |       | +------+
+     |       +-| RP03 |         Scope(RP03): the PCI0 power scope
+     |       | +------+
+     |       |   |
+     |       |   | +------+
+     |       |   +-| PXP3 |     PowerResource(PXP3): the PCI0 power resource
+     |       |     +------+
+     |       |
+     |       | +------+
+     |       +-| GFX0 |         Device(GFX0): the graphics adapter
+     |         +------+
+     |           |
+     |           | +------+
+     |           +-| _ADR |     Name(_ADR, 0x00020000): the PCI bus address
+     |           | +------+
+     |           |
+     |           | +------+
+     |           +-| DD01 |     Device(DD01): the LCD output device
+     |             +------+
+     |               |
+     |               | +------+
+     |               +-| _BCL | Method(_BCL): the backlight control method
+     |                 +------+
+     |
+     | +------+
+     +-| _TZ  |                 Scope(_TZ): the thermal zone namespace
+     | +------+
+     |   |
+     |   | +------+
+     |   +-| FN00 |             PowerResource(FN00): the FAN0 power resource
+     |   | +------+
+     |   |
+     |   | +------+
+     |   +-| FAN0 |             Device(FAN0): the FAN0 cooling device
+     |   | +------+
+     |   |   |
+     |   |   | +------+
+     |   |   +-| _HID |         Name(_HID, "PNP0A0B"): the hardware ID
+     |   |     +------+
+     |   |
+     |   | +------+
+     |   +-| TZ00 |             ThermalZone(TZ00); the FAN thermal zone
+     |     +------+
+     |
+     | +------+
+     +-| _GPE |                 Scope(_GPE): the GPE namespace
+       +------+
+
+                     Figure 2. Example ACPI Namespace
+
+
+3. Linux ACPI Device Objects
+
+   The Linux kernel's core ACPI subsystem creates struct acpi_device
+   objects for ACPI namespace objects representing devices, power resources
+   processors, thermal zones.  Those objects are exported to user space via
+   sysfs as directories in the subtree under /sys/devices/LNXSYSTM:00.  The
+   format of their names is <bus_id:instance>, where 'bus_id' refers to the
+   ACPI namespace representation of the given object and 'instance' is used
+   for distinguishing different object of the same 'bus_id' (it is
+   two-digit decimal representation of an unsigned integer).
+
+   The value of 'bus_id' depends on the type of the object whose name it is
+   part of as listed in the table below.
+
+                +---+-----------------+-------+----------+
+                |   | Object/Feature  | Table | bus_id   |
+                +---+-----------------+-------+----------+
+                | N | Root            | xSDT  | LNXSYSTM |
+                +---+-----------------+-------+----------+
+                | N | Device          | xSDT  | _HID     |
+                +---+-----------------+-------+----------+
+                | N | Processor       | xSDT  | LNXCPU   |
+                +---+-----------------+-------+----------+
+                | N | ThermalZone     | xSDT  | LNXTHERM |
+                +---+-----------------+-------+----------+
+                | N | PowerResource   | xSDT  | LNXPOWER |
+                +---+-----------------+-------+----------+
+                | N | Other Devices   | xSDT  | device   |
+                +---+-----------------+-------+----------+
+                | F | PWR_BUTTON      | FADT  | LNXPWRBN |
+                +---+-----------------+-------+----------+
+                | F | SLP_BUTTON      | FADT  | LNXSLPBN |
+                +---+-----------------+-------+----------+
+                | M | Video Extension | xSDT  | LNXVIDEO |
+                +---+-----------------+-------+----------+
+                | M | ATA Controller  | xSDT  | LNXIOBAY |
+                +---+-----------------+-------+----------+
+                | M | Docking Station | xSDT  | LNXDOCK  |
+                +---+-----------------+-------+----------+
+
+                 Table 1. ACPI Namespace Objects Mapping
+
+   The following rules apply when creating struct acpi_device objects on
+   the basis of the contents of ACPI System Description Tables (as
+   indicated by the letter in the first column and the notation in the
+   second column of the table above):
+   N:
+      The object's source is an ACPI namespace node (as indicated by the
+      named object's type in the second column).  In that case the object's
+      directory in sysfs will contain the 'path' attribute whose value is
+      the full path to the node from the namespace root.
+      struct acpi_device objects are created for the ACPI namespace nodes
+      whose _STA control methods return PRESENT or FUNCTIONING.  The power
+      resource nodes or nodes without _STA are assumed to be both PRESENT
+      and FUNCTIONING.
+   F:
+      The struct acpi_device object is created for a fixed hardware
+      feature (as indicated by the fixed feature flag's name in the second
+      column), so its sysfs directory will not contain the 'path'
+      attribute.
+   M:
+      The struct acpi_device object is created for an ACPI namespace node
+      with specific control methods (as indicated by the ACPI defined
+      device's type in the second column).  The 'path' attribute containing
+      its namespace path will be present in its sysfs directory.  For
+      example, if the _BCL method is present for an ACPI namespace node, a
+      struct acpi_device object with LNXVIDEO 'bus_id' will be created for
+      it.
+
+   The third column of the above table indicates which ACPI System
+   Description Tables contain information used for the creation of the
+   struct acpi_device objects represented by the given row (xSDT means DSDT
+   or SSDT).
+
+   The forth column of the above table indicates the 'bus_id' generation
+   rule of the struct acpi_device object:
+   _HID:
+      _HID in the last column of the table means that the object's bus_id
+      is derived from the _HID/_CID identification objects present under
+      the corresponding ACPI namespace node. The object's sysfs directory
+      will then contain the 'hid' and 'modalias' attributes that can be
+      used to retrieve the _HID and _CIDs of that object.
+   LNXxxxxx:
+      The 'modalias' attribute is also present for struct acpi_device
+      objects having bus_id of the "LNXxxxxx" form (pseudo devices), in
+      which cases it contains the bus_id string itself.
+   device:
+      'device' in the last column of the table indicates that the object's
+      bus_id cannot be determined from _HID/_CID of the corresponding
+      ACPI namespace node, although that object represents a device (for
+      example, it may be a PCI device with _ADR defined and without _HID
+      or _CID).  In that case the string 'device' will be used as the
+      object's bus_id.
+
+
+4. Linux ACPI Physical Device Glue
+
+   ACPI device (i.e. struct acpi_device) objects may be linked to other
+   objects in the Linux' device hierarchy that represent "physical" devices
+   (for example, devices on the PCI bus).  If that happens, it means that
+   the ACPI device object is a "companion" of a device otherwise
+   represented in a different way and is used (1) to provide configuration
+   information on that device which cannot be obtained by other means and
+   (2) to do specific things to the device with the help of its ACPI
+   control methods.  One ACPI device object may be linked this way to
+   multiple "physical" devices.
+
+   If an ACPI device object is linked to a "physical" device, its sysfs
+   directory contains the "physical_node" symbolic link to the sysfs
+   directory of the target device object.  In turn, the target device's
+   sysfs directory will then contain the "firmware_node" symbolic link to
+   the sysfs directory of the companion ACPI device object.
+   The linking mechanism relies on device identification provided by the
+   ACPI namespace.  For example, if there's an ACPI namespace object
+   representing a PCI device (i.e. a device object under an ACPI namespace
+   object representing a PCI bridge) whose _ADR returns 0x00020000 and the
+   bus number of the parent PCI bridge is 0, the sysfs directory
+   representing the struct acpi_device object created for that ACPI
+   namespace object will contain the 'physical_node' symbolic link to the
+   /sys/devices/pci0000:00/0000:00:02:0/ sysfs directory of the
+   corresponding PCI device.
+
+   The linking mechanism is generally bus-specific.  The core of its
+   implementation is located in the drivers/acpi/glue.c file, but there are
+   complementary parts depending on the bus types in question located
+   elsewhere.  For example, the PCI-specific part of it is located in
+   drivers/pci/pci-acpi.c.
+
+
+5. Example Linux ACPI Device Tree
+
+   The sysfs hierarchy of struct acpi_device objects corresponding to the
+   example ACPI namespace illustrated in Figure 2 with the addition of
+   fixed PWR_BUTTON/SLP_BUTTON devices is shown below.
+
+   +--------------+---+-----------------+
+   | LNXSYSTEM:00 | \ | acpi:LNXSYSTEM: |
+   +--------------+---+-----------------+
+     |
+     | +-------------+-----+----------------+
+     +-| LNXPWRBN:00 | N/A | acpi:LNXPWRBN: |
+     | +-------------+-----+----------------+
+     |
+     | +-------------+-----+----------------+
+     +-| LNXSLPBN:00 | N/A | acpi:LNXSLPBN: |
+     | +-------------+-----+----------------+
+     |
+     | +-----------+------------+--------------+
+     +-| LNXCPU:00 | \_PR_.CPU0 | acpi:LNXCPU: |
+     | +-----------+------------+--------------+
+     |
+     | +-------------+-------+----------------+
+     +-| LNXSYBUS:00 | \_SB_ | acpi:LNXSYBUS: |
+     | +-------------+-------+----------------+
+     |   |
+     |   | +- - - - - - - +- - - - - - +- - - - - - - -+
+     |   +-| * PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: |
+     |   | +- - - - - - - +- - - - - - +- - - - - - - -+
+     |   |
+     |   | +------------+------------+-----------------------+
+     |   +-| PNP0A08:00 | \_SB_.PCI0 | acpi:PNP0A08:PNP0A03: |
+     |     +------------+------------+-----------------------+
+     |       |
+     |       | +-----------+-----------------+-----+
+     |       +-| device:00 | \_SB_.PCI0.RP03 | N/A |
+     |       | +-----------+-----------------+-----+
+     |       |   |
+     |       |   | +-------------+----------------------+----------------+
+     |       |   +-| LNXPOWER:00 | \_SB_.PCI0.RP03.PXP3 | acpi:LNXPOWER: |
+     |       |     +-------------+----------------------+----------------+
+     |       |
+     |       | +-------------+-----------------+----------------+
+     |       +-| LNXVIDEO:00 | \_SB_.PCI0.GFX0 | acpi:LNXVIDEO: |
+     |         +-------------+-----------------+----------------+
+     |           |
+     |           | +-----------+-----------------+-----+
+     |           +-| device:01 | \_SB_.PCI0.DD01 | N/A |
+     |             +-----------+-----------------+-----+
+     |
+     | +-------------+-------+----------------+
+     +-| LNXSYBUS:01 | \_TZ_ | acpi:LNXSYBUS: |
+       +-------------+-------+----------------+
+         |
+         | +-------------+------------+----------------+
+         +-| LNXPOWER:0a | \_TZ_.FN00 | acpi:LNXPOWER: |
+         | +-------------+------------+----------------+
+         |
+         | +------------+------------+---------------+
+         +-| PNP0C0B:00 | \_TZ_.FAN0 | acpi:PNP0C0B: |
+         | +------------+------------+---------------+
+         |
+         | +-------------+------------+----------------+
+         +-| LNXTHERM:00 | \_TZ_.TZ00 | acpi:LNXTHERM: |
+           +-------------+------------+----------------+
+
+                  Figure 3. Example Linux ACPI Device Tree
+
+   NOTE: Each node is represented as "object/path/modalias", where:
+         1. 'object' is the name of the object's directory in sysfs.
+         2. 'path' is the ACPI namespace path of the corresponding
+            ACPI namespace object, as returned by the object's 'path'
+            sysfs attribute.
+         3. 'modalias' is the value of the object's 'modalias' sysfs
+            attribute (as described earlier in this document).
+   NOTE: N/A indicates the device object does not have the 'path' or the
+         'modalias' attribute.
+   NOTE: The PNP0C0D device listed above is highlighted (marked by "*")
+         to indicate it will be created only when its _STA methods return
+         PRESENT or FUNCTIONING.
diff --git a/Documentation/acpi/video_extension.txt b/Documentation/acpi/video_extension.txt
new file mode 100644 (file)
index 0000000..78b32ac
--- /dev/null
@@ -0,0 +1,106 @@
+ACPI video extensions
+~~~~~~~~~~~~~~~~~~~~~
+
+This driver implement the ACPI Extensions For Display Adapters for
+integrated graphics devices on motherboard, as specified in ACPI 2.0
+Specification, Appendix B, allowing to perform some basic control like
+defining the video POST device, retrieving EDID information or to
+setup a video output, etc.  Note that this is an ref. implementation
+only.  It may or may not work for your integrated video device.
+
+The ACPI video driver does 3 things regarding backlight control:
+
+1 Export a sysfs interface for user space to control backlight level
+
+If the ACPI table has a video device, and acpi_backlight=vendor kernel
+command line is not present, the driver will register a backlight device
+and set the required backlight operation structure for it for the sysfs
+interface control. For every registered class device, there will be a
+directory named acpi_videoX under /sys/class/backlight.
+
+The backlight sysfs interface has a standard definition here:
+Documentation/ABI/stable/sysfs-class-backlight.
+
+And what ACPI video driver does is:
+actual_brightness: on read, control method _BQC will be evaluated to
+get the brightness level the firmware thinks it is at;
+bl_power: not implemented, will set the current brightness instead;
+brightness: on write, control method _BCM will run to set the requested
+brightness level;
+max_brightness: Derived from the _BCL package(see below);
+type: firmware
+
+Note that ACPI video backlight driver will always use index for
+brightness, actual_brightness and max_brightness. So if we have
+the following _BCL package:
+
+Method (_BCL, 0, NotSerialized)
+{
+       Return (Package (0x0C)
+       {
+               0x64,
+               0x32,
+               0x0A,
+               0x14,
+               0x1E,
+               0x28,
+               0x32,
+               0x3C,
+               0x46,
+               0x50,
+               0x5A,
+               0x64
+       })
+}
+
+The first two levels are for when laptop are on AC or on battery and are
+not used by Linux currently. The remaining 10 levels are supported levels
+that we can choose from. The applicable index values are from 0 (that
+corresponds to the 0x0A brightness value) to 9 (that corresponds to the
+0x64 brightness value) inclusive. Each of those index values is regarded
+as a "brightness level" indicator. Thus from the user space perspective
+the range of available brightness levels is from 0 to 9 (max_brightness)
+inclusive.
+
+2 Notify user space about hotkey event
+
+There are generally two cases for hotkey event reporting:
+i) For some laptops, when user presses the hotkey, a scancode will be
+   generated and sent to user space through the input device created by
+   the keyboard driver as a key type input event, with proper remap, the
+   following key code will appear to user space:
+
+       EV_KEY, KEY_BRIGHTNESSUP
+       EV_KEY, KEY_BRIGHTNESSDOWN
+       etc.
+
+For this case, ACPI video driver does not need to do anything(actually,
+it doesn't even know this happened).
+
+ii) For some laptops, the press of the hotkey will not generate the
+    scancode, instead, firmware will notify the video device ACPI node
+    about the event. The event value is defined in the ACPI spec. ACPI
+    video driver will generate an key type input event according to the
+    notify value it received and send the event to user space through the
+    input device it created:
+
+       event           keycode
+       0x86            KEY_BRIGHTNESSUP
+       0x87            KEY_BRIGHTNESSDOWN
+       etc.
+
+so this would lead to the same effect as case i) now.
+
+Once user space tool receives this event, it can modify the backlight
+level through the sysfs interface.
+
+3 Change backlight level in the kernel
+
+This works for machines covered by case ii) in Section 2. Once the driver
+received a notification, it will set the backlight level accordingly. This does
+not affect the sending of event to user space, they are always sent to user
+space regardless of whether or not the video module controls the backlight level
+directly. This behaviour can be controlled through the brightness_switch_enabled
+module parameter as documented in kernel-parameters.txt. It is recommended to
+disable this behaviour once a GUI environment starts up and wants to have full
+control of the backlight level.
index 5f583af0a6e184cc568b492e7853b282b8a4b4e3..78a377124ef04ec1f25fa4f47a5d065f449fe221 100644 (file)
@@ -73,3 +73,10 @@ Translation table lookup with 64KB pages:
  |                 |    +--------------------------> [41:29] L2 index (only 38:29 used)
  |                 +-------------------------------> [47:42] L1 index (not used)
  +-------------------------------------------------> [63] TTBR0/1
+
+When using KVM, the hypervisor maps kernel pages in EL2, at a fixed
+offset from the kernel VA (top 24bits of the kernel VA set to zero):
+
+Start                  End                     Size            Use
+-----------------------------------------------------------------------
+0000004000000000       0000007fffffffff         256GB          kernel objects mapped in HYP
index 12e01d432bfef479bd690e81cf0339421e47b87d..7740038d82bcb5669ab946ab6fa580b4920d0041 100644 (file)
@@ -373,7 +373,7 @@ can become very uneven.
 1.7 What is sched_load_balance ?
 --------------------------------
 
-The kernel scheduler (kernel/sched.c) automatically load balances
+The kernel scheduler (kernel/sched/core.c) automatically load balances
 tasks.  If one CPU is underutilized, kernel code running on that
 CPU will look for tasks on other more overloaded CPUs and move those
 tasks to itself, within the constraints of such placement mechanisms
index ddf4f93967a94e1385d378ac257f5e919da77cfb..327acec6f90b4a30adca8dca396f48d8c4d87aca 100644 (file)
@@ -834,10 +834,9 @@ Test:
 
 12. TODO
 
-1. Add support for accounting huge pages (as a separate controller)
-2. Make per-cgroup scanner reclaim not-shared pages first
-3. Teach controller to account for shared-pages
-4. Start reclamation in the background when the limit is
+1. Make per-cgroup scanner reclaim not-shared pages first
+2. Teach controller to account for shared-pages
+3. Start reclamation in the background when the limit is
    not yet hit but the usage is getting closer
 
 Summary
index a3585eac83b605cfdf5f07b15930d77e62eef5d8..19fa98e07bf7fe79f403042d14858677f4474839 100644 (file)
@@ -186,7 +186,7 @@ As most cpufreq processors only allow for being set to a few specific
 frequencies, a "frequency table" with some functions might assist in
 some work of the processor driver. Such a "frequency table" consists
 of an array of struct cpufreq_frequency_table entries, with any value in
-"index" you want to use, and the corresponding frequency in
+"driver_data" you want to use, and the corresponding frequency in
 "frequency". At the end of the table, you need to add a
 cpufreq_frequency_table entry with frequency set to CPUFREQ_TABLE_END. And
 if you want to skip one entry in the table, set the frequency to 
@@ -214,10 +214,4 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
 is the corresponding frequency table helper for the ->target
 stage. Just pass the values to this function, and the unsigned int
 index returns the number of the frequency table entry which contains
-the frequency the CPU shall be set to. PLEASE NOTE: This is not the
-"index" which is in this cpufreq_table_entry.index, but instead
-cpufreq_table[index]. So, the new frequency is
-cpufreq_table[index].frequency, and the value you stored into the
-frequency table "index" field is
-cpufreq_table[index].index.
-
+the frequency the CPU shall be set to.
index 0efd1b905b9dd8f909e9e7bd184af4e66cd1e0f5..edd4b4df393202ac99b27269966b0ab15c44fff0 100644 (file)
@@ -370,8 +370,10 @@ A: There is no clear spec defined way from ACPI that can give us that
    CPUs in MADT as hotpluggable CPUS.  In the case there are no disabled CPUS
    we assume 1/2 the number of CPUs currently present can be hotplugged.
 
-   Caveat: Today's ACPI MADT can only provide 256 entries since the apicid field
-   in MADT is only 8 bits.
+   Caveat: ACPI MADT can only provide 256 entries in systems with only ACPI 2.0c
+   or earlier ACPI version supported, because the apicid field in MADT is only
+   8 bits. From ACPI 3.0, this limitation was removed since the apicid field
+   was extended to 32 bits with x2APIC introduced.
 
 User Space Notification
 
index ba046b8fa92fb4a34a360fe54e6b997c019feb43..7bf1be20d93a4555d55e19c2992904011413f9ee 100644 (file)
@@ -222,5 +222,4 @@ drivers/dma/: location for offload engine drivers
 include/linux/async_tx.h: core header file for the async_tx api
 crypto/async_tx/async_tx.c: async_tx interface to dmaengine and common code
 crypto/async_tx/async_memcpy.c: copy offload
-crypto/async_tx/async_memset.c: memory fill offload
 crypto/async_tx/async_xor.c: xor and xor zero sum offload
index b9015912bca6bb6ea7a73ef4dc2a94f189346385..23721d3be3e6160e2057b0b11ef002e2828f458f 100644 (file)
@@ -100,8 +100,7 @@ Your cooperation is appreciated.
                 10 = /dev/aio          Asynchronous I/O notification interface
                 11 = /dev/kmsg         Writes to this come out as printk's, reads
                                        export the buffered printk records.
-                12 = /dev/oldmem       Used by crashdump kernels to access
-                                       the memory of the kernel that crashed.
+                12 = /dev/oldmem       OBSOLETE - replaced by /proc/vmcore
 
   1 block      RAM disk
                  0 = /dev/ram0         First RAM disk
index cbef09b5c8a71672924360e028176488f03f2faa..69ddf9fad2dcccc36bbaa330b96170d2eb9b213d 100644 (file)
@@ -16,6 +16,9 @@ Required properties:
      performs the same operation).
        "marvell,"aurora-outer-cache: Marvell Controller designed to be
         compatible with the ARM one with outer cache mode.
+       "bcm,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
 - 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
index b519f9b699c30eec22d99b7398691b3b80c4c7a3..3ec0c5c4f0e91da8b520de71996fa6637de05705 100644 (file)
@@ -12,6 +12,11 @@ Optional properties:
 - calxeda,port-phys: phandle-combophy and lane assignment, which maps each
                        SATA port to a combophy and a lane within that
                        combophy
+- calxeda,sgpio-gpio: phandle-gpio bank, bit offset, and default on or off,
+                       which indicates that the driver supports SGPIO
+                       indicator lights using the indicated GPIOs
+- calxeda,led-order : a u32 array that map port numbers to offsets within the
+                       SGPIO bitstream.
 - dma-coherent      : Present if dma operations are coherent
 
 Example:
diff --git a/Documentation/devicetree/bindings/clock/nspire-clock.txt b/Documentation/devicetree/bindings/clock/nspire-clock.txt
new file mode 100644 (file)
index 0000000..7c3bc8b
--- /dev/null
@@ -0,0 +1,24 @@
+TI-NSPIRE Clocks
+
+Required properties:
+- compatible: Valid compatible properties include:
+       "lsi,nspire-cx-ahb-divider" for the AHB divider in the CX model
+       "lsi,nspire-classic-ahb-divider" for the AHB divider in the older model
+       "lsi,nspire-cx-clock" for the base clock in the CX model
+       "lsi,nspire-classic-clock" for the base clock in the older model
+
+- reg: Physical base address of the controller and length of memory mapped
+       region.
+
+Optional:
+- clocks: For the "nspire-*-ahb-divider" compatible clocks, this is the parent
+       clock where it divides the rate from.
+
+Example:
+
+ahb_clk {
+       #clock-cells = <0>;
+       compatible = "lsi,nspire-cx-clock";
+       reg = <0x900B0000 0x4>;
+       clocks = <&base_clk>;
+};
diff --git a/Documentation/devicetree/bindings/clock/rockchip.txt b/Documentation/devicetree/bindings/clock/rockchip.txt
new file mode 100644 (file)
index 0000000..a891c82
--- /dev/null
@@ -0,0 +1,74 @@
+Device Tree Clock bindings for arch-rockchip
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+== Gate clocks ==
+
+The gate registers form a continuos block which makes the dt node
+structure a matter of taste, as either all gates can be put into
+one gate clock spanning all registers or they can be divided into
+the 10 individual gates containing 16 clocks each.
+The code supports both approaches.
+
+Required properties:
+- compatible : "rockchip,rk2928-gate-clk"
+- reg : shall be the control register address(es) for the clock.
+- #clock-cells : from common clock binding; shall be set to 1
+- clock-output-names : the corresponding gate names that the clock controls
+- clocks : should contain the parent clock for each individual gate,
+  therefore the number of clocks elements should match the number of
+  clock-output-names
+
+Example using multiple gate clocks:
+
+               clk_gates0: gate-clk@200000d0 {
+                       compatible = "rockchip,rk2928-gate-clk";
+                       reg = <0x200000d0 0x4>;
+                       clocks = <&dummy>, <&dummy>,
+                                <&dummy>, <&dummy>,
+                                <&dummy>, <&dummy>,
+                                <&dummy>, <&dummy>,
+                                <&dummy>, <&dummy>,
+                                <&dummy>, <&dummy>,
+                                <&dummy>, <&dummy>,
+                                <&dummy>, <&dummy>;
+
+                       clock-output-names =
+                               "gate_core_periph", "gate_cpu_gpll",
+                               "gate_ddrphy", "gate_aclk_cpu",
+                               "gate_hclk_cpu", "gate_pclk_cpu",
+                               "gate_atclk_cpu", "gate_i2s0",
+                               "gate_i2s0_frac", "gate_i2s1",
+                               "gate_i2s1_frac", "gate_i2s2",
+                               "gate_i2s2_frac", "gate_spdif",
+                               "gate_spdif_frac", "gate_testclk";
+
+                       #clock-cells = <1>;
+               };
+
+               clk_gates1: gate-clk@200000d4 {
+                       compatible = "rockchip,rk2928-gate-clk";
+                       reg = <0x200000d4 0x4>;
+                       clocks = <&xin24m>, <&xin24m>,
+                                <&xin24m>, <&dummy>,
+                                <&dummy>, <&xin24m>,
+                                <&xin24m>, <&dummy>,
+                                <&xin24m>, <&dummy>,
+                                <&xin24m>, <&dummy>,
+                                <&xin24m>, <&dummy>,
+                                <&xin24m>, <&dummy>;
+
+                       clock-output-names =
+                               "gate_timer0", "gate_timer1",
+                               "gate_timer2", "gate_jtag",
+                               "gate_aclk_lcdc1_src", "gate_otgphy0",
+                               "gate_otgphy1", "gate_ddr_gpll",
+                               "gate_uart0", "gate_frac_uart0",
+                               "gate_uart1", "gate_frac_uart1",
+                               "gate_uart2", "gate_frac_uart2",
+                               "gate_uart3", "gate_frac_uart3";
+
+                       #clock-cells = <1>;
+               };
index cc374651662c6aa9456e96698ceac4d0e50d988c..66c75b2d61587f7bdd888a999545c5f9adc482aa 100644 (file)
@@ -44,6 +44,11 @@ Optional child node properties:
 - silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth
   divider.
 - silabs,pll-master: boolean, multisynth can change pll frequency.
+- silabs,disable-state : clock output disable state, shall be
+  0 = clock output is driven LOW when disabled
+  1 = clock output is driven HIGH when disabled
+  2 = clock output is FLOATING (HIGH-Z) when disabled
+  3 = clock output is NEVER disabled
 
 ==Example==
 
index 729f52426fe1b16c969ea36a767db802e6a03f99..d495521a79d2c1fa028c43f50b77dd7423388432 100644 (file)
@@ -12,22 +12,30 @@ Required properties:
        "allwinner,sun4i-axi-clk" - for the AXI clock
        "allwinner,sun4i-axi-gates-clk" - for the AXI gates
        "allwinner,sun4i-ahb-clk" - for the AHB clock
-       "allwinner,sun4i-ahb-gates-clk" - for the AHB gates
+       "allwinner,sun4i-ahb-gates-clk" - for the AHB gates on A10
+       "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
        "allwinner,sun4i-apb0-clk" - for the APB0 clock
-       "allwinner,sun4i-apb0-gates-clk" - for the APB0 gates
+       "allwinner,sun4i-apb0-gates-clk" - for the APB0 gates on A10
+       "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
        "allwinner,sun4i-apb1-clk" - for the APB1 clock
        "allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing
-       "allwinner,sun4i-apb1-gates-clk" - for the APB1 gates
+       "allwinner,sun4i-apb1-gates-clk" - for the APB1 gates on A10
+       "allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13
 
 Required properties for all clocks:
 - reg : shall be the control register address for the clock.
 - clocks : shall be the input parent clock(s) phandle for the clock
 - #clock-cells : from common clock binding; shall be set to 0 except for
-       "allwinner,sun4i-*-gates-clk" where it shall be set to 1
+       "allwinner,*-gates-clk" where it shall be set to 1
 
-Additionally, "allwinner,sun4i-*-gates-clk" clocks require:
+Additionally, "allwinner,*-gates-clk" clocks require:
 - clock-output-names : the corresponding gate names that the clock controls
 
+Clock consumers should specify the desired clocks they use with a
+"clocks" phandle cell. Consumers that are using a gated clock should
+provide an additional ID in their clock property. The values of this
+ID are documented in sunxi/<soc>-gates.txt.
+
 For example:
 
 osc24M: osc24M@01c20050 {
@@ -50,102 +58,3 @@ cpu: cpu@01c20054 {
        reg = <0x01c20054 0x4>;
        clocks = <&osc32k>, <&osc24M>, <&pll1>;
 };
-
-
-
-Gate clock outputs
-
-The "allwinner,sun4i-*-gates-clk" clocks provide several gatable outputs;
-their corresponding offsets as present on sun4i are listed below. Note that
-some of these gates are not present on sun5i.
-
-  * AXI gates ("allwinner,sun4i-axi-gates-clk")
-
-    DRAM                                                                0
-
-  * AHB gates ("allwinner,sun4i-ahb-gates-clk")
-
-    USB0                                                                0
-    EHCI0                                                               1
-    OHCI0                                                               2*
-    EHCI1                                                               3
-    OHCI1                                                               4*
-    SS                                                                  5
-    DMA                                                                 6
-    BIST                                                                7
-    MMC0                                                                8
-    MMC1                                                                9
-    MMC2                                                                10
-    MMC3                                                                11
-    MS                                                                  12**
-    NAND                                                                13
-    SDRAM                                                               14
-
-    ACE                                                                 16
-    EMAC                                                                17
-    TS                                                                  18
-
-    SPI0                                                                20
-    SPI1                                                                21
-    SPI2                                                                22
-    SPI3                                                                23
-    PATA                                                                24
-    SATA                                                                25**
-    GPS                                                                 26*
-
-    VE                                                                  32
-    TVD                                                                 33
-    TVE0                                                                34
-    TVE1                                                                35
-    LCD0                                                                36
-    LCD1                                                                37
-
-    CSI0                                                                40
-    CSI1                                                                41
-
-    HDMI                                                                43
-    DE_BE0                                                              44
-    DE_BE1                                                              45
-    DE_FE0                                                              46
-    DE_FE1                                                              47
-
-    MP                                                                  50
-
-    MALI400                                                             52
-
-  * APB0 gates ("allwinner,sun4i-apb0-gates-clk")
-
-    CODEC                                                               0
-    SPDIF                                                               1*
-    AC97                                                                2
-    IIS                                                                 3
-
-    PIO                                                                 5
-    IR0                                                                 6
-    IR1                                                                 7
-
-    KEYPAD                                                              10
-
-  * APB1 gates ("allwinner,sun4i-apb1-gates-clk")
-
-    I2C0                                                                0
-    I2C1                                                                1
-    I2C2                                                                2
-
-    CAN                                                                 4
-    SCR                                                                 5
-    PS20                                                                6
-    PS21                                                                7
-
-    UART0                                                               16
-    UART1                                                               17
-    UART2                                                               18
-    UART3                                                               19
-    UART4                                                               20
-    UART5                                                               21
-    UART6                                                               22
-    UART7                                                               23
-
-Notation:
- [*]:  The datasheet didn't mention these, but they are present on AW code
- [**]: The datasheet had this marked as "NC" but they are used on AW code
diff --git a/Documentation/devicetree/bindings/clock/sunxi/sun4i-a10-gates.txt b/Documentation/devicetree/bindings/clock/sunxi/sun4i-a10-gates.txt
new file mode 100644 (file)
index 0000000..6a03475
--- /dev/null
@@ -0,0 +1,93 @@
+Gate clock outputs
+------------------
+
+  * AXI gates ("allwinner,sun4i-axi-gates-clk")
+
+    DRAM                                       0
+
+  * AHB gates ("allwinner,sun4i-ahb-gates-clk")
+
+    USB0                                       0
+    EHCI0                                      1
+    OHCI0                                      2*
+    EHCI1                                      3
+    OHCI1                                      4*
+    SS                                         5
+    DMA                                                6
+    BIST                                       7
+    MMC0                                       8
+    MMC1                                       9
+    MMC2                                       10
+    MMC3                                       11
+    MS                                         12**
+    NAND                                       13
+    SDRAM                                      14
+
+    ACE                                                16
+    EMAC                                       17
+    TS                                         18
+
+    SPI0                                       20
+    SPI1                                       21
+    SPI2                                       22
+    SPI3                                       23
+    PATA                                       24
+    SATA                                       25**
+    GPS                                                26*
+
+    VE                                         32
+    TVD                                                33
+    TVE0                                       34
+    TVE1                                       35
+    LCD0                                       36
+    LCD1                                       37
+
+    CSI0                                       40
+    CSI1                                       41
+
+    HDMI                                       43
+    DE_BE0                                     44
+    DE_BE1                                     45
+    DE_FE1                                     46
+    DE_FE1                                     47
+
+    MP                                         50
+
+    MALI400                                    52
+
+  * APB0 gates ("allwinner,sun4i-apb0-gates-clk")
+
+    CODEC                                      0
+    SPDIF                                      1*
+    AC97                                       2
+    IIS                                                3
+
+    PIO                                                5
+    IR0                                                6
+    IR1                                                7
+
+    KEYPAD                                     10
+
+  * APB1 gates ("allwinner,sun4i-apb1-gates-clk")
+
+    I2C0                                       0
+    I2C1                                       1
+    I2C2                                       2
+
+    CAN                                                4
+    SCR                                                5
+    PS20                                       6
+    PS21                                       7
+
+    UART0                                      16
+    UART1                                      17
+    UART2                                      18
+    UART3                                      19
+    UART4                                      20
+    UART5                                      21
+    UART6                                      22
+    UART7                                      23
+
+Notation:
+ [*]:  The datasheet didn't mention these, but they are present on AW code
+ [**]: The datasheet had this marked as "NC" but they are used on AW code
diff --git a/Documentation/devicetree/bindings/clock/sunxi/sun5i-a13-gates.txt b/Documentation/devicetree/bindings/clock/sunxi/sun5i-a13-gates.txt
new file mode 100644 (file)
index 0000000..006b6df
--- /dev/null
@@ -0,0 +1,58 @@
+Gate clock outputs
+------------------
+
+  * AXI gates ("allwinner,sun4i-axi-gates-clk")
+
+    DRAM                                       0
+
+  * AHB gates ("allwinner,sun5i-a13-ahb-gates-clk")
+
+    USBOTG                                     0
+    EHCI                                       1
+    OHCI                                       2
+
+    SS                                         5
+    DMA                                                6
+    BIST                                       7
+    MMC0                                       8
+    MMC1                                       9
+    MMC2                                       10
+
+    NAND                                       13
+    SDRAM                                      14
+
+    SPI0                                       20
+    SPI1                                       21
+    SPI2                                       22
+
+    STIMER                                     28
+
+    VE                                         32
+
+    LCD                                                36
+
+    CSI                                                40
+
+    DE_BE                                      44
+
+    DE_FE                                      46
+
+    IEP                                                51
+    MALI400                                    52
+
+  * APB0 gates ("allwinner,sun5i-a13-apb0-gates-clk")
+
+    CODEC                                      0
+
+    PIO                                                5
+    IR                                         6
+
+  * APB1 gates ("allwinner,sun5i-a13-apb1-gates-clk")
+
+    I2C0                                       0
+    I2C1                                       1
+    I2C2                                       2
+
+    UART1                                      17
+
+    UART3                                      19
index a880c70d0047091ab224c98422fb1a34b9f25cdb..91d71cc0314ad7b5cfb468c311e38aaab2bd40e9 100644 (file)
@@ -8,6 +8,8 @@ Required properties:
 - compatible : shall be one of the following:
        "via,vt8500-pll-clock" - for a VT8500/WM8505 PLL clock
        "wm,wm8650-pll-clock" - for a WM8650 PLL clock
+       "wm,wm8750-pll-clock" - for a WM8750 PLL clock
+       "wm,wm8850-pll-clock" - for a WM8850 PLL clock
        "via,vt8500-device-clock" - for a VT/WM device clock
 
 Required properties for PLL clocks:
diff --git a/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt b/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
new file mode 100644 (file)
index 0000000..63bf4be
--- /dev/null
@@ -0,0 +1,48 @@
+Xilinx plb/axi GPIO controller
+
+Dual channel GPIO controller with configurable number of pins
+(from 1 to 32 per channel). Every pin can be configured as
+input/output/tristate. Both channels share the same global IRQ but
+local interrupts can be enabled on channel basis.
+
+Required properties:
+- compatible : Should be "xlnx,xps-gpio-1.00.a"
+- reg : Address and length of the register set for the device
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters (currently unused).
+- gpio-controller : Marks the device node as a GPIO controller.
+
+Optional properties:
+- interrupts : Interrupt mapping for GPIO IRQ.
+- interrupt-parent : Phandle for the interrupt controller that
+  services interrupts for this device.
+- xlnx,all-inputs : if n-th bit is setup, GPIO-n is input
+- xlnx,dout-default : if n-th bit is 1, GPIO-n default value is 1
+- xlnx,gpio-width : gpio width
+- xlnx,tri-default : if n-th bit is 1, GPIO-n is in tristate mode
+- xlnx,is-dual : if 1, controller also uses the second channel
+- xlnx,all-inputs-2 : as above but for the second channel
+- xlnx,dout-default-2 : as above but the second channel
+- xlnx,gpio2-width : as above but for the second channel
+- xlnx,tri-default-2 : as above but for the second channel
+
+
+Example:
+gpio: gpio@40000000 {
+       #gpio-cells = <2>;
+       compatible = "xlnx,xps-gpio-1.00.a";
+       gpio-controller ;
+       interrupt-parent = <&microblaze_0_intc>;
+       interrupts = < 6 2 >;
+       reg = < 0x40000000 0x10000 >;
+       xlnx,all-inputs = <0x0>;
+       xlnx,all-inputs-2 = <0x0>;
+       xlnx,dout-default = <0x0>;
+       xlnx,dout-default-2 = <0x0>;
+       xlnx,gpio-width = <0x2>;
+       xlnx,gpio2-width = <0x2>;
+       xlnx,interrupt-present = <0x1>;
+       xlnx,is-dual = <0x1>;
+       xlnx,tri-default = <0xffffffff>;
+       xlnx,tri-default-2 = <0xffffffff>;
+} ;
diff --git a/Documentation/devicetree/bindings/hwmon/g762.txt b/Documentation/devicetree/bindings/hwmon/g762.txt
new file mode 100644 (file)
index 0000000..25cc6d8
--- /dev/null
@@ -0,0 +1,47 @@
+GMT G762/G763 PWM Fan controller
+
+Required node properties:
+
+ - "compatible": must be either "gmt,g762" or "gmt,g763"
+ - "reg": I2C bus address of the device
+ - "clocks": a fixed clock providing input clock frequency
+            on CLK pin of the chip.
+
+Optional properties:
+
+ - "fan_startv": fan startup voltage. Accepted values are 0, 1, 2 and 3.
+              The higher the more.
+
+ - "pwm_polarity": pwm polarity. Accepted values are 0 (positive duty)
+              and 1 (negative duty).
+
+ - "fan_gear_mode": fan gear mode. Supported values are 0, 1 and 2.
+
+If an optional property is not set in .dts file, then current value is kept
+unmodified (e.g. u-boot installed value).
+
+Additional information on operational parameters for the device is available
+in Documentation/hwmon/g762. A detailed datasheet for the device is available
+at http://natisbad.org/NAS/refs/GMT_EDS-762_763-080710-0.2.pdf.
+
+Example g762 node:
+
+   clocks {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       g762_clk: fixedclk {
+                compatible = "fixed-clock";
+                #clock-cells = <0>;
+                clock-frequency = <8192>;
+       }
+   }
+
+   g762: g762@3e {
+       compatible = "gmt,g762";
+       reg = <0x3e>;
+       clocks = <&g762_clk>
+       fan_gear_mode = <0>; /* chip default */
+       fan_startv = <1>;    /* chip default */
+       pwm_polarity = <0>;  /* chip default */
+   };
diff --git a/Documentation/devicetree/bindings/i2c/ina2xx.txt b/Documentation/devicetree/bindings/i2c/ina2xx.txt
new file mode 100644 (file)
index 0000000..a2ad85d
--- /dev/null
@@ -0,0 +1,22 @@
+ina2xx properties
+
+Required properties:
+- compatible: Must be one of the following:
+       - "ti,ina219" for ina219
+       - "ti,ina220" for ina220
+       - "ti,ina226" for ina226
+       - "ti,ina230" for ina230
+- reg: I2C address
+
+Optional properties:
+
+- shunt-resistor
+       Shunt resistor value in micro-Ohm
+
+Example:
+
+ina220@44 {
+       compatible = "ti,ina220";
+       reg = <0x44>;
+       shunt-resistor = <1000>;
+};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/abilis,tb10x-ictl.txt
new file mode 100644 (file)
index 0000000..9d52d5a
--- /dev/null
@@ -0,0 +1,38 @@
+TB10x Top Level Interrupt Controller
+====================================
+
+The Abilis TB10x SOC contains a custom interrupt controller. It performs
+one-to-one mapping of external interrupt sources to CPU interrupts and
+provides support for reconfigurable trigger modes.
+
+Required properties
+-------------------
+
+- compatible: Should be "abilis,tb10x-ictl"
+- reg: specifies physical base address and size of register range.
+- interrupt-congroller: Identifies the node as an interrupt controller.
+- #interrupt cells: Specifies the number of cells used to encode an interrupt
+  source connected to this controller. The value shall be 2.
+- interrupt-parent: Specifies the parent interrupt controller.
+- interrupts: Specifies the list of interrupt lines which are handled by
+  the interrupt controller in the parent controller's notation. Interrupts
+  are mapped one-to-one to parent interrupts.
+
+Example
+-------
+
+intc: interrupt-controller {   /* Parent interrupt controller */
+       interrupt-controller;
+       #interrupt-cells = <1>; /* For example below */
+       /* ... */
+};
+
+tb10x_ictl: pic@2000 {         /* TB10x interrupt controller */
+       compatible = "abilis,tb10x-ictl";
+       reg = <0x2000 0x20>;
+       interrupt-controller;
+       #interrupt-cells = <2>;
+       interrupt-parent = <&intc>;
+       interrupts = <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 31>;
+};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/marvell,orion-intc.txt
new file mode 100644 (file)
index 0000000..2c11ac7
--- /dev/null
@@ -0,0 +1,48 @@
+Marvell Orion SoC interrupt controllers
+
+* Main interrupt controller
+
+Required properties:
+- compatible: shall be "marvell,orion-intc"
+- reg: base address(es) of interrupt registers starting with CAUSE register
+- interrupt-controller: identifies the node as an interrupt controller
+- #interrupt-cells: number of cells to encode an interrupt source, shall be 1
+
+The interrupt sources map to the corresponding bits in the interrupt
+registers, i.e.
+- 0 maps to bit 0 of first base address,
+- 1 maps to bit 1 of first base address,
+- 32 maps to bit 0 of second base address, and so on.
+
+Example:
+       intc: interrupt-controller {
+               compatible = "marvell,orion-intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+                /* Dove has 64 first level interrupts */
+               reg = <0x20200 0x10>, <0x20210 0x10>;
+       };
+
+* Bridge interrupt controller
+
+Required properties:
+- compatible: shall be "marvell,orion-bridge-intc"
+- reg: base address of bridge interrupt registers starting with CAUSE register
+- interrupts: bridge interrupt of the main interrupt controller
+- interrupt-controller: identifies the node as an interrupt controller
+- #interrupt-cells: number of cells to encode an interrupt source, shall be 1
+
+Optional properties:
+- marvell,#interrupts: number of interrupts provided by bridge interrupt
+      controller, defaults to 32 if not set
+
+Example:
+       bridge_intc: interrupt-controller {
+               compatible = "marvell,orion-bridge-intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = <0x20110 0x8>;
+               interrupts = <0>;
+               /* Dove bridge provides 5 interrupts */
+               marvell,#interrupts = <5>;
+       };
diff --git a/Documentation/devicetree/bindings/leds/leds-lp55xx.txt b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt
new file mode 100644 (file)
index 0000000..d517688
--- /dev/null
@@ -0,0 +1,147 @@
+Binding for TI/National Semiconductor LP55xx Led Drivers
+
+Required properties:
+- compatible: "national,lp5521" or "national,lp5523" or "ti,lp5562"
+- reg: I2C slave address
+- clock-mode: Input clock mode, (0: automode, 1: internal, 2: external)
+
+Each child has own specific current settings
+- led-cur: Current setting at each led channel (mA x10, 0 if led is not connected)
+- max-cur: Maximun current at each led channel.
+
+Optional properties:
+- label: Used for naming LEDs
+
+Alternatively, each child can have specific channel name
+- chan-name: Name of each channel name
+
+example 1) LP5521
+3 LED channels, external clock used. Channel names are 'lp5521_pri:channel0',
+'lp5521_pri:channel1' and 'lp5521_pri:channel2'
+
+lp5521@32 {
+       compatible = "national,lp5521";
+       reg = <0x32>;
+       label = "lp5521_pri";
+       clock-mode = /bits/ 8 <2>;
+
+       chan0 {
+               led-cur = /bits/ 8 <0x2f>;
+               max-cur = /bits/ 8 <0x5f>;
+       };
+
+       chan1 {
+               led-cur = /bits/ 8 <0x2f>;
+               max-cur = /bits/ 8 <0x5f>;
+       };
+
+       chan2 {
+               led-cur = /bits/ 8 <0x2f>;
+               max-cur = /bits/ 8 <0x5f>;
+       };
+};
+
+example 2) LP5523
+9 LED channels with specific name. Internal clock used.
+The I2C slave address is configurable with ASEL1 and ASEL0 pins.
+Available addresses are 32/33/34/35h.
+
+ASEL1    ASEL0    Address
+-------------------------
+ GND      GND       32h
+ GND      VEN       33h
+ VEN      GND       34h
+ VEN      VEN       35h
+
+lp5523@32 {
+       compatible = "national,lp5523";
+       reg = <0x32>;
+       clock-mode = /bits/ 8 <1>;
+
+       chan0 {
+               chan-name = "d1";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan1 {
+               chan-name = "d2";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan2 {
+               chan-name = "d3";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan3 {
+               chan-name = "d4";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan4 {
+               chan-name = "d5";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan5 {
+               chan-name = "d6";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan6 {
+               chan-name = "d7";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan7 {
+               chan-name = "d8";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan8 {
+               chan-name = "d9";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+};
+
+example 3) LP5562
+4 channels are defined.
+
+lp5562@30 {
+       compatible = "ti,lp5562";
+       reg = <0x30>;
+       clock-mode = /bits/8 <2>;
+
+       chan0 {
+               chan-name = "R";
+               led-cur = /bits/ 8 <0x20>;
+               max-cur = /bits/ 8 <0x60>;
+       };
+
+       chan1 {
+               chan-name = "G";
+               led-cur = /bits/ 8 <0x20>;
+               max-cur = /bits/ 8 <0x60>;
+       };
+
+       chan2 {
+               chan-name = "B";
+               led-cur = /bits/ 8 <0x20>;
+               max-cur = /bits/ 8 <0x60>;
+       };
+
+       chan3 {
+               chan-name = "W";
+               led-cur = /bits/ 8 <0x20>;
+               max-cur = /bits/ 8 <0x60>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt
new file mode 100644 (file)
index 0000000..0e295c9
--- /dev/null
@@ -0,0 +1,62 @@
+Wolfson Arizona class audio SoCs
+
+These devices are audio SoCs with extensive digital capabilites and a range
+of analogue I/O.
+
+Required properties:
+
+  - compatible : one of the following chip-specific strings:
+       "wlf,wm5102"
+       "wlf,wm5110"
+  - reg : I2C slave address when connected using I2C, chip select number when
+    using SPI.
+
+  - interrupts : The interrupt line the /IRQ signal for the device is
+    connected to.
+  - interrupt-controller : Arizona class devices contain interrupt controllers
+    and may provide interrupt services to other devices.
+  - interrupt-parent : The parent interrupt controller.
+  - #interrupt-cells: the number of cells to describe an IRQ, this should be 2.
+    The first cell is the IRQ number.
+    The second cell is the flags, encoded as the trigger masks from
+    Documentation/devicetree/bindings/interrupts.txt
+
+  - gpio-controller : Indicates this device is a GPIO controller.
+  - #gpio-cells : Must be 2. The first cell is the pin number and the
+    second cell is used to specify optional parameters (currently unused).
+
+  - AVDD1-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply,
+    SPKVDDL-supply, SPKVDDR-supply : power supplies for the device, as covered
+    in Documentation/devicetree/bindings/regulator/regulator.txt
+
+Optional properties:
+
+  - wlf,reset : GPIO specifier for the GPIO controlling /RESET
+  - wlf,ldoena : GPIO specifier for the GPIO controlling LDOENA
+
+  - wlf,gpio-defaults : A list of GPIO configuration register values. If
+    absent, no configuration of these registers is performed. If any
+    entry has a value that is out of range for a 16 bit register then
+    the chip default will be used.  If present exactly five values must
+    be specified.
+
+Example:
+
+codec: wm5102@1a {
+       compatible = "wlf,wm5102";
+       reg = <0x1a>;
+       interrupts = <347>;
+       #interrupt-cells = <2>;
+        interrupt-parent = <&gic>;
+
+       gpio-controller;
+       #gpio-cells = <2>;
+
+       wlf,gpio-defaults = <
+               0x00000000, /* AIF1TXLRCLK */
+               0xffffffff,
+               0xffffffff,
+               0xffffffff,
+               0xffffffff,
+       >;
+};
diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
new file mode 100644 (file)
index 0000000..11921cc
--- /dev/null
@@ -0,0 +1,55 @@
+Maxim MAX77693 multi-function device
+
+MAX77693 is a Multifunction device with the following submodules:
+- PMIC,
+- CHARGER,
+- LED,
+- MUIC,
+- HAPTIC
+
+It is interfaced to host controller using i2c.
+This document describes the bindings for the mfd device.
+
+Required properties:
+- compatible : Must be "maxim,max77693".
+- reg : Specifies the i2c slave address of PMIC block.
+- interrupts : This i2c device has an IRQ line connected to the main SoC.
+- interrupt-parent :  The parent interrupt controller.
+
+Optional properties:
+- regulators : The regulators of max77693 have to be instantiated under subnod
+  named "regulators" using the following format.
+
+       regulators {
+               regualtor-compatible = ESAFEOUT1/ESAFEOUT2/CHARGER
+               standard regulator constratints[*].
+       };
+
+       [*] refer Documentation/devicetree/bindings/regulator/regulator.txt
+
+Example:
+       max77693@66 {
+               compatible = "maxim,max77693";
+               reg = <0x66>;
+               interrupt-parent = <&gpx1>;
+               interrupts = <5 2>;
+
+               regulators {
+                       esafeout@1 {
+                               regulator-compatible = "ESAFEOUT1";
+                               regulator-name = "ESAFEOUT1";
+                               regulator-boot-on;
+                       };
+                       esafeout@2 {
+                               regulator-compatible = "ESAFEOUT2";
+                               regulator-name = "ESAFEOUT2";
+                               };
+                       charger@0 {
+                               regulator-compatible = "CHARGER";
+                               regulator-name = "CHARGER";
+                               regulator-min-microamp = <60000>;
+                               regulator-max-microamp = <2580000>;
+                                       regulator-boot-on;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt
new file mode 100644 (file)
index 0000000..ddcdeb6
--- /dev/null
@@ -0,0 +1,41 @@
+Freescale Vybrid VF610 IOMUX Controller
+
+Please refer to fsl,imx-pinctrl.txt in this directory for common binding part
+and usage.
+
+Required properties:
+- compatible: "fsl,vf610-iomuxc"
+- fsl,pins: two integers array, represents a group of pins mux and config
+  setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is
+  a pin working on a specific function, CONFIG is the pad setting value
+  such as pull-up, speed, ode for this pin. Please refer to Vybrid VF610
+  datasheet for the valid pad config settings.
+
+CONFIG bits definition:
+PAD_CTL_SPEED_LOW              (1 << 12)
+PAD_CTL_SPEED_MED              (2 << 12)
+PAD_CTL_SPEED_HIGH             (3 << 12)
+PAD_CTL_SRE_FAST               (1 << 11)
+PAD_CTL_SRE_SLOW               (0 << 11)
+PAD_CTL_ODE                    (1 << 10)
+PAD_CTL_HYS                    (1 << 9)
+PAD_CTL_DSE_DISABLE            (0 << 6)
+PAD_CTL_DSE_150ohm             (1 << 6)
+PAD_CTL_DSE_75ohm              (2 << 6)
+PAD_CTL_DSE_50ohm              (3 << 6)
+PAD_CTL_DSE_37ohm              (4 << 6)
+PAD_CTL_DSE_30ohm              (5 << 6)
+PAD_CTL_DSE_25ohm              (6 << 6)
+PAD_CTL_DSE_20ohm              (7 << 6)
+PAD_CTL_PUS_100K_DOWN          (0 << 4)
+PAD_CTL_PUS_47K_UP             (1 << 4)
+PAD_CTL_PUS_100K_UP            (2 << 4)
+PAD_CTL_PUS_22K_UP             (3 << 4)
+PAD_CTL_PKE                    (1 << 3)
+PAD_CTL_PUE                    (1 << 2)
+PAD_CTL_OBE_ENABLE             (1 << 1)
+PAD_CTL_IBE_ENABLE             (1 << 0)
+PAD_CTL_OBE_IBE_ENABLE         (3 << 0)
+
+Please refer to vf610-pinfunc.h in device tree source folder
+for all available PIN_FUNC_ID for Vybrid VF610.
diff --git a/Documentation/devicetree/bindings/pinctrl/img,tz1090-pdc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/img,tz1090-pdc-pinctrl.txt
new file mode 100644 (file)
index 0000000..a186181
--- /dev/null
@@ -0,0 +1,127 @@
+ImgTec TZ1090 PDC pin controller
+
+Required properties:
+- compatible: "img,tz1090-pdc-pinctrl"
+- reg: Should contain the register physical address and length of the
+  SOC_GPIO_CONTROL registers in the PDC register region.
+
+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".
+
+TZ1090-PDC's pin configuration nodes act as a container for an abitrary 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.
+
+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. For this reason, even seemingly boolean
+values are actually tristates in this binding: unspecified, off, or on.
+Unspecified is represented as an absent property, and off/on are represented as
+integer values 0 and 1.
+
+Required subnode-properties:
+- tz1090,pins : An array of strings. Each string contains the name of a pin or
+  group. Valid values for these names are listed below.
+
+Optional subnode-properties:
+- tz1090,function: A string containing the name of the function to mux to the
+  pin or group. Valid values for function names are listed below, including
+  which pingroups can be muxed to them.
+- supported generic pinconfig properties (for further details see
+  Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt):
+  - bias-disable
+  - bias-high-impedance
+  - bias-bus-hold
+  - bias-pull-up
+  - bias-pull-down
+  - input-schmitt-enable
+  - input-schmitt-disable
+  - drive-strength: Integer, control drive strength of pins in mA.
+      2: 2mA
+      4: 4mA
+      8: 8mA
+      12: 12mA
+  - low-power-enable: Flag, power-on-start weak pull-down for invalid power.
+  - low-power-disable: Flag, power-on-start weak pull-down disabled.
+
+Note that many of these properties are only valid for certain specific pins
+or groups. See the TZ1090 TRM for complete details regarding which groups
+support which functionality. The Linux pinctrl driver may also be a useful
+reference.
+
+Valid values for pin and group names are:
+
+  pins:
+
+    These all support bias-high-impediance, bias-pull-up, bias-pull-down, and
+    bias-bus-hold (which can also be provided to any of the groups below to set
+    it for all gpio pins in that group).
+
+    gpio0, gpio1, sys_wake0, sys_wake1, sys_wake2, ir_data, ext_power.
+
+  mux groups:
+
+    These all support function.
+
+    gpio0
+        pins:       gpio0.
+        function:   ir_mod_stable_out.
+    gpio1
+        pins:       gpio1.
+        function:   ir_mod_power_out.
+
+  drive groups:
+
+    These support input-schmitt-enable, input-schmitt-disable,
+    drive-strength, low-power-enable, and low-power-disable.
+
+    pdc
+        pins:   gpio0, gpio1, sys_wake0, sys_wake1, sys_wake2, ir_data,
+                ext_power.
+
+Example:
+
+       pinctrl_pdc: pinctrl@02006500 {
+               #gpio-range-cells = <3>;
+               compatible = "img,tz1090-pdc-pinctrl";
+               reg = <0x02006500 0x100>;
+       };
+
+Example board file extracts:
+
+       &pinctrl_pdc {
+               pinctrl-names = "default";
+               pinctrl-0 = <&syswake_default>;
+
+               syswake_default: syswakes {
+                       syswake_cfg {
+                               tz1090,pins =   "sys_wake0",
+                                               "sys_wake1",
+                                               "sys_wake2";
+                               pull-up;
+                       };
+               };
+               irmod_default: irmod {
+                       gpio0_cfg {
+                               tz1090,pins =   "gpio0";
+                               tz1090,function = "ir_mod_stable_out";
+                       };
+                       gpio1_cfg {
+                               tz1090,pins =   "gpio1";
+                               tz1090,function = "ir_mod_power_out";
+                       };
+               };
+       };
+
+       ir: ir@02006200 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&irmod_default>;
+       };
diff --git a/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt
new file mode 100644 (file)
index 0000000..4b27c99
--- /dev/null
@@ -0,0 +1,227 @@
+ImgTec TZ1090 pin controller
+
+Required properties:
+- compatible: "img,tz1090-pinctrl"
+- reg: Should contain the register physical address and length of the pad
+  configuration registers (CR_PADS_* and CR_IF_CTL0).
+
+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".
+
+TZ1090's pin configuration nodes act as a container for an abitrary 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.
+
+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. For this reason, even seemingly boolean
+values are actually tristates in this binding: unspecified, off, or on.
+Unspecified is represented as an absent property, and off/on are represented as
+integer values 0 and 1.
+
+Required subnode-properties:
+- tz1090,pins : An array of strings. Each string contains the name of a pin or
+  group. Valid values for these names are listed below.
+
+Optional subnode-properties:
+- tz1090,function: A string containing the name of the function to mux to the
+  pin or group. Valid values for function names are listed below, including
+  which pingroups can be muxed to them.
+- supported generic pinconfig properties (for further details see
+  Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt):
+  - bias-disable
+  - bias-high-impedance
+  - bias-bus-hold
+  - bias-pull-up
+  - bias-pull-down
+  - input-schmitt-enable
+  - input-schmitt-disable
+  - drive-strength: Integer, control drive strength of pins in mA.
+      2: 2mA
+      4: 4mA
+      8: 8mA
+      12: 12mA
+
+
+Note that many of these properties are only valid for certain specific pins
+or groups. See the TZ1090 TRM for complete details regarding which groups
+support which functionality. The Linux pinctrl driver may also be a useful
+reference.
+
+Valid values for pin and group names are:
+
+  gpio pins:
+
+    These all support bias-high-impediance, bias-pull-up, bias-pull-down, and
+    bias-bus-hold (which can also be provided to any of the groups below to set
+    it for all pins in that group).
+
+    They also all support the some form of muxing. Any pins which are contained
+    in one of the mux groups (see below) can be muxed only to the functions
+    supported by the mux group. All other pins can be muxed to the "perip"
+    function which which enables them with their intended peripheral.
+
+    Different pins in the same mux group cannot be muxed to different functions,
+    however it is possible to mux only a subset of the pins in a mux group to a
+    particular function and leave the remaining pins unmuxed. This is useful if
+    the board connects certain pins in a group to other devices to be controlled
+    by GPIO, and you don't want the usual peripheral to have any control of the
+    pin.
+
+    ant_sel0, ant_sel1, gain0, gain1, gain2, gain3, gain4, gain5, gain6, gain7,
+    i2s_bclk_out, i2s_din, i2s_dout0, i2s_dout1, i2s_dout2, i2s_lrclk_out,
+    i2s_mclk, pa_on, pdm_a, pdm_b, pdm_c, pdm_d, pll_on, rx_hp, rx_on,
+    scb0_sclk, scb0_sdat, scb1_sclk, scb1_sdat, scb2_sclk, scb2_sdat, sdh_cd,
+    sdh_clk_in, sdh_wp, sdio_clk, sdio_cmd, sdio_d0, sdio_d1, sdio_d2, sdio_d3,
+    spi0_cs0, spi0_cs1, spi0_cs2, spi0_din, spi0_dout, spi0_mclk, spi1_cs0,
+    spi1_cs1, spi1_cs2, spi1_din, spi1_dout, spi1_mclk, tft_blank_ls, tft_blue0,
+    tft_blue1, tft_blue2, tft_blue3, tft_blue4, tft_blue5, tft_blue6, tft_blue7,
+    tft_green0, tft_green1, tft_green2, tft_green3, tft_green4, tft_green5,
+    tft_green6, tft_green7, tft_hsync_nr, tft_panelclk, tft_pwrsave, tft_red0,
+    tft_red1, tft_red2, tft_red3, tft_red4, tft_red5, tft_red6, tft_red7,
+    tft_vd12acb, tft_vdden_gd, tft_vsync_ns, tx_on, uart0_cts, uart0_rts,
+    uart0_rxd, uart0_txd, uart1_rxd, uart1_txd.
+
+        bias-high-impediance:  supported.
+        bias-pull-up:          supported.
+        bias-pull-down:        supported.
+        bias-bus-hold:         supported.
+        function:              perip or those supported by pin's mux group.
+
+  other pins:
+
+    These other pins are part of various pin groups below, but can't be
+    controlled as GPIOs. They do however support bias-high-impediance,
+    bias-pull-up, bias-pull-down, and bias-bus-hold (which can also be provided
+    to any of the groups below to set it for all pins in that group).
+
+    clk_out0, clk_out1, tck, tdi, tdo, tms, trst.
+
+        bias-high-impediance:  supported.
+        bias-pull-up:          supported.
+        bias-pull-down:        supported.
+        bias-bus-hold:         supported.
+
+  mux groups:
+
+    These all support function, and some support drive configs.
+
+    afe
+        pins:                  tx_on, rx_on, pll_on, pa_on, rx_hp, ant_sel0,
+                               ant_sel1, gain0, gain1, gain2, gain3, gain4,
+                               gain5, gain6, gain7.
+        function:              afe, ts_out_0.
+        input-schmitt-enable:  supported.
+        input-schmitt-disable: supported.
+        drive-strength:        supported.
+    pdm_d
+        pins:                  pdm_d.
+        function:              pdm_dac, usb_vbus.
+    sdh
+        pins:                  sdh_cd, sdh_wp, sdh_clk_in.
+        function:              sdh, sdio.
+    sdio
+        pins:                  sdio_clk, sdio_cmd, sdio_d0, sdio_d1, sdio_d2,
+                               sdio_d3.
+        function:              sdio, sdh.
+    spi1_cs2
+        pins:                  spi1_cs2.
+        function:              spi1_cs2, usb_vbus.
+    tft
+        pins:                  tft_red0, tft_red1, tft_red2, tft_red3,
+                               tft_red4, tft_red5, tft_red6, tft_red7,
+                               tft_green0, tft_green1, tft_green2, tft_green3,
+                               tft_green4, tft_green5, tft_green6, tft_green7,
+                               tft_blue0, tft_blue1, tft_blue2, tft_blue3,
+                               tft_blue4, tft_blue5, tft_blue6, tft_blue7,
+                               tft_vdden_gd, tft_panelclk, tft_blank_ls,
+                               tft_vsync_ns, tft_hsync_nr, tft_vd12acb,
+                               tft_pwrsave.
+        function:              tft, ext_dac, not_iqadc_stb, iqdac_stb, ts_out_1,
+                               lcd_trace, phy_ringosc.
+        input-schmitt-enable:  supported.
+        input-schmitt-disable: supported.
+        drive-strength:        supported.
+
+  drive groups:
+
+    These all support input-schmitt-enable, input-schmitt-disable,
+    and drive-strength.
+
+    jtag
+        pins:   tck, trst, tdi, tdo, tms.
+    scb1
+        pins:   scb1_sdat, scb1_sclk.
+    scb2
+        pins:   scb2_sdat, scb2_sclk.
+    spi0
+        pins:   spi0_mclk, spi0_cs0, spi0_cs1, spi0_cs2, spi0_dout, spi0_din.
+    spi1
+        pins:   spi1_mclk, spi1_cs0, spi1_cs1, spi1_cs2, spi1_dout, spi1_din.
+    uart
+        pins:   uart0_txd, uart0_rxd, uart0_rts, uart0_cts,
+                uart1_txd, uart1_rxd.
+    drive_i2s
+        pins:   clk_out1, i2s_din, i2s_dout0, i2s_dout1, i2s_dout2,
+                i2s_lrclk_out, i2s_bclk_out, i2s_mclk.
+    drive_pdm
+        pins:   clk_out0, pdm_b, pdm_a.
+    drive_scb0
+        pins:   scb0_sclk, scb0_sdat, pdm_d, pdm_c.
+    drive_sdio
+        pins:   sdio_clk, sdio_cmd, sdio_d0, sdio_d1, sdio_d2, sdio_d3,
+                sdh_wp, sdh_cd, sdh_clk_in.
+
+  convenience groups:
+
+    These are just convenient groupings of pins and don't support any drive
+    configs.
+
+    uart0
+        pins:   uart0_cts, uart0_rts, uart0_rxd, uart0_txd.
+    uart1
+        pins:   uart1_rxd, uart1_txd.
+    scb0
+        pins:   scb0_sclk, scb0_sdat.
+    i2s
+        pins:   i2s_bclk_out, i2s_din, i2s_dout0, i2s_dout1, i2s_dout2,
+                i2s_lrclk_out, i2s_mclk.
+
+Example:
+
+       pinctrl: pinctrl@02005800 {
+               #gpio-range-cells = <3>;
+               compatible = "img,tz1090-pinctrl";
+               reg = <0x02005800 0xe4>;
+       };
+
+Example board file extract:
+
+       &pinctrl {
+               uart0_default: uart0 {
+                       uart0_cfg {
+                               tz1090,pins =   "uart0_rxd",
+                                               "uart0_txd";
+                               tz1090,function = "perip";
+                       };
+               };
+               tft_default: tft {
+                       tft_cfg {
+                               tz1090,pins =   "tft";
+                               tz1090,function = "tft";
+                       };
+               };
+       };
+
+       uart@02004b00 {
+               pinctrl-names = "default";
+               pinctrl-0 = <&uart0_default>;
+       };
index a648aaad61102e7b58feb6a0a98085b1493befa5..50ec3512a292c3cbfc8a2ab4aba5c005c10ad2db 100644 (file)
@@ -10,29 +10,31 @@ Required properties:
 Available mpp pins/groups and functions:
 Note: brackets (x) are not part of the mpp name for marvell,function and given
 only for more detailed description in this document.
+Note: pmu* also allows for Power Management functions listed below
 
 name          pins     functions
 ================================================================================
-mpp0          0        gpio, pmu, uart2(rts), sdio0(cd), lcd0(pwm)
-mpp1          1        gpio, pmu, uart2(cts), sdio0(wp), lcd1(pwm)
+mpp0          0        gpio, pmu, uart2(rts), sdio0(cd), lcd0(pwm), pmu*
+mpp1          1        gpio, pmu, uart2(cts), sdio0(wp), lcd1(pwm), pmu*
 mpp2          2        gpio, pmu, uart2(txd), sdio0(buspwr), sata(prsnt),
-                       uart1(rts)
+                       uart1(rts), pmu*
 mpp3          3        gpio, pmu, uart2(rxd), sdio0(ledctrl), sata(act),
-                       uart1(cts), lcd-spi(cs1)
-mpp4          4        gpio, pmu, uart3(rts), sdio1(cd), spi1(miso)
-mpp5          5        gpio, pmu, uart3(cts), sdio1(wp), spi1(cs)
-mpp6          6        gpio, pmu, uart3(txd), sdio1(buspwr), spi1(mosi)
-mpp7          7        gpio, pmu, uart3(rxd), sdio1(ledctrl), spi1(sck)
-mpp8          8        gpio, pmu, watchdog(rstout)
-mpp9          9        gpio, pmu, pex1(clkreq)
-mpp10         10       gpio, pmu, ssp(sclk)
+                       uart1(cts), lcd-spi(cs1), pmu*
+mpp4          4        gpio, pmu, uart3(rts), sdio1(cd), spi1(miso), pmu*
+mpp5          5        gpio, pmu, uart3(cts), sdio1(wp), spi1(cs), pmu*
+mpp6          6        gpio, pmu, uart3(txd), sdio1(buspwr), spi1(mosi), pmu*
+mpp7          7        gpio, pmu, uart3(rxd), sdio1(ledctrl), spi1(sck), pmu*
+mpp8          8        gpio, pmu, watchdog(rstout), pmu*
+mpp9          9        gpio, pmu, pex1(clkreq), pmu*
+mpp10         10       gpio, pmu, ssp(sclk), pmu*
 mpp11         11       gpio, pmu, sata(prsnt), sata-1(act), sdio0(ledctrl),
-                       sdio1(ledctrl), pex0(clkreq)
-mpp12         12       gpio, pmu, uart2(rts), audio0(extclk), sdio1(cd), sata(act)
+                       sdio1(ledctrl), pex0(clkreq), pmu*
+mpp12         12       gpio, pmu, uart2(rts), audio0(extclk), sdio1(cd),
+                       sata(act), pmu*
 mpp13         13       gpio, pmu, uart2(cts), audio1(extclk), sdio1(wp),
-                       ssp(extclk)
-mpp14         14       gpio, pmu, uart2(txd), sdio1(buspwr), ssp(rxd)
-mpp15         15       gpio, pmu, uart2(rxd), sdio1(ledctrl), ssp(sfrm)
+                       ssp(extclk), pmu*
+mpp14         14       gpio, pmu, uart2(txd), sdio1(buspwr), ssp(rxd), pmu*
+mpp15         15       gpio, pmu, uart2(rxd), sdio1(ledctrl), ssp(sfrm), pmu*
 mpp16         16       gpio, uart3(rts), sdio0(cd), ac97(sdi1), lcd-spi(cs1)
 mpp17         17       gpio, uart3(cts), sdio0(wp), ac97(sdi2), twsi(sda),
                        ac97-1(sysclko)
@@ -57,6 +59,21 @@ mpp_nand      64-71    gpo, nand
 audio0        -        i2s, ac97
 twsi          -        none, opt1, opt2, opt3
 
+Power Management functions (pmu*):
+pmu-nc               Pin not driven by any PM function
+pmu-low              Pin driven low (0)
+pmu-high             Pin driven high (1)
+pmic(sdi)            Pin is used for PMIC SDI
+cpu-pwr-down         Pin is used for CPU_PWRDWN
+standby-pwr-down     Pin is used for STBY_PWRDWN
+core-pwr-good        Pin is used for CORE_PWR_GOOD (Pins 0-7 only)
+cpu-pwr-good         Pin is used for CPU_PWR_GOOD (Pins 8-15 only)
+bat-fault            Pin is used for BATTERY_FAULT
+ext0-wakeup          Pin is used for EXT0_WU
+ext1-wakeup          Pin is used for EXT0_WU
+ext2-wakeup          Pin is used for EXT0_WU
+pmu-blink            Pin is used for blink function
+
 Notes:
 * group "mpp_audio1" allows the following functions and gpio pins:
   - gpio          : gpio on pins 52-57
index c95ea8278f870ba29c4fa998165ee5b760bc3076..aeb3c995cc048a3f21704152a64c67c5fb739a50 100644 (file)
@@ -126,3 +126,51 @@ device; they may be grandchildren, for example. Whether this is legal, and
 whether there is any interaction between the child and intermediate parent
 nodes, is again defined entirely by the binding for the individual pin
 controller device.
+
+== Using generic pinconfig options ==
+
+Generic pinconfig parameters can be used by defining a separate node containing
+the applicable parameters (and optional values), like:
+
+pcfg_pull_up: pcfg_pull_up {
+       bias-pull-up;
+       drive-strength = <20>;
+};
+
+This node should then be referenced in the appropriate pinctrl node as a phandle
+and parsed in the driver using the pinconf_generic_parse_dt_config function.
+
+Supported configuration parameters are:
+
+bias-disable           - disable any pin bias
+bias-high-impedance    - high impedance mode ("third-state", "floating")
+bias-bus-hold          - latch weakly
+bias-pull-up           - pull up the pin
+bias-pull-down         - pull down the pin
+bias-pull-pin-default  - use pin-default pull state
+drive-push-pull                - drive actively high and low
+drive-open-drain       - drive with open drain
+drive-open-source      - drive with open source
+drive-strength         - sink or source at most X mA
+input-schmitt-enable   - enable schmitt-trigger mode
+input-schmitt-disable  - disable schmitt-trigger mode
+input-debounce         - debounce mode with debound time X
+low-power-enable       - enable low power mode
+low-power-disable      - disable low power mode
+output-low             - set the pin to output mode with low level
+output-high            - set the pin to output mode with high level
+
+Arguments for parameters:
+
+- bias-pull-up, -down and -pin-default take as optional argument on hardware
+  supporting it the pull strength in Ohm. bias-disable will disable the pull.
+
+- drive-strength takes as argument the target strength in mA.
+
+- input-debounce takes the debounce time in usec as argument
+  or 0 to disable debouncing
+
+All parameters not listed here, do not take an argument.
+
+More in-depth documentation on these parameters can be found in
+<include/linux/pinctrl/pinconfig-generic.h>
index 08f0c3d01575822f2c4c3e4e6395c3c498da2080..5a02e30dd262dfabfca818339c4da04dc2eae9d2 100644 (file)
@@ -18,7 +18,8 @@ Optional properties:
   pin functions is ignored
 
 - pinctrl-single,bit-per-mux : boolean to indicate that one register controls
-  more than one pin
+  more than one pin, for which "pinctrl-single,function-mask" property specifies
+ position mask of pin.
 
 - pinctrl-single,drive-strength : array of value that are used to configure
   drive strength in the pinmux register. They're value of drive strength
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
new file mode 100644 (file)
index 0000000..05bf82a
--- /dev/null
@@ -0,0 +1,110 @@
+*ST pin controller.
+
+Each multi-function pin is controlled, driven and routed through the
+PIO multiplexing block. Each pin supports GPIO functionality (ALT0)
+and multiple alternate functions(ALT1 - ALTx) that directly connect
+the pin to different hardware blocks.
+
+When a pin is in GPIO mode, Output Enable (OE), Open Drain(OD), and
+Pull Up (PU) are driven by the related PIO block.
+
+ST pinctrl driver controls PIO multiplexing block and also interacts with
+gpio driver to configure a pin.
+
+Required properties: (PIO multiplexing block)
+- compatible   : should be "st,<SOC>-<pio-block>-pinctrl"
+       like st,stih415-sbc-pinctrl, st,stih415-front-pinctrl and so on.
+- gpio-controller : Indicates this device is a GPIO controller
+- #gpio-cells    : Should be one. The first cell is the pin number.
+- st,retime-pin-mask   : Should be mask to specify which pins can be retimed.
+       If the property is not present, it is assumed that all the pins in the
+       bank are capable of retiming. Retiming is mainly used to improve the
+       IO timing margins of external synchronous interfaces.
+- st,bank-name         : Should be a name string for this bank as
+                       specified in datasheet.
+- st,syscfg            : Should be a phandle of the syscfg node.
+
+Example:
+       pin-controller-sbc {
+               #address-cells  = <1>;
+               #size-cells     = <1>;
+               compatible      = "st,stih415-sbc-pinctrl";
+               st,syscfg       = <&syscfg_sbc>;
+               ranges          = <0 0xfe610000 0x5000>;
+               PIO0: gpio@fe610000 {
+                       gpio-controller;
+                       #gpio-cells     = <1>;
+                       reg             = <0 0x100>;
+                       st,bank-name    = "PIO0";
+               };
+               ...
+               pin-functions nodes follow...
+       };
+
+
+Contents of function subnode node:
+----------------------
+Required properties for pin configuration node:
+- st,pins      : Child node with list of pins with configuration.
+
+Below is the format of how each pin conf should look like.
+
+<bank offset mux mode rt_type rt_delay rt_clk>
+
+Every PIO is represented with 4-7 parameters depending on retime configuration.
+Each parameter is explained as below.
+
+-bank          : Should be bank phandle to which this PIO belongs.
+-offset                : Offset in the PIO bank.
+-mux           : Should be alternate function number associated this pin.
+               Use same numbers from datasheet.
+-mode          :pin configuration is selected from one of the below values.
+               IN
+               IN_PU
+               OUT
+               BIDIR
+               BIDIR_PU
+
+-rt_type       Retiming Configuration for the pin.
+               Possible retime configuration are:
+
+               -------         -------------
+               value           args
+               -------         -------------
+               NICLK           <delay> <clk>
+               ICLK_IO         <delay> <clk>
+               BYPASS          <delay>
+               DE_IO           <delay> <clk>
+               SE_ICLK_IO      <delay> <clk>
+               SE_NICLK_IO     <delay> <clk>
+
+- delay        is retime delay in pico seconds as mentioned in data sheet.
+
+- rt_clk       :clk to be use for retime.
+               Possible values are:
+               CLK_A
+               CLK_B
+               CLK_C
+               CLK_D
+
+Example of mmcclk pin which is a bi-direction pull pu with retime config
+as non inverted clock retimed with CLK_B and delay of 0 pico seconds:
+
+pin-controller {
+       ...
+       mmc0 {
+               pinctrl_mmc: mmc {
+                       st,pins {
+                               mmcclk = <&PIO13 4 ALT4 BIDIR_PU NICLK 0 CLK_B>;
+                               ...
+                       };
+               };
+       ...
+       };
+};
+
+sdhci0:sdhci@fe810000{
+       ...
+       pinctrl-names = "default";
+       pinctrl-0       = <&pinctrl_mmc>;
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt
new file mode 100644 (file)
index 0000000..d5dac7b
--- /dev/null
@@ -0,0 +1,153 @@
+* Renesas Pin Function Controller (GPIO and Pin Mux/Config)
+
+The Pin Function Controller (PFC) is a Pin Mux/Config controller. On SH7372,
+SH73A0, R8A73A4 and R8A7740 it also acts as a GPIO controller.
+
+
+Pin Control
+-----------
+
+Required Properties:
+
+  - compatible: should be one of the following.
+    - "renesas,pfc-r8a73a4": for R8A73A4 (R-Mobile APE6) compatible pin-controller.
+    - "renesas,pfc-r8a7740": for R8A7740 (R-Mobile A1) compatible pin-controller.
+    - "renesas,pfc-r8a7778": for R8A7778 (R-Mobile M1) compatible pin-controller.
+    - "renesas,pfc-r8a7779": for R8A7779 (R-Car H1) compatible pin-controller.
+    - "renesas,pfc-r8a7790": for R8A7790 (R-Car H2) compatible pin-controller.
+    - "renesas,pfc-sh7372": for SH7372 (SH-Mobile AP4) compatible pin-controller.
+    - "renesas,pfc-sh73a0": for SH73A0 (SH-Mobile AG5) compatible pin-controller.
+
+  - reg: Base address and length of each memory resource used by the pin
+    controller hardware module.
+
+Optional properties:
+
+  - #gpio-range-cells: Mandatory when the PFC doesn't handle GPIO, forbidden
+    otherwise. Should be 3.
+
+The PFC node also acts as a container for pin configuration nodes. Please refer
+to pinctrl-bindings.txt in this directory for the definition of the term "pin
+configuration node" and for the common pinctrl bindings used by client devices.
+
+Each pin configuration node represents a desired configuration for a pin, a
+pin group, or a list of pins or pin groups. The configuration can include the
+function to select on those pin(s) and pin configuration parameters (such as
+pull-up and pull-down).
+
+Pin configuration nodes contain pin configuration properties, either directly
+or grouped in child subnodes. Both pin muxing and configuration parameters can
+be grouped in that way and referenced as a single pin configuration node by
+client devices.
+
+A configuration node or subnode must reference at least one pin (through the
+pins or pin groups properties) and contain at least a function or one
+configuration parameter. When the function is present only pin groups can be
+used to reference pins.
+
+All pin configuration nodes and subnodes names are ignored. All of those nodes
+are parsed through phandles and processed purely based on their content.
+
+Pin Configuration Node Properties:
+
+- renesas,pins : An array of strings, each string containing the name of a pin.
+- renesas,groups : An array of strings, each string containing the name of a pin
+  group.
+
+- renesas,function: A string containing the name of the function to mux to the
+  pin group(s) specified by the renesas,groups property
+
+  Valid values for pin, group and function names can be found in the group and
+  function arrays of the PFC data file corresponding to the SoC
+  (drivers/pinctrl/sh-pfc/pfc-*.c)
+
+The pin configuration parameters use the generic pinconf bindings defined in
+pinctrl-bindings.txt in this directory. The supported parameters are
+bias-disable, bias-pull-up and bias-pull-down.
+
+
+GPIO
+----
+
+On SH7372, SH73A0, R8A73A4 and R8A7740 the PFC node is also a GPIO controller
+node.
+
+Required Properties:
+
+  - gpio-controller: Marks the device node as a gpio controller.
+
+  - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
+    cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
+    GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
+
+The syntax of the gpio specifier used by client nodes should be the following
+with values derived from the SoC user manual.
+
+  <[phandle of the gpio controller node]
+   [pin number within the gpio controller]
+   [flags]>
+
+On other mach-shmobile platforms GPIO is handled by the gpio-rcar driver.
+Please refer to Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
+for documentation of the GPIO device tree bindings on those platforms.
+
+
+Examples
+--------
+
+Example 1: SH73A0 (SH-Mobile AG5) pin controller node
+
+       pfc: pfc@e6050000 {
+               compatible = "renesas,pfc-sh73a0";
+               reg = <0xe6050000 0x8000>,
+                     <0xe605801c 0x1c>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+Example 2: A GPIO LED node that references a GPIO
+
+       #include <dt-bindings/gpio/gpio.h>
+
+       leds {
+               compatible = "gpio-leds";
+               led1 {
+                       gpios = <&pfc 20 GPIO_ACTIVE_LOW>;
+               };
+       };
+
+Example 3: KZM-A9-GT (SH-Mobile AG5) default pin state hog and pin control maps
+           for the MMCIF and SCIFA4 devices
+
+       &pfc {
+               pinctrl-0 = <&scifa4_pins>;
+               pinctrl-names = "default";
+
+               mmcif_pins: mmcif {
+                       mux {
+                               renesas,groups = "mmc0_data8_0", "mmc0_ctrl_0";
+                               renesas,function = "mmc0";
+                       };
+                       cfg {
+                               renesas,groups = "mmc0_data8_0";
+                               renesas,pins = "PORT279";
+                               bias-pull-up;
+                       };
+               };
+
+               scifa4_pins: scifa4 {
+                       renesas,groups = "scifa4_data", "scifa4_ctrl";
+                       renesas,function = "scifa4";
+               };
+       };
+
+Example 4: KZM-A9-GT (SH-Mobile AG5) default pin state for the MMCIF device
+
+       &mmcif {
+               pinctrl-0 = <&mmcif_pins>;
+               pinctrl-names = "default";
+
+               bus-width = <8>;
+               vmmc-supply = <&reg_1p8v>;
+               status = "okay";
+       };
diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
new file mode 100644 (file)
index 0000000..b0fb101
--- /dev/null
@@ -0,0 +1,97 @@
+* Rockchip Pinmux Controller
+
+The Rockchip Pinmux Controller, enables the IC
+to share one PAD to several functional blocks. The sharing is done by
+multiplexing the PAD input/output signals. For each PAD there are up to
+4 muxing options with option 0 being the use as a GPIO.
+
+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 Rockchip pin configuration node is a node of a group of pins which can be
+used for a specific device or function. This node represents both mux and
+config of the pins in that group. The 'pins' selects the function mode(also
+named pin mode) this pin can work on and the 'config' configures various pad
+settings such as pull-up, etc.
+
+The pins are grouped into up to 5 individual pin banks which need to be
+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"
+
+Required properties for gpio sub nodes:
+  - compatible: "rockchip,gpio-bank"
+  - reg: register of the gpio bank (different than the iomux registerset)
+  - interrupts: base interrupt of the gpio bank in the interrupt controller
+  - clocks: clock that drives this bank
+  - gpio-controller: identifies the node as a gpio controller and pin bank.
+  - #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO
+    binding is used, the amount of cells must be specified as 2. See generic
+    GPIO binding documentation for description of particular cells.
+  - interrupt-controller: identifies the controller node as interrupt-parent.
+  - #interrupt-cells: the value of this property should be 2 and the interrupt
+    cells should use the standard two-cell scheme described in
+    bindings/interrupt-controller/interrupts.txt
+
+Required properties for pin configuration node:
+  - rockchip,pins: 3 integers array, represents a group of pins mux and config
+    setting. The format is rockchip,pins = <PIN_BANK PIN_BANK_IDX MUX &phandle>.
+    The MUX 0 means gpio and MUX 1 to 3 mean the specific device function.
+    The phandle of a node containing the generic pinconfig options
+    to use, as described in pinctrl-bindings.txt in this directory.
+
+Examples:
+
+#include <dt-bindings/pinctrl/rockchip.h>
+
+...
+
+pinctrl@20008000 {
+       compatible = "rockchip,rk3066a-pinctrl";
+       reg = <0x20008000 0x150>;
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges;
+
+       gpio0: gpio0@20034000 {
+               compatible = "rockchip,gpio-bank";
+               reg = <0x20034000 0x100>;
+               interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_gates8 9>;
+
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               interrupt-controller;
+               #interrupt-cells = <2>;
+       };
+
+       ...
+
+       pcfg_pull_default: pcfg_pull_default {
+               bias-pull-pin-default
+       };
+
+       uart2 {
+               uart2_xfer: uart2-xfer {
+                       rockchip,pins = <RK_GPIO1 8 1 &pcfg_pull_default>,
+                                       <RK_GPIO1 9 1 &pcfg_pull_default>;
+               };
+       };
+};
+
+uart2: serial@20064000 {
+       compatible = "snps,dw-apb-uart";
+       reg = <0x20064000 0x400>;
+       interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+       reg-shift = <2>;
+       reg-io-width = <1>;
+       clocks = <&mux_uart2>;
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart2_xfer>;
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt b/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt
new file mode 100644 (file)
index 0000000..e3865e1
--- /dev/null
@@ -0,0 +1,352 @@
+ST Ericsson abx500 pinmux controller
+
+Required properties:
+- compatible: "stericsson,ab8500-gpio",  "stericsson,ab8540-gpio",
+             "stericsson,ab8505-gpio", "stericsson,ab9540-gpio",
+
+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".
+
+ST Ericsson's 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 input, output, pull up, pull down...
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Required subnode-properties:
+- ste,pins : An array of strings. Each string contains the name of a pin or
+    group.
+
+Optional subnode-properties:
+- ste,function: A string containing the name of the function to mux to the
+  pin or group.
+
+- generic pin configuration option to use. Example :
+
+       default_cfg {
+               ste,pins = "GPIO1";
+               bias-disable;
+       };
+
+- ste,config: Handle of pin configuration node containing the generic
+  pinconfig options to use, as described in pinctrl-bindings.txt in
+  this directory. Example :
+
+       pcfg_bias_disable: pcfg_bias_disable {
+               bias-disable;
+       };
+
+       default_cfg {
+               ste,pins = "GPIO1";
+               ste.config = <&pcfg_bias_disable>;
+       };
+
+Example board file extract:
+
+&pinctrl_abx500 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&sysclkreq2_default_mode>, <&sysclkreq3_default_mode>, <&gpio3_default_mode>, <&sysclkreq6_default_mode>, <&pwmout1_default_mode>, <&pwmout2_default_mode>, <&pwmout3_default_mode>, <&adi1_default_mode>, <&dmic12_default_mode>, <&dmic34_default_mode>, <&dmic56_default_mode>, <&sysclkreq5_default_mode>, <&batremn_default_mode>, <&service_default_mode>, <&pwrctrl0_default_mode>, <&pwrctrl1_default_mode>, <&pwmextvibra1_default_mode>, <&pwmextvibra2_default_mode>, <&gpio51_default_mode>, <&gpio52_default_mode>, <&gpio53_default_mode>, <&gpio54_default_mode>, <&pdmclkdat_default_mode>;
+
+       sysclkreq2 {
+               sysclkreq2_default_mode: sysclkreq2_default {
+                       default_mux {
+                               ste,function = "sysclkreq";
+                               ste,pins = "sysclkreq2_d_1";
+                       };
+                       default_cfg {
+                               ste,pins = "GPIO1";
+                               bias-disable;
+                       };
+               };
+       };
+       sysclkreq3 {
+               sysclkreq3_default_mode: sysclkreq3_default {
+                       default_mux {
+                               ste,function = "sysclkreq";
+                               ste,pins = "sysclkreq3_d_1";
+                       };
+                       default_cfg {
+                               ste,pins = "GPIO2";
+                               output-low;
+                       };
+               };
+       };
+       gpio3 {
+               gpio3_default_mode: gpio3_default {
+                       default_mux {
+                               ste,function = "gpio";
+                               ste,pins = "gpio3_a_1";
+                       };
+                       default_cfg {
+                               ste,pins = "GPIO3";
+                               output-low;
+                       };
+               };
+       };
+       sysclkreq6 {
+               sysclkreq6_default_mode: sysclkreq6_default {
+                       default_mux {
+                               ste,function = "sysclkreq";
+                               ste,pins = "sysclkreq6_d_1";
+                       };
+                       default_cfg {
+                               ste,pins = "GPIO4";
+                               bias-disable;
+                       };
+               };
+       };
+       pwmout1 {
+               pwmout1_default_mode: pwmout1_default {
+                       default_mux {
+                               ste,function = "pwmout";
+                               ste,pins = "pwmout1_d_1";
+                       };
+                       default_cfg {
+                               ste,pins = "GPIO14";
+                               output-low;
+                       };
+               };
+       };
+       pwmout2 {
+               pwmout2_default_mode: pwmout2_default {
+                       pwmout2_default_mux {
+                               ste,function = "pwmout";
+                               ste,pins = "pwmout2_d_1";
+                       };
+                       pwmout2_default_cfg {
+                               ste,pins = "GPIO15";
+                               output-low;
+                       };
+               };
+       };
+       pwmout3 {
+               pwmout3_default_mode: pwmout3_default {
+                       pwmout3_default_mux {
+                               ste,function = "pwmout";
+                               ste,pins = "pwmout3_d_1";
+                       };
+                       pwmout3_default_cfg {
+                               ste,pins = "GPIO16";
+                               output-low;
+                       };
+               };
+       };
+       adi1 {
+
+               adi1_default_mode: adi1_default {
+                       adi1_default_mux {
+                               ste,function = "adi1";
+                               ste,pins = "adi1_d_1";
+                       };
+                       adi1_default_cfg1 {
+                               ste,pins = "GPIO17","GPIO19","GPIO20";
+                               bias-disable;
+                       };
+                       adi1_default_cfg2 {
+                               ste,pins = "GPIO18";
+                               output-low;
+                       };
+               };
+       };
+       dmic12 {
+               dmic12_default_mode: dmic12_default {
+                       dmic12_default_mux {
+                               ste,function = "dmic";
+                               ste,pins = "dmic12_d_1";
+                       };
+                       dmic12_default_cfg1 {
+                               ste,pins = "GPIO27";
+                               output-low;
+                       };
+                       dmic12_default_cfg2 {
+                               ste,pins = "GPIO28";
+                               bias-disable;
+                       };
+               };
+       };
+       dmic34 {
+               dmic34_default_mode: dmic34_default {
+                       dmic34_default_mux {
+                               ste,function = "dmic";
+                               ste,pins = "dmic34_d_1";
+                       };
+                       dmic34_default_cfg1 {
+                               ste,pins = "GPIO29";
+                               output-low;
+                       };
+                       dmic34_default_cfg2 {
+                               ste,pins = "GPIO30";
+                               bias-disable;{
+
+                       };
+               };
+       };
+       dmic56 {
+               dmic56_default_mode: dmic56_default {
+                       dmic56_default_mux {
+                               ste,function = "dmic";
+                               ste,pins = "dmic56_d_1";
+                       };
+                       dmic56_default_cfg1 {
+                               ste,pins = "GPIO31";
+                               output-low;
+                       };
+                       dmic56_default_cfg2 {
+                               ste,pins = "GPIO32";
+                               bias-disable;
+                       };
+               };
+       };
+       sysclkreq5 {
+               sysclkreq5_default_mode: sysclkreq5_default {
+                       sysclkreq5_default_mux {
+                               ste,function = "sysclkreq";
+                               ste,pins = "sysclkreq5_d_1";
+                       };
+                       sysclkreq5_default_cfg {
+                               ste,pins = "GPIO42";
+                               output-low;
+                       };
+               };
+       };
+       batremn {
+               batremn_default_mode: batremn_default {
+                       batremn_default_mux {
+                               ste,function = "batremn";
+                               ste,pins = "batremn_d_1";
+                       };
+                       batremn_default_cfg {
+                               ste,pins = "GPIO43";
+                               bias-disable;
+                       };
+               };
+       };
+       service {
+               service_default_mode: service_default {
+                       service_default_mux {
+                               ste,function = "service";
+                               ste,pins = "service_d_1";
+                       };
+                       service_default_cfg {
+                               ste,pins = "GPIO44";
+                               bias-disable;
+                       };
+               };
+       };
+       pwrctrl0 {
+               pwrctrl0_default_mux: pwrctrl0_mux {
+                       pwrctrl0_default_mux {
+                               ste,function = "pwrctrl";
+                               ste,pins = "pwrctrl0_d_1";
+                       };
+               };
+               pwrctrl0_default_mode: pwrctrl0_default {
+                       pwrctrl0_default_cfg {
+                               ste,pins = "GPIO45";
+                               bias-disable;
+                       };
+               };
+       };
+       pwrctrl1 {
+               pwrctrl1_default_mux: pwrctrl1_mux {
+                       pwrctrl1_default_mux {
+                               ste,function = "pwrctrl";
+                               ste,pins = "pwrctrl1_d_1";
+                       };
+               };
+               pwrctrl1_default_mode: pwrctrl1_default {
+                       pwrctrl1_default_cfg {
+                               ste,pins = "GPIO46";
+                               bias-disable;
+                       };
+               };
+       };
+       pwmextvibra1 {
+               pwmextvibra1_default_mode: pwmextvibra1_default {
+                       pwmextvibra1_default_mux {
+                               ste,function = "pwmextvibra";
+                               ste,pins = "pwmextvibra1_d_1";
+                       };
+                       pwmextvibra1_default_cfg {
+                               ste,pins = "GPIO47";
+                               bias-disable;
+                       };
+               };
+       };
+       pwmextvibra2 {
+               pwmextvibra2_default_mode: pwmextvibra2_default {
+                       pwmextvibra2_default_mux {
+                               ste,function = "pwmextvibra";
+                               ste,pins = "pwmextvibra2_d_1";
+                       };
+                       pwmextvibra1_default_cfg {
+                               ste,pins = "GPIO48";
+                               bias-disable;
+                       };
+               };
+       };
+       gpio51 {
+               gpio51_default_mode: gpio51_default {
+                               gpio51_default_mux {
+                               ste,function = "gpio";
+                               ste,pins = "gpio51_a_1";
+                       };
+                       gpio51_default_cfg {
+                               ste,pins = "GPIO51";
+                               output-low;
+                       };
+               };
+       };
+       gpio52 {
+               gpio52_default_mode: gpio52_default {
+                       gpio52_default_mux {
+                               ste,function = "gpio";
+                               ste,pins = "gpio52_a_1";
+                       };
+                       gpio52_default_cfg {
+                               ste,pins = "GPIO52";
+                               bias-pull-down;
+                       };
+               };
+       };
+       gpio53 {
+               gpio53_default_mode: gpio53_default {
+                       gpio53_default_mux {
+                               ste,function = "gpio";
+                               ste,pins = "gpio53_a_1";
+                       };
+                       gpio53_default_cfg {
+                               ste,pins = "GPIO53";
+                               bias-pull-down;
+                       };
+               };
+       };
+       gpio54 {
+               gpio54_default_mode: gpio54_default {
+                       gpio54_default_mux {
+                               ste,function = "gpio";
+                               ste,pins = "gpio54_a_1";
+                       };
+                       gpio54_default_cfg {
+                               ste,pins = "GPIO54";
+                               output-low;
+                       };
+               };
+       };
+       pdmclkdat {
+               pdmclkdat_default_mode: pdmclkdat_default {
+                       pdmclkdat_default_mux {
+                               ste,function = "pdm";
+                               ste,pins = "pdmclkdat_d_1";
+                       };
+                       pdmclkdat_default_cfg {
+                               ste,pins = "GPIO55", "GPIO56";
+                               bias-disable;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/pps/pps-gpio.txt b/Documentation/devicetree/bindings/pps/pps-gpio.txt
new file mode 100644 (file)
index 0000000..40bf9c3
--- /dev/null
@@ -0,0 +1,20 @@
+Device-Tree Bindings for a PPS Signal on GPIO
+
+These properties describe a PPS (pulse-per-second) signal connected to
+a GPIO pin.
+
+Required properties:
+- compatible: should be "pps-gpio"
+- gpios: one PPS GPIO in the format described by ../gpio/gpio.txt
+
+Optional properties:
+- assert-falling-edge: when present, assert is indicated by a falling edge
+                       (instead of by a rising edge)
+
+Example:
+       pps {
+               compatible = "pps-gpio";
+               gpios = <&gpio2 6 0>;
+
+               assert-falling-edge;
+       };
diff --git a/Documentation/devicetree/bindings/regulator/lp872x.txt b/Documentation/devicetree/bindings/regulator/lp872x.txt
new file mode 100644 (file)
index 0000000..7818318
--- /dev/null
@@ -0,0 +1,160 @@
+Binding for TI/National Semiconductor LP872x Driver
+
+Required properties:
+  - compatible: "ti,lp8720" or "ti,lp8725"
+  - reg: I2C slave address. 0x7d = LP8720, 0x7a = LP8725
+
+Optional properties:
+  - ti,general-config: the value of LP872X_GENERAL_CFG register (u8)
+    (LP8720)
+    bit[2]: BUCK output voltage control by external DVS pin or register
+            1 = external pin, 0 = bit7 of register 08h
+    bit[1]: sleep control by external DVS pin or register
+            1 = external pin, 0 = bit6 of register 08h
+    bit[0]: time step unit(usec). 1 = 25, 0 = 50
+
+    (LP8725)
+    bit[7:6]: time step unit(usec). 00 = 32, 01 = 64, 10 = 128, 11 = 256
+    bit[4]:   BUCK2 enable control. 1 = enable, 0 = disable
+    bit[3]:   BUCK2 output voltage register address. 1 = 0Ah, 0 = 0Bh
+    bit[2]:   BUCK1 output voltage control by external DVS pin or register
+              1 = register 08h, 0 = DVS
+    bit[1]:   LDO sleep control. 1 = sleep mode, 0 = normal
+    bit[0]:   BUCK1 enable control, 1 = enable, 0 = disable
+
+    For more details, please see the datasheet.
+
+  - ti,update-config: define it when LP872X_GENERAL_CFG register should be set
+  - ti,dvs-gpio: GPIO specifier for external DVS pin control of LP872x devices.
+  - ti,dvs-vsel: DVS selector. 0 = SEL_V1, 1 = SEL_V2.
+  - ti,dvs-state: initial DVS pin state. 0 = DVS_LOW, 1 = DVS_HIGH.
+
+  Sub nodes for regulator_init_data
+    LP8720 has maximum 6 nodes. (child name: ldo1 ~ 5 and buck)
+    LP8725 has maximum 9 nodes. (child name: ldo1 ~ 5, lilo1,2 and buck1,2)
+    For more details, please see the following binding document.
+    (Documentation/devicetree/bindings/regulator/regulator.txt)
+
+Datasheet
+  - LP8720: http://www.ti.com/lit/ds/symlink/lp8720.pdf
+  - LP8725: http://www.ti.com/lit/ds/symlink/lp8725.pdf
+
+Example 1) LP8720
+
+lp8720@7d {
+       compatible = "ti,lp8720";
+       reg = <0x7d>;
+
+       /* external DVS pin used, timestep is 25usec */
+       ti,general-config = /bits/ 8 <0x03>;
+       ti,update-config;
+
+       /*
+        * The dvs-gpio depends on the processor environment.
+        * For example, following GPIO specifier means GPIO134 in OMAP4.
+        */
+       ti,dvs-gpio = <&gpio5 6 0>;
+       ti,dvs-vsel = /bits/ 8 <1>;             /* SEL_V2 */
+       ti,dvs-state = /bits/ 8 <1>;            /* DVS_HIGH */
+
+       vaf: ldo1 {
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       vmmc: ldo2 {
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       vcam_io: ldo3 {
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+       };
+
+       vcam_core: ldo4 {
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <2850000>;
+               regulator-boot-on;
+       };
+
+       vcam: ldo5 {
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       vcc: buck {
+               regulator-name = "VBUCK";
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <2300000>;
+       };
+};
+
+Example 2) LP8725
+
+lp8725@7a {
+       compatible = "ti,lp8725";
+       reg = <0x7a>;
+
+       /* Enable BUCK1,2, no DVS, normal LDO mode, timestep is 256usec */
+       ti,general-config = /bits/ 8 <0xdd>;
+       ti,update-config;
+
+       vcam_io: ldo1 {
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       vcam_core: ldo2 {
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       vcam: ldo3 {
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       vcmmb_io: ldo4 {
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+       };
+
+       vcmmb_core: ldo5 {
+               regulator-min-microvolt = <1200000>;
+               regulator-max-microvolt = <3300000>;
+               regulator-boot-on;
+       };
+
+       vaux1: lilo1 {
+               regulator-name = "VAUX1";
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       vaux2: lilo2 {
+               regulator-name = "VAUX2";
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <3300000>;
+       };
+
+       vcc1: buck1 {
+               regulator-name = "VBUCK1";
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <3000000>;
+               regulator-min-microamp  = <460000>;
+               regulator-max-microamp  = <1370000>;
+               regulator-boot-on;
+       };
+
+       vcc2: buck2 {
+               regulator-name = "VBUCK2";
+               regulator-min-microvolt = <800000>;
+               regulator-max-microvolt = <3000000>;
+               regulator-min-microamp  = <460000>;
+               regulator-max-microamp  = <1370000>;
+               regulator-boot-on;
+       };
+};
diff --git a/Documentation/devicetree/bindings/regulator/max8973-regulator.txt b/Documentation/devicetree/bindings/regulator/max8973-regulator.txt
new file mode 100644 (file)
index 0000000..4f15d8a
--- /dev/null
@@ -0,0 +1,21 @@
+* Maxim MAX8973 Voltage Regulator
+
+Required properties:
+
+- compatible:  must be "maxim,max8973"
+- reg:         the i2c slave address of the regulator. It should be 0x1b.
+
+Any standard regulator properties can be used to configure the single max8973
+DCDC.
+
+Example:
+
+       max8973@1b {
+               compatible = "maxim,max8973";
+               reg = <0x1b>;
+
+               regulator-min-microvolt = <935000>;
+               regulator-max-microvolt = <1200000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
index ecfc6ccd67ef7bb22be6bab6267bfa724211d5e9..48a3b8e5d6bde80fce883c7db83f99dc4bcc7da7 100644 (file)
@@ -9,6 +9,7 @@ Optional properties:
 - regulator-max-microamp: largest current consumers may set
 - regulator-always-on: boolean, regulator should never be disabled
 - regulator-boot-on: bootloader/firmware enabled regulator
+- regulator-allow-bypass: allow the regulator to go into bypass mode
 - <name>-supply: phandle to the parent supply/regulator node
 - regulator-ramp-delay: ramp delay for regulator(in uV/uS)
 
diff --git a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
new file mode 100644 (file)
index 0000000..2e57a33
--- /dev/null
@@ -0,0 +1,128 @@
+Adaptive Body Bias(ABB) SoC internal LDO regulator for Texas Instruments SoCs
+
+Required Properties:
+- compatible: Should be one of:
+  - "ti,abb-v1" for older SoCs like OMAP3
+  - "ti,abb-v2" for newer SoCs like OMAP4, OMAP5
+- reg: Address and length of the register set for the device. It contains
+  the information of registers in the same order as described by reg-names
+- reg-names: Should contain the reg names
+  - "base-address"     - contains base address of ABB module
+  - "int-address"      - contains address of interrupt register for ABB module
+  (also see Optional properties)
+- #address-cell: should be 0
+- #size-cell: should be 0
+- clocks: should point to the clock node used by ABB module
+- ti,settling-time: Settling time in uSecs from SoC documentation for ABB module
+       to settle down(target time for SR2_WTCNT_VALUE).
+- ti,clock-cycles: SoC specific data about count of system ti,clock-cycles used for
+       computing settling time from SoC Documentation for ABB module(clock
+       cycles for SR2_WTCNT_VALUE).
+- ti,tranxdone-status-mask: Mask to the int-register to write-to-clear mask
+       indicating LDO tranxdone (operation complete).
+- ti,abb_info: An array of 6-tuples u32 items providing information about ABB
+       configuration needed per operational voltage of the device.
+       Each item consists of the following in the same order:
+       volt: voltage in uV - Only used to index ABB information.
+       ABB mode: one of the following:
+               0-bypass
+               1-Forward Body Bias(FBB)
+               3-Reverse Body Bias(RBB)
+       efuse:  (see Optional properties)
+       RBB enable efuse Mask:  (See Optional properties)
+       FBB enable efuse Mask:  (See Optional properties)
+       Vset value efuse Mask:  (See Optional properties)
+
+       NOTE: If more than 1 entry is present, then regulator is setup to change
+             voltage, allowing for various modes to be selected indexed off
+             the regulator. Further, ABB LDOs are considered always-on by
+             default.
+
+Optional Properties:
+- reg-names: In addition to the required properties, the following are optional
+  - "efuse-address"    - Contains efuse base address used to pick up ABB info.
+  - "ldo-address"      - Contains address of ABB LDO overide register address.
+       "efuse-address" is required for this.
+- ti,ldovbb-vset-mask  - Required if ldo-address is set, mask for LDO override
+       register to provide override vset value.
+- ti,ldovbb-override-mask - Required if ldo-address is set, mask for LDO
+       override register to enable override vset value.
+- ti,abb_opp_sel: Addendum to the description in required properties
+       efuse: Mandatory if 'efuse-address' register is defined. Provides offset
+              from efuse-address to pick up ABB characteristics. Set to 0 if
+              'efuse-address' is not defined.
+       RBB enable efuse Mask:  Optional if 'efuse-address' register is defined.
+               'ABB mode' is force set to RBB mode if value at "efuse-address"
+               + efuse maps to RBB mask. Set to 0 to ignore this.
+       FBB enable efuse Mask:  Optional if 'efuse-address' register is defined.
+               'ABB mode' is force set to FBB mode if value at "efuse-address"
+               + efuse maps to FBB mask (valid only if RBB mask does not match)
+               Set to 0 to ignore this.
+       Vset value efuse Mask:  Mandatory if ldo-address is set. Picks up from
+               efuse the value to set in 'ti,ldovbb-vset-mask' at ldo-address.
+
+Example #1: Simplest configuration (no efuse data, hard coded ABB table):
+abb_x: regulator-abb-x {
+       compatible = "ti,abb-v1";
+       regulator-name = "abb_x";
+       #address-cell = <0>;
+       #size-cells = <0>;
+       reg = <0x483072f0 0x8>, <0x48306818 0x4>;
+       reg-names = "base-address", "int-address";
+       ti,tranxdone-status-mask = <0x4000000>;
+       clocks = <&sysclk>;
+       ti,settling-time = <30>;
+       ti,clock-cycles = <8>;
+       ti,abb_info = <
+       /* uV           ABB     efuse   rbb_m   fbb_m   vset_m */
+       1012500         0       0       0       0       0 /* Bypass */
+       1200000         3       0       0       0       0 /* RBB mandatory */
+       1320000         1       0       0       0       0 /* FBB mandatory */
+       >;
+};
+
+Example #2: Efuse bits contain ABB mode setting (no LDO override capability)
+abb_y: regulator-abb-y {
+       compatible = "ti,abb-v2";
+       regulator-name = "abb_y";
+       #address-cell = <0>;
+       #size-cells = <0>;
+       reg = <0x4a307bd0 0x8>, <0x4a306014 0x4>, <0x4A002268 0x8>;
+       reg-names = "base-address", "int-address", "efuse-address";
+       ti,tranxdone-status-mask = <0x4000000>;
+       clocks = <&sysclk>;
+       ti,settling-time = <50>;
+       ti,clock-cycles = <16>;
+       ti,abb_info = <
+       /* uV           ABB     efuse   rbb_m   fbb_m   vset_m */
+       975000          0       0       0       0       0 /* Bypass */
+       1012500         0       0       0x40000 0       0 /* RBB optional */
+       1200000         0       0x4     0       0x40000 0 /* FBB optional */
+       1320000         1       0       0       0       0 /* FBB mandatory */
+       >;
+};
+
+Example #3: Efuse bits contain ABB mode setting and LDO override capability
+abb_z: regulator-abb-z {
+       compatible = "ti,abb-v2";
+       regulator-name = "abb_z";
+       #address-cell = <0>;
+       #size-cells = <0>;
+       reg = <0x4ae07ce4 0x8>, <0x4ae06010 0x4>,
+             <0x4a002194 0x8>, <0x4ae0C314 0x4>;
+       reg-names = "base-address", "int-address",
+                   "efuse-address", "ldo-address";
+       ti,tranxdone-status-mask = <0x8000000>;
+       /* LDOVBBMM_MUX_CTRL */
+       ti,ldovbb-override-mask = <0x400>;
+       /* LDOVBBMM_VSET_OUT */
+       ti,ldovbb-vset-mask = <0x1F>;
+       clocks = <&sysclk>;
+       ti,settling-time = <50>;
+       ti,clock-cycles = <16>;
+       ti,abb_info = <
+       /* uV   ABB     efuse   rbb_m   fbb_m   vset_m */
+       975000  0       0       0       0       0       /* Bypass */
+       1200000 0       0x4     0       0x40000 0x1f00  /* FBB optional, vset */
+       >;
+};
diff --git a/Documentation/devicetree/bindings/sound/adi,adau1701.txt b/Documentation/devicetree/bindings/sound/adi,adau1701.txt
new file mode 100644 (file)
index 0000000..547a49b
--- /dev/null
@@ -0,0 +1,35 @@
+Analog Devices ADAU1701
+
+Required properties:
+
+ - compatible:         Should contain "adi,adau1701"
+ - reg:                        The i2c address. Value depends on the state of ADDR0
+                       and ADDR1, as wired in hardware.
+
+Optional properties:
+
+ - reset-gpio:                 A GPIO spec to define which pin is connected to the
+                       chip's !RESET pin. If specified, the driver will
+                       assert a hardware reset at probe time.
+ - adi,pll-mode-gpios: An array of two GPIO specs to describe the GPIOs
+                       the ADAU's PLL config pins are connected to.
+                       The state of the pins are set according to the
+                       configured clock divider on ASoC side before the
+                       firmware is loaded.
+ - adi,pin-config:     An array of 12 numerical values selecting one of the
+                       pin configurations as described in the datasheet,
+                       table 53. Note that the value of this property has
+                       to be prefixed with '/bits/ 8'.
+
+Examples:
+
+       i2c_bus {
+               adau1701@34 {
+                       compatible = "adi,adau1701";
+                       reg = <0x34>;
+                       reset-gpio = <&gpio 23 0>;
+                       adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>;
+                       adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4
+                                                   0x4 0x4 0x4 0x4 0x4 0x4>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt b/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt
new file mode 100644 (file)
index 0000000..f49450a
--- /dev/null
@@ -0,0 +1,46 @@
+Freescale i.MX audio complex with WM8962 codec
+
+Required properties:
+- compatible : "fsl,imx-audio-wm8962"
+- model : The user-visible name of this sound complex
+- ssi-controller : The phandle of the i.MX SSI controller
+- audio-codec : The phandle of the WM8962 audio codec
+- audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names could be power
+  supplies, WM8962 pins, and the jacks on the board:
+
+  Power supplies:
+   * Mic Bias
+
+  Board connectors:
+   * Mic Jack
+   * Headphone Jack
+   * Ext Spk
+
+- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
+- mux-ext-port : The external port of the i.MX audio muxer
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+sound {
+       compatible = "fsl,imx6q-sabresd-wm8962",
+                    "fsl,imx-audio-wm8962";
+       model = "wm8962-audio";
+       ssi-controller = <&ssi2>;
+       audio-codec = <&codec>;
+               audio-routing =
+               "Headphone Jack", "HPOUTL",
+               "Headphone Jack", "HPOUTR",
+               "Ext Spk", "SPKOUTL",
+               "Ext Spk", "SPKOUTR",
+               "MICBIAS", "AMIC",
+               "IN3R", "MICBIAS",
+               "DMIC", "MICBIAS",
+               "DMICDAT", "DMIC";
+       mux-int-port = <2>;
+       mux-ext-port = <3>;
+};
index c37ba6143d9b338cc9b80b66f1253f1939af9d2b..7ba07a118e370deb7ac43e72fb18b307aa4a33c5 100644 (file)
@@ -3,8 +3,11 @@
 Required properties:
 - compatible: Should be "fsl,<chip>-saif"
 - reg: Should contain registers location and length
-- interrupts: Should contain ERROR and DMA interrupts
-- fsl,saif-dma-channel: APBX DMA channel for the SAIF
+- interrupts: Should contain ERROR interrupt number
+- dmas: DMA specifier, consisting of a phandle to DMA controller node
+  and SAIF DMA channel ID.
+  Refer to dma.txt and fsl-mxs-dma.txt for details.
+- dma-names: Must be "rx-tx".
 
 Optional properties:
 - fsl,saif-master: phandle to the master SAIF.  It's only required for
@@ -23,14 +26,16 @@ aliases {
 saif0: saif@80042000 {
        compatible = "fsl,imx28-saif";
        reg = <0x80042000 2000>;
-       interrupts = <59 80>;
-       fsl,saif-dma-channel = <4>;
+       interrupts = <59>;
+       dmas = <&dma_apbx 4>;
+       dma-names = "rx-tx";
 };
 
 saif1: saif@80046000 {
        compatible = "fsl,imx28-saif";
        reg = <0x80046000 2000>;
-       interrupts = <58 81>;
-       fsl,saif-dma-channel = <5>;
+       interrupts = <58>;
+       dmas = <&dma_apbx 5>;
+       dma-names = "rx-tx";
        fsl,saif-master = <&saif0>;
 };
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt
new file mode 100644 (file)
index 0000000..d130818
--- /dev/null
@@ -0,0 +1,71 @@
+NVIDIA Tegra audio complex, with RT5640 CODEC
+
+Required properties:
+- compatible : "nvidia,tegra-audio-rt5640"
+- clocks : Must contain an entry for each entry in clock-names.
+- clock-names : Must include the following entries:
+  "pll_a" (The Tegra clock of that name),
+  "pll_a_out0" (The Tegra clock of that name),
+  "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the RT5640's pins, and the jacks on the board:
+
+  RT5640 pins:
+
+  * DMIC1
+  * DMIC2
+  * MICBIAS1
+  * IN1P
+  * IN1R
+  * IN2P
+  * IN2R
+  * HPOL
+  * HPOR
+  * LOUTL
+  * LOUTR
+  * MONOP
+  * MONON
+  * SPOLP
+  * SPOLN
+  * SPORP
+  * SPORN
+
+  Board connectors:
+
+  * Headphones
+  * Speakers
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
+  connected to the CODEC.
+- nvidia,audio-codec : The phandle of the RT5640 audio codec. This binding
+  assumes that AIF1 on the CODEC is connected to Tegra.
+
+Optional properties:
+- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in
+
+Example:
+
+sound {
+       compatible = "nvidia,tegra-audio-rt5640-dalmore",
+                       "nvidia,tegra-audio-rt5640";
+       nvidia,model = "NVIDIA Tegra Dalmore";
+
+       nvidia,audio-routing =
+               "Headphones", "HPOR",
+               "Headphones", "HPOL",
+               "Speakers", "SPORP",
+               "Speakers", "SPORN",
+               "Speakers", "SPOLP",
+               "Speakers", "SPOLN";
+
+       nvidia,i2s-controller = <&tegra_i2s1>;
+       nvidia,audio-codec = <&rt5640>;
+
+       nvidia,hp-det-gpios = <&gpio 143 0>; /* GPIO PR7 */
+
+       clocks = <&tegra_car 216>, <&tegra_car 217>, <&tegra_car 120>;
+       clock-names = "pll_a", "pll_a_out0", "mclk";
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5640.txt b/Documentation/devicetree/bindings/sound/rt5640.txt
new file mode 100644 (file)
index 0000000..005bcb2
--- /dev/null
@@ -0,0 +1,30 @@
+RT5640 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5640".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+- realtek,in1-differential
+- realtek,in2-differential
+  Boolean. Indicate MIC1/2 input are differential, rather than single-ended.
+
+- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
+
+Example:
+
+rt5640 {
+       compatible = "realtek,rt5640";
+       reg = <0x1c>;
+       interrupt-parent = <&gpio>;
+       interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
+       realtek,ldo1-en-gpios =
+               <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+};
index 9cc44449508df9f2ee6704acf59b113a6ad9e079..955df60a118c5465b9884369db48533ba17af121 100644 (file)
@@ -5,9 +5,12 @@ Required properties:
 
 - reg : the I2C address of the device
 
+- clocks : the clock provider of SYS_MCLK
+
 Example:
 
 codec: sgtl5000@0a {
        compatible = "fsl,sgtl5000";
        reg = <0x0a>;
+       clocks = <&clks 150>;
 };
diff --git a/Documentation/devicetree/bindings/sound/spdif-receiver.txt b/Documentation/devicetree/bindings/sound/spdif-receiver.txt
new file mode 100644 (file)
index 0000000..80f807b
--- /dev/null
@@ -0,0 +1,10 @@
+Device-Tree bindings for dummy spdif receiver
+
+Required properties:
+       - compatible: should be "linux,spdif-dir".
+
+Example node:
+
+       codec: spdif-receiver {
+               compatible = "linux,spdif-dir";
+       };
diff --git a/Documentation/devicetree/bindings/sound/spdif-transmitter.txt b/Documentation/devicetree/bindings/sound/spdif-transmitter.txt
new file mode 100644 (file)
index 0000000..55a8584
--- /dev/null
@@ -0,0 +1,10 @@
+Device-Tree bindings for dummy spdif transmitter
+
+Required properties:
+       - compatible: should be "linux,spdif-dit".
+
+Example node:
+
+       codec: spdif-transmitter {
+               compatible = "linux,spdif-dit";
+       };
diff --git a/Documentation/devicetree/bindings/sound/ssm2518.txt b/Documentation/devicetree/bindings/sound/ssm2518.txt
new file mode 100644 (file)
index 0000000..59381a7
--- /dev/null
@@ -0,0 +1,20 @@
+SSM2518 audio amplifier
+
+This device supports I2C only.
+
+Required properties:
+  - compatible : Must be "adi,ssm2518"
+  - reg : the I2C address of the device. This will either be 0x34 (ADDR pin low)
+       or 0x35 (ADDR pin high)
+
+Optional properties:
+  - gpios : GPIO connected to the nSD pin. If the property is not present it is
+               assumed that the nSD pin is hardwired to always on.
+
+Example:
+
+       ssm2518: ssm2518@34 {
+               compatible = "adi,ssm2518";
+               reg = <0x34>;
+               gpios = <&gpio 5 0>;
+       };
index 8ea4f5b4818d22dfbb233350152c624e77aed56c..d2866a0d6a262694ddc7dfd447da87a37a031a23 100644 (file)
@@ -20,6 +20,17 @@ Optional properties:
                        When not specified, the hardware default of 1300ms
                        is retained.
 
+ - ti,mid-z-channel-X: Boolean properties, X being a number from 1 to 6.
+                       If given, channel X will start with the Mid-Z start
+                       sequence, otherwise the default Low-Z scheme is used.
+
+                       The correct configuration depends on how the power
+                       stages connected to the PWM output pins work. Not all
+                       power stages are compatible to Mid-Z - please refer
+                       to the datasheets for more details.
+
+                       Most systems should not set any of these properties.
+
 Examples:
 
        i2c_bus {
index dceb3b1c2bb7628316a2833aea977d900788faaf..7f82b59ec8f947f336ec6515d88839cbe7c3bb54 100644 (file)
@@ -8,9 +8,32 @@ Required properties:
 
   - reg : the I2C address of the device.
 
+Optional properties:
+  - spk-mono: This is a boolean property. If present, the SPK_MONO bit
+    of R51 (Class D Control 2) gets set, indicating that the speaker is
+    in mono mode.
+
+  - mic-cfg : Default register value for R48 (Additional Control 4).
+    If absent, the default should be the register default.
+
+  - gpio-cfg : A list of GPIO configuration register values. The list must
+    be 6 entries long. If absent, no configuration of these registers is
+    performed. And note that only the value within [0x0, 0xffff] is valid.
+    Any other value is regarded as setting the GPIO register by its reset
+    value 0x0.
+
 Example:
 
 codec: wm8962@1a {
        compatible = "wlf,wm8962";
        reg = <0x1a>;
+
+       gpio-cfg = <
+               0x0000 /* 0:Default */
+               0x0000 /* 1:Default */
+               0x0013 /* 2:FN_DMICCLK */
+               0x0000 /* 3:Default */
+               0x8014 /* 4:FN_DMICCDAT */
+               0x0000 /* 5:Default */
+       >;
 };
index 938809c6829bfdffd6b14af8005a60c2e7e003be..4c85c4c69584a14d39dd8597facb920b4b69cf46 100644 (file)
@@ -10,7 +10,18 @@ Required properties:
                          input. The default is D0 as input and
                          D1 as output.
 
-Example:
+Optional properties:
+- dmas: List of DMA specifiers with the controller specific format
+       as described in the generic DMA client binding. A tx and rx
+       specifier is required for each chip select.
+- dma-names: List of DMA request names. These strings correspond
+       1:1 with the DMA specifiers listed in dmas. The string naming
+       is to be "rxN" and "txN" for RX and TX requests,
+       respectively, where N equals the chip select number.
+
+Examples:
+
+[hwmod populated DMA resources]
 
 mcspi1: mcspi@1 {
     #address-cells = <1>;
@@ -20,3 +31,17 @@ mcspi1: mcspi@1 {
     ti,spi-num-cs = <4>;
 };
 
+[generic DMA request binding]
+
+mcspi1: mcspi@1 {
+    #address-cells = <1>;
+    #size-cells = <0>;
+    compatible = "ti,omap4-mcspi";
+    ti,hwmods = "mcspi1";
+    ti,spi-num-cs = <2>;
+    dmas = <&edma 42
+           &edma 43
+           &edma 44
+           &edma 45>;
+    dma-names = "tx0", "rx0", "tx1", "rx1";
+};
index 9858f337529c1c6edec3444cf0ac145ec331ed07..fe7afe22538149706eab5727c989d91a8530c387 100644 (file)
@@ -11,10 +11,8 @@ be able to use diff(1).
 prototypes:
        int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_weak_revalidate)(struct dentry *, unsigned int);
-       int (*d_hash)(const struct dentry *, const struct inode *,
-                       struct qstr *);
-       int (*d_compare)(const struct dentry *, const struct inode *,
-                       const struct dentry *, const struct inode *,
+       int (*d_hash)(const struct dentry *, struct qstr *);
+       int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(struct dentry *);
        void (*d_release)(struct dentry *);
@@ -66,6 +64,7 @@ prototypes:
        int (*atomic_open)(struct inode *, struct dentry *,
                                struct file *, unsigned open_flag,
                                umode_t create_mode, int *opened);
+       int (*tmpfile) (struct inode *, struct dentry *, umode_t);
 
 locking rules:
        all may block
@@ -93,6 +92,7 @@ removexattr:  yes
 fiemap:                no
 update_time:   no
 atomic_open:   yes
+tmpfile:       no
 
        Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
@@ -344,25 +344,38 @@ prototypes:
 
 
 locking rules:
-                       file_lock_lock  may block
+                       inode->i_lock   may block
 fl_copy_lock:          yes             no
 fl_release_private:    maybe           no
 
 ----------------------- lock_manager_operations ---------------------------
 prototypes:
        int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
+       unsigned long (*lm_owner_key)(struct file_lock *);
        void (*lm_notify)(struct file_lock *);  /* unblock callback */
        int (*lm_grant)(struct file_lock *, struct file_lock *, int);
        void (*lm_break)(struct file_lock *); /* break_lease callback */
        int (*lm_change)(struct file_lock **, int);
 
 locking rules:
-                       file_lock_lock  may block
-lm_compare_owner:      yes             no
-lm_notify:             yes             no
-lm_grant:              no              no
-lm_break:              yes             no
-lm_change              yes             no
+
+                       inode->i_lock   blocked_lock_lock       may block
+lm_compare_owner:      yes[1]          maybe                   no
+lm_owner_key           yes[1]          yes                     no
+lm_notify:             yes             yes                     no
+lm_grant:              no              no                      no
+lm_break:              yes             no                      no
+lm_change              yes             no                      no
+
+[1]:   ->lm_compare_owner and ->lm_owner_key are generally called with
+*an* inode->i_lock held. It may not be the i_lock of the inode
+associated with either file_lock argument! This is the case with deadlock
+detection, since the code has to chase down the owners of locks that may
+be entirely unrelated to the one on which the lock is being acquired.
+For deadlock detection however, the blocked_lock_lock is also held. The
+fact that these locks are held ensures that the file_locks do not
+disappear out from under you while doing the comparison or generating an
+owner key.
 
 --------------------------- buffer_head -----------------------------------
 prototypes:
index fd8d0d594fc7c9fd6bd1a5baa107968a9c9fab01..fcc22c982a25fe244a59135d7066ef156ef76be6 100644 (file)
@@ -473,7 +473,8 @@ This file is only present if the CONFIG_MMU kernel configuration option is
 enabled.
 
 The /proc/PID/clear_refs is used to reset the PG_Referenced and ACCESSED/YOUNG
-bits on both physical and virtual pages associated with a process.
+bits on both physical and virtual pages associated with a process, and the
+soft-dirty bit on pte (see Documentation/vm/soft-dirty.txt for details).
 To clear the bits for all the pages associated with the process
     > echo 1 > /proc/PID/clear_refs
 
@@ -482,6 +483,10 @@ To clear the bits for the anonymous pages associated with the process
 
 To clear the bits for the file mapped pages associated with the process
     > echo 3 > /proc/PID/clear_refs
+
+To clear the soft-dirty bit
+    > echo 4 > /proc/PID/clear_refs
+
 Any other value written to /proc/PID/clear_refs will have no effect.
 
 The /proc/pid/pagemap gives the PFN, which can be used to find the pageflags
index e6bd1ffd821e28fe05f8046836074b2f6976b6d8..f93a88250a448a99293d0a6d776af50b1a98453b 100644 (file)
@@ -360,6 +360,8 @@ struct inode_operations {
        int (*removexattr) (struct dentry *, const char *);
        void (*update_time)(struct inode *, struct timespec *, int);
        int (*atomic_open)(struct inode *, struct dentry *,
+       int (*tmpfile) (struct inode *, struct dentry *, umode_t);
+} ____cacheline_aligned;
                                struct file *, unsigned open_flag,
                                umode_t create_mode, int *opened);
 };
@@ -472,6 +474,9 @@ otherwise noted.
        component is negative or needs lookup.  Cached positive dentries are
        still handled by f_op->open().
 
+  tmpfile: called in the end of O_TMPFILE open().  Optional, equivalent to
+       atomically creating, opening and unlinking a file in given directory.
+
 The Address Space Object
 ========================
 
@@ -554,7 +559,6 @@ your filesystem. The following members are defined:
 struct address_space_operations {
        int (*writepage)(struct page *page, struct writeback_control *wbc);
        int (*readpage)(struct file *, struct page *);
-       int (*sync_page)(struct page *);
        int (*writepages)(struct address_space *, struct writeback_control *);
        int (*set_page_dirty)(struct page *page);
        int (*readpages)(struct file *filp, struct address_space *mapping,
@@ -576,6 +580,9 @@ struct address_space_operations {
        /* migrate the contents of a page to the specified target */
        int (*migratepage) (struct page *, struct page *);
        int (*launder_page) (struct page *);
+       int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
+                                       unsigned long);
+       void (*is_dirty_writeback) (struct page *, bool *, bool *);
        int (*error_remove_page) (struct mapping *mapping, struct page *page);
        int (*swap_activate)(struct file *);
        int (*swap_deactivate)(struct file *);
@@ -607,13 +614,6 @@ struct address_space_operations {
        In this case, the page will be relocated, relocked and if
        that all succeeds, ->readpage will be called again.
 
-  sync_page: called by the VM to notify the backing store to perform all
-       queued I/O operations for a page. I/O operations for other pages
-       associated with this address_space object may also be performed.
-
-       This function is optional and is called only for pages with
-       PG_Writeback set while waiting for the writeback to complete.
-
   writepages: called by the VM to write out pages associated with the
        address_space object.  If wbc->sync_mode is WBC_SYNC_ALL, then
        the writeback_control will specify a range of pages that must be
@@ -742,6 +742,20 @@ struct address_space_operations {
        prevent redirtying the page, it is kept locked during the whole
        operation.
 
+  is_partially_uptodate: Called by the VM when reading a file through the
+       pagecache when the underlying blocksize != pagesize. If the required
+       block is up to date then the read can complete without needing the IO
+       to bring the whole page up to date.
+
+  is_dirty_writeback: Called by the VM when attempting to reclaim a page.
+       The VM uses dirty and writeback information to determine if it needs
+       to stall to allow flushers a chance to complete some IO. Ordinarily
+       it can use PageDirty and PageWriteback but some filesystems have
+       more complex state (unstable pages in NFS prevent reclaim) or
+       do not set those flags due to locking problems (jbd). This callback
+       allows a filesystem to indicate to the VM if a page should be
+       treated as dirty or writeback for the purposes of stalling.
+
   error_remove_page: normally set to generic_error_remove_page if truncation
        is ok for this address space. Used for memory failure handling.
        Setting this implies you deal with pages going away under you,
@@ -901,10 +915,8 @@ defined:
 struct dentry_operations {
        int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_weak_revalidate)(struct dentry *, unsigned int);
-       int (*d_hash)(const struct dentry *, const struct inode *,
-                       struct qstr *);
-       int (*d_compare)(const struct dentry *, const struct inode *,
-                       const struct dentry *, const struct inode *,
+       int (*d_hash)(const struct dentry *, struct qstr *);
+       int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
        void (*d_release)(struct dentry *);
@@ -949,25 +961,24 @@ struct dentry_operations {
 
   d_hash: called when the VFS adds a dentry to the hash table. The first
        dentry passed to d_hash is the parent directory that the name is
-       to be hashed into. The inode is the dentry's inode.
+       to be hashed into.
 
        Same locking and synchronisation rules as d_compare regarding
        what is safe to dereference etc.
 
   d_compare: called to compare a dentry name with a given name. The first
        dentry is the parent of the dentry to be compared, the second is
-       the parent's inode, then the dentry and inode (may be NULL) of the
-       child dentry. len and name string are properties of the dentry to be
-       compared. qstr is the name to compare it with.
+       the child dentry. len and name string are properties of the dentry
+       to be compared. qstr is the name to compare it with.
 
        Must be constant and idempotent, and should not take locks if
-       possible, and should not or store into the dentry or inodes.
-       Should not dereference pointers outside the dentry or inodes without
+       possible, and should not or store into the dentry.
+       Should not dereference pointers outside the dentry without
        lots of care (eg.  d_parent, d_inode, d_name should not be used).
 
        However, our vfsmount is pinned, and RCU held, so the dentries and
        inodes won't disappear, neither will our sb or filesystem module.
-       ->i_sb and ->d_sb may be used.
+       ->d_sb may be used.
 
        It is a tricky calling convention because it needs to be called under
        "rcu-walk", ie. without any locks or references on things.
index 5e97f333c4df547e79507631a5b848578409f3d6..896cdc972ca8edcd9e7ae31081aeb39cc4d91eb3 100644 (file)
@@ -2,16 +2,30 @@ Kernel driver ds1621
 ====================
 
 Supported chips:
-  * Dallas Semiconductor DS1621
+  * Dallas Semiconductor / Maxim Integrated DS1621
     Prefix: 'ds1621'
-    Addresses scanned: I2C 0x48 - 0x4f
-    Datasheet: Publicly available at the Dallas Semiconductor website
-               http://www.dalsemi.com/
+    Addresses scanned: none
+    Datasheet: Publicly available from www.maximintegrated.com
+
   * Dallas Semiconductor DS1625
-    Prefix: 'ds1621'
-    Addresses scanned: I2C 0x48 - 0x4f
-    Datasheet: Publicly available at the Dallas Semiconductor website
-               http://www.dalsemi.com/
+    Prefix: 'ds1625'
+    Addresses scanned: none
+    Datasheet: Publicly available from www.datasheetarchive.com
+
+  * Maxim Integrated DS1631
+    Prefix: 'ds1631'
+    Addresses scanned: none
+    Datasheet: Publicly available from www.maximintegrated.com
+
+  * Maxim Integrated DS1721
+    Prefix: 'ds1721'
+    Addresses scanned: none
+    Datasheet: Publicly available from www.maximintegrated.com
+
+  * Maxim Integrated DS1731
+    Prefix: 'ds1731'
+    Addresses scanned: none
+    Datasheet: Publicly available from www.maximintegrated.com
 
 Authors:
         Christian W. Zuckschwerdt <zany@triq.net>
@@ -59,5 +73,115 @@ any of the limits have ever been met or exceeded since last power-up or
 reset. Be aware: When testing, it showed that the status of Tout can change
 with neither of the alarms set.
 
-Temperature conversion of the DS1621 takes up to 1000ms; internal access to
-non-volatile registers may last for 10ms or below.
+Since there is no version or vendor identification register, there is
+no unique identification for these devices. Therefore, explicit device
+instantiation is required for correct device identification and functionality
+(one device per address in this address range: 0x48..0x4f).
+
+The DS1625 is pin compatible and functionally equivalent with the DS1621,
+but the DS1621 is meant to replace it. The DS1631, DS1721, and DS1731 are
+also pin compatible with the DS1621 and provide multi-resolution support.
+
+Additionally, the DS1721 data sheet says the temperature flags (THF and TLF)
+are used internally, however, these flags do get set and cleared as the actual
+temperature crosses the min or max settings (which by default are set to 75
+and 80 degrees respectively).
+
+Temperature Conversion:
+-----------------------
+DS1621 - 750ms (older devices may take up to 1000ms)
+DS1625 - 500ms
+DS1631 - 93ms..750ms for 9..12 bits resolution, respectively.
+DS1721 - 93ms..750ms for 9..12 bits resolution, respectively.
+DS1731 - 93ms..750ms for 9..12 bits resolution, respectively.
+
+Note:
+On the DS1621, internal access to non-volatile registers may last for 10ms
+or less (unverified on the other devices).
+
+Temperature Accuracy:
+---------------------
+DS1621: +/- 0.5 degree Celsius (from 0 to +70 degrees)
+DS1625: +/- 0.5 degree Celsius (from 0 to +70 degrees)
+DS1631: +/- 0.5 degree Celsius (from 0 to +70 degrees)
+DS1721: +/- 1.0 degree Celsius (from -10 to +85 degrees)
+DS1731: +/- 1.0 degree Celsius (from -10 to +85 degrees)
+
+Note:
+Please refer to the device datasheets for accuracy at other temperatures.
+
+Temperature Resolution:
+-----------------------
+As mentioned above, the DS1631, DS1721, and DS1731 provide multi-resolution
+support, which is achieved via the R0 and R1 config register bits, where:
+
+R0..R1
+------
+ 0  0 => 9 bits, 0.5 degrees Celcius
+ 1  0 => 10 bits, 0.25 degrees Celcius
+ 0  1 => 11 bits, 0.125 degrees Celcius
+ 1  1 => 12 bits, 0.0625 degrees Celcius
+
+Note:
+At initial device power-on, the default resolution is set to 12-bits.
+
+The resolution mode for the DS1631, DS1721, or DS1731 can be changed from
+userspace, via the device 'update_interval' sysfs attribute. This attribute
+will normalize the range of input values to the device maximum resolution
+values defined in the datasheet as follows:
+
+Resolution    Conversion Time    Input Range
+ (C/LSB)       (msec)             (msec)
+------------------------------------------------
+0.5             93.75              0....94
+0.25            187.5              95...187
+0.125           375                188..375
+0.0625          750                376..infinity
+------------------------------------------------
+
+The following examples show how the 'update_interval' attribute can be
+used to change the conversion time:
+
+$ cat update_interval
+750
+$ cat temp1_input
+22062
+$
+$ echo 300 > update_interval
+$ cat update_interval
+375
+$ cat temp1_input
+22125
+$
+$ echo 150 > update_interval
+$ cat update_interval
+188
+$ cat temp1_input
+22250
+$
+$ echo 1 > update_interval
+$ cat update_interval
+94
+$ cat temp1_input
+22000
+$
+$ echo 1000 > update_interval
+$ cat update_interval
+750
+$ cat temp1_input
+22062
+$
+
+As shown, the ds1621 driver automatically adjusts the 'update_interval'
+user input, via a step function. Reading back the 'update_interval' value
+after a write operation provides the conversion time used by the device.
+
+Mathematically, the resolution can be derived from the conversion time
+via the following function:
+
+   g(x) = 0.5 * [minimum_conversion_time/x]
+
+where:
+ -> 'x' = the output from 'update_interval'
+ -> 'g(x)' = the resolution in degrees C per LSB.
+ -> 93.75ms = minimum conversion time
diff --git a/Documentation/hwmon/g762 b/Documentation/hwmon/g762
new file mode 100644 (file)
index 0000000..923db9c
--- /dev/null
@@ -0,0 +1,65 @@
+Kernel driver g762
+==================
+
+The GMT G762 Fan Speed PWM Controller is connected directly to a fan
+and performs closed-loop or open-loop control of the fan speed. Two
+modes - PWM or DC - are supported by the device.
+
+For additional information, a detailed datasheet is available at
+http://natisbad.org/NAS/ref/GMT_EDS-762_763-080710-0.2.pdf. sysfs
+bindings are described in Documentation/hwmon/sysfs-interface.
+
+The following entries are available to the user in a subdirectory of
+/sys/bus/i2c/drivers/g762/ to control the operation of the device.
+This can be done manually using the following entries but is usually
+done via a userland daemon like fancontrol.
+
+Note that those entries do not provide ways to setup the specific
+hardware characteristics of the system (reference clock, pulses per
+fan revolution, ...); Those can be modified via devicetree bindings
+documented in Documentation/devicetree/bindings/hwmon/g762.txt or
+using a specific platform_data structure in board initialization
+file (see include/linux/platform_data/g762.h).
+
+  fan1_target: set desired fan speed. This only makes sense in closed-loop
+            fan speed control (i.e. when pwm1_enable is set to 2).
+
+  fan1_input: provide current fan rotation value in RPM as reported by
+            the fan to the device.
+
+  fan1_div: fan clock divisor. Supported value are 1, 2, 4 and 8.
+
+  fan1_pulses: number of pulses per fan revolution. Supported values
+            are 2 and 4.
+
+  fan1_fault: reports fan failure, i.e. no transition on fan gear pin for
+            about 0.7s (if the fan is not voluntarily set off).
+
+  fan1_alarm: in closed-loop control mode, if fan RPM value is 25% out
+            of the programmed value for over 6 seconds 'fan1_alarm' is
+            set to 1.
+
+  pwm1_enable: set current fan speed control mode i.e. 1 for manual fan
+            speed control (open-loop) via pwm1 described below, 2 for
+            automatic fan speed control (closed-loop) via fan1_target
+            above.
+
+  pwm1_mode: set or get fan driving mode: 1 for PWM mode, 0 for DC mode.
+
+  pwm1: get or set PWM fan control value in open-loop mode. This is an
+            integer value between 0 and 255. 0 stops the fan, 255 makes
+            it run at full speed.
+
+Both in PWM mode ('pwm1_mode' set to 1) and DC mode ('pwm1_mode' set to 0),
+when current fan speed control mode is open-loop ('pwm1_enable' set to 1),
+the fan speed is programmed by setting a value between 0 and 255 via 'pwm1'
+entry (0 stops the fan, 255 makes it run at full speed). In closed-loop mode
+('pwm1_enable' set to 2), the expected rotation speed in RPM can be passed to
+the chip via 'fan1_target'. In closed-loop mode, the target speed is compared
+with current speed (available via 'fan1_input') by the device and a feedback
+is performed to match that target value. The fan speed value is computed
+based on the parameters associated with the physical characteristics of the
+system: a reference clock source frequency, a number of pulses per fan
+revolution, etc.
+
+Note that the driver will update its values at most once per second.
index 03444f9d833fa4a6e19bc1bec8385cc6f1a00df7..4223c2d3b508be75e5764e67fe979b23aec90cc7 100644 (file)
@@ -44,4 +44,6 @@ The INA226 monitors both a shunt voltage drop and bus supply voltage.
 The INA230 is a high or low side current shunt and power monitor with an I2C
 interface. The INA230 monitors both a shunt voltage drop and bus supply voltage.
 
-The shunt value in micro-ohms can be set via platform data.
+The shunt value in micro-ohms can be set via platform data or device tree.
+Please refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
+if the device tree is used.
index 1e6634f54c5019b45b6d663b6fd7cd7db9b23530..a370b2047cf3025b5a0c318af15c670a76bc41e3 100644 (file)
@@ -13,7 +13,7 @@ Supported adapters:
   * AMD SP5100 (SB700 derivative found on some server mainboards)
     Datasheet: Publicly available at the AMD website
     http://support.amd.com/us/Embedded_TechDocs/44413.pdf
-  * AMD Hudson-2
+  * AMD Hudson-2, CZ
     Datasheet: Not publicly available
   * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
     Datasheet: Publicly available at the SMSC website http://www.smsc.com
index 237acab169dd723b5a3f9ec3e40c79d55246f48a..2a5f0e14efa351a73ef1eb53c392ecef7c9b4f6b 100644 (file)
@@ -72,6 +72,7 @@ Code  Seq#(hex)       Include File            Comments
 0x06   all     linux/lp.h
 0x09   all     linux/raid/md_u.h
 0x10   00-0F   drivers/char/s390/vmcp.h
+0x10   10-1F   arch/s390/include/uapi/sclp_ctl.h
 0x12   all     linux/fs.h
                linux/blkpg.h
 0x1b   all     InfiniBand Subsystem    <http://infiniband.sourceforge.net/>
index 9c7fd988e299f0a9a5bcdec3d3db98efc837b2c0..bec123e466ae4662fde2e71959827febc0c8ddf7 100644 (file)
@@ -47,19 +47,12 @@ parameter. Optionally the size of the ELF header can also be passed
 when using the elfcorehdr=[size[KMG]@]offset[KMG] syntax.
 
 
-With the dump-capture kernel, you can access the memory image, or "old
-memory," in two ways:
-
-- Through a /dev/oldmem device interface. A capture utility can read the
-  device file and write out the memory in raw format. This is a raw dump
-  of memory. Analysis and capture tools must be intelligent enough to
-  determine where to look for the right information.
-
-- Through /proc/vmcore. This exports the dump as an ELF-format file that
-  you can write out using file copy commands such as cp or scp. Further,
-  you can use analysis tools such as the GNU Debugger (GDB) and the Crash
-  tool to debug the dump file. This method ensures that the dump pages are
-  correctly ordered.
+With the dump-capture kernel, you can access the memory image through
+/proc/vmcore. This exports the dump as an ELF-format file that you can
+write out using file copy commands such as cp or scp. Further, you can
+use analysis tools such as the GNU Debugger (GDB) and the Crash tool to
+debug the dump file. This method ensures that the dump pages are correctly
+ordered.
 
 
 Setup and Installation
@@ -423,18 +416,6 @@ the following command:
 
    cp /proc/vmcore <dump-file>
 
-You can also access dumped memory as a /dev/oldmem device for a linear
-and raw view. To create the device, use the following command:
-
-    mknod /dev/oldmem c 1 12
-
-Use the dd command with suitable options for count, bs, and skip to
-access specific portions of the dump.
-
-To see the entire memory, use the following command:
-
-   dd if=/dev/oldmem of=oldmem.001
-
 
 Analysis
 ========
index 2fe6e767b3d6013f3d1023c2e518b0466fa27e2f..25dc4a0e7e48096c342893bbc42d12b015e684a1 100644 (file)
@@ -1129,11 +1129,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        The builtin appraise policy appraises all files
                        owned by uid=0.
 
-       ima_audit=      [IMA]
-                       Format: { "0" | "1" }
-                       0 -- integrity auditing messages. (Default)
-                       1 -- enable informational integrity auditing messages.
-
        ima_hash=       [IMA]
                        Format: { "sha1" | "md5" }
                        default: "sha1"
@@ -1158,6 +1153,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        inport.irq=     [HW] Inport (ATI XL and Microsoft) busmouse driver
                        Format: <irq>
 
+       int_pln_enable  [x86] Enable power limit notification interrupt
+
+       integrity_audit=[IMA]
+                       Format: { "0" | "1" }
+                       0 -- basic integrity auditing messages. (Default)
+                       1 -- additional integrity auditing messages.
+
        intel_iommu=    [DMAR] Intel IOMMU driver (DMAR) option
                on
                        Enable intel iommu driver.
@@ -1456,6 +1458,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
                        * dump_id: dump IDENTIFY data.
 
+                       * atapi_dmadir: Enable ATAPI DMADIR bridge support
+
                        If there are multiple matching configurations changing
                        the same attribute, the last one is used.
 
@@ -3229,6 +3233,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        video=          [FB] Frame buffer configuration
                        See Documentation/fb/modedb.txt.
 
+       video.brightness_switch_enabled= [0,1]
+                       If set to 1, on receiving an ACPI notify event
+                       generated by hotkey, video driver will adjust brightness
+                       level and then send out the event to user space through
+                       the allocated input device; If set to 0, video driver
+                       will only send out the event without touching backlight
+                       brightness level.
+                       default: 1
+
        virtio_mmio.device=
                        [VMMIO] Memory mapped virtio (platform) device.
 
@@ -3341,6 +3354,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        that this also can be controlled per-workqueue for
                        workqueues visible under /sys/bus/workqueue/.
 
+       workqueue.power_efficient
+                       Per-cpu workqueues are generally preferred because
+                       they show better performance thanks to cache
+                       locality; unfortunately, per-cpu workqueues tend to
+                       be more power hungry than unbound workqueues.
+
+                       Enabling this makes the per-cpu workqueues which
+                       were observed to contribute significantly to power
+                       consumption unbound, leading to measurably lower
+                       power usage at the cost of small performance
+                       overhead.
+
+                       The default value of this parameter is determined by
+                       the config option CONFIG_WQ_POWER_EFFICIENT_DEFAULT.
+
        x2apic_phys     [X86-64,APIC] Use x2apic physical mode instead of
                        default x2apic cluster mode on platforms
                        supporting x2apic.
index cbf7ae412da4ab915a345582cf6b5fc93ca00ed5..5f39ef55c6f66699d9d8298b94ed18087d19e674 100644 (file)
@@ -157,6 +157,53 @@ RCU_SOFTIRQ:  Do at least one of the following:
                calls and by forcing both kernel threads and interrupts
                to execute elsewhere.
 
+Name: kworker/%u:%d%s (cpu, id, priority)
+Purpose: Execute workqueue requests
+To reduce its OS jitter, do any of the following:
+1.     Run your workload at a real-time priority, which will allow
+       preempting the kworker daemons.
+2.     Do any of the following needed to avoid jitter that your
+       application cannot tolerate:
+       a.      Build your kernel with CONFIG_SLUB=y rather than
+               CONFIG_SLAB=y, thus avoiding the slab allocator's periodic
+               use of each CPU's workqueues to run its cache_reap()
+               function.
+       b.      Avoid using oprofile, thus avoiding OS jitter from
+               wq_sync_buffer().
+       c.      Limit your CPU frequency so that a CPU-frequency
+               governor is not required, possibly enlisting the aid of
+               special heatsinks or other cooling technologies.  If done
+               correctly, and if you CPU architecture permits, you should
+               be able to build your kernel with CONFIG_CPU_FREQ=n to
+               avoid the CPU-frequency governor periodically running
+               on each CPU, including cs_dbs_timer() and od_dbs_timer().
+               WARNING:  Please check your CPU specifications to
+               make sure that this is safe on your particular system.
+       d.      It is not possible to entirely get rid of OS jitter
+               from vmstat_update() on CONFIG_SMP=y systems, but you
+               can decrease its frequency by writing a large value to
+               /proc/sys/vm/stat_interval.  The default value is HZ,
+               for an interval of one second.  Of course, larger values
+               will make your virtual-memory statistics update more
+               slowly.  Of course, you can also run your workload at
+               a real-time priority, thus preempting vmstat_update().
+       e.      If running on high-end powerpc servers, build with
+               CONFIG_PPC_RTAS_DAEMON=n.  This prevents the RTAS
+               daemon from running on each CPU every second or so.
+               (This will require editing Kconfig files and will defeat
+               this platform's RAS functionality.)  This avoids jitter
+               due to the rtas_event_scan() function.
+               WARNING:  Please check your CPU specifications to
+               make sure that this is safe on your particular system.
+       f.      If running on Cell Processor, build your kernel with
+               CBE_CPUFREQ_SPU_GOVERNOR=n to avoid OS jitter from
+               spu_gov_work().
+               WARNING:  Please check your CPU specifications to
+               make sure that this is safe on your particular system.
+       g.      If running on PowerMAC, build your kernel with
+               CONFIG_PMAC_RACKMETER=n to disable the CPU-meter,
+               avoiding OS jitter from rackmeter_do_timer().
+
 Name: rcuc/%u
 Purpose: Execute RCU callbacks in CONFIG_RCU_BOOST=y kernels.
 To reduce its OS jitter, do at least one of the following:
index 447fd4cd54ec834ed1810b050df9cc5aaa35438a..c5948c7d662a4123062ac317eefa570c7b63cdba 100644 (file)
@@ -203,15 +203,8 @@ using a certain resistor value - pull up and pull down - so that the pin has a
 stable value when nothing is driving the rail it is connected to, or when it's
 unconnected.
 
-Pin configuration can be programmed either using the explicit APIs described
-immediately below, or by adding configuration entries into the mapping table;
-see section "Board/machine configuration" below.
-
-For example, a platform may do the following to pull up a pin to VDD:
-
-#include <linux/pinctrl/consumer.h>
-
-ret = pin_config_set("foo-dev", "FOO_GPIO_PIN", PLATFORM_X_PULL_UP);
+Pin configuration can be programmed by adding configuration entries into the
+mapping table; see section "Board/machine configuration" below.
 
 The format and meaning of the configuration parameter, PLATFORM_X_PULL_UP
 above, is entirely defined by the pin controller driver.
@@ -350,6 +343,23 @@ chip b:
  - GPIO range : [48 .. 55]
  - pin range  : [64 .. 71]
 
+The above examples assume the mapping between the GPIOs and pins is
+linear. If the mapping is sparse or haphazard, an array of arbitrary pin
+numbers can be encoded in the range like this:
+
+static const unsigned range_pins[] = { 14, 1, 22, 17, 10, 8, 6, 2 };
+
+static struct pinctrl_gpio_range gpio_range = {
+       .name = "chip",
+       .id = 0,
+       .base = 32,
+       .pins = &range_pins,
+       .npins = ARRAY_SIZE(range_pins),
+       .gc = &chip;
+};
+
+In this case the pin_base property will be ignored.
+
 When GPIO-specific functions in the pin control subsystem are called, these
 ranges will be used to look up the appropriate pin controller by inspecting
 and matching the pin to the pin ranges across all controllers. When a
@@ -357,9 +367,9 @@ pin controller handling the matching range is found, GPIO-specific functions
 will be called on that specific pin controller.
 
 For all functionalities dealing with pin biasing, pin muxing etc, the pin
-controller subsystem will subtract the range's .base offset from the passed
-in gpio number, and add the ranges's .pin_base offset to retrive a pin number.
-After that, the subsystem passes it on to the pin control driver, so the driver
+controller subsystem will look up the corresponding pin number from the passed
+in gpio number, and use the range's internals to retrive a pin number. After
+that, the subsystem passes it on to the pin control driver, so the driver
 will get an pin number into its handled number range. Further it is also passed
 the range ID value, so that the pin controller knows which range it should
 deal with.
@@ -368,6 +378,7 @@ Calling pinctrl_add_gpio_range from pinctrl driver is DEPRECATED. Please see
 section 2.1 of Documentation/devicetree/bindings/gpio/gpio.txt on how to bind
 pinctrl and gpio drivers.
 
+
 PINMUX interfaces
 =================
 
@@ -1226,8 +1237,8 @@ setting up the config and muxing for the pins right before the device is
 probing, nevertheless orthogonal to the GPIO subsystem.
 
 But there are also situations where it makes sense for the GPIO subsystem
-to communicate directly with with the pinctrl subsystem, using the latter
-as a back-end. This is when the GPIO driver may call out to the functions
+to communicate directly with the pinctrl subsystem, using the latter as a
+back-end. This is when the GPIO driver may call out to the functions
 described in the section "Pin control interaction with the GPIO subsystem"
 above. This only involves per-pin multiplexing, and will be completely
 hidden behind the gpio_*() function namespace. In this case, the driver
index 79a2a58425ee1c1df7df251bc12aa40fdbeb0ecb..483632087788db0532718d2a26ab2283c379c38d 100644 (file)
@@ -7,7 +7,7 @@ one of the parameters.
 Two different PM QoS frameworks are available:
 1. PM QoS classes for cpu_dma_latency, network_latency, network_throughput.
 2. the per-device PM QoS framework provides the API to manage the per-device latency
-constraints.
+constraints and PM QoS flags.
 
 Each parameters have defined units:
  * latency: usec
@@ -86,13 +86,17 @@ To remove the user mode request for a target value simply close the device
 node.
 
 
-2. PM QoS per-device latency framework
+2. PM QoS per-device latency and flags framework
+
+For each device, there are two lists of PM QoS requests. One is maintained
+along with the aggregated target of latency value and the other is for PM QoS
+flags. Values are updated in response to changes of the request list.
+
+Target latency value is simply the minimum of the request values held in the
+parameter list elements.  The PM QoS flags aggregate value is a gather (bitwise
+OR) of all list elements' values. Two device PM QoS flags are defined currently:
+PM_QOS_FLAG_NO_POWER_OFF and PM_QOS_FLAG_REMOTE_WAKEUP.
 
-For each device a list of performance requests is maintained along with
-an aggregated target value.  The aggregated target value is updated with
-changes to the request list or elements of the list.  Typically the
-aggregated target value is simply the max or min of the request values held
-in the parameter list elements.
 Note: the aggregated target value is implemented as an atomic variable so that
 reading the aggregated value does not require any locking mechanism.
 
@@ -119,6 +123,38 @@ the request.
 s32 dev_pm_qos_read_value(device):
 Returns the aggregated value for a given device's constraints list.
 
+enum pm_qos_flags_status dev_pm_qos_flags(device, mask)
+Check PM QoS flags of the given device against the given mask of flags.
+The meaning of the return values is as follows:
+       PM_QOS_FLAGS_ALL: All flags from the mask are set
+       PM_QOS_FLAGS_SOME: Some flags from the mask are set
+       PM_QOS_FLAGS_NONE: No flags from the mask are set
+       PM_QOS_FLAGS_UNDEFINED: The device's PM QoS structure has not been
+                       initialized or the list of requests is empty.
+
+int dev_pm_qos_add_ancestor_request(dev, handle, value)
+Add a PM QoS request for the first direct ancestor of the given device whose
+power.ignore_children flag is unset.
+
+int dev_pm_qos_expose_latency_limit(device, value)
+Add a request to the device's PM QoS list of latency constraints and create
+a sysfs attribute pm_qos_resume_latency_us under the device's power directory
+allowing user space to manipulate that request.
+
+void dev_pm_qos_hide_latency_limit(device)
+Drop the request added by dev_pm_qos_expose_latency_limit() from the device's
+PM QoS list of latency constraints and remove sysfs attribute pm_qos_resume_latency_us
+from the device's power directory.
+
+int dev_pm_qos_expose_flags(device, value)
+Add a request to the device's PM QoS list of flags and create sysfs attributes
+pm_qos_no_power_off and pm_qos_remote_wakeup under the device's power directory
+allowing user space to change these flags' value.
+
+void dev_pm_qos_hide_flags(device)
+Drop the request added by dev_pm_qos_expose_flags() from the device's PM QoS list
+of flags and remove sysfs attributes pm_qos_no_power_off and pm_qos_remote_wakeup
+under the device's power directory.
 
 Notification mechanisms:
 The per-device PM QoS framework has 2 different and distinct notification trees:
index 6c9f5d9aa115d04ee86c5297f5e3051bee31c0b9..71d8fe4e75d3e5301e25037a28d91600d633dba7 100644 (file)
@@ -144,8 +144,12 @@ The action performed by the idle callback is totally dependent on the subsystem
 (or driver) in question, but the expected and recommended action is to check
 if the device can be suspended (i.e. if all of the conditions necessary for
 suspending the device are satisfied) and to queue up a suspend request for the
-device in that case.  The value returned by this callback is ignored by the PM
-core.
+device in that case.  If there is no idle callback, or if the callback returns
+0, then the PM core will attempt to carry out a runtime suspend of the device;
+in essence, it will call pm_runtime_suspend() directly.  To prevent this (for
+example, if the callback routine has started a delayed suspend), the routine
+should return a non-zero value.  Negative error return codes are ignored by the
+PM core.
 
 The helper functions provided by the PM core, described in Section 4, guarantee
 that the following constraints are met with respect to runtime PM callbacks for
@@ -301,9 +305,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
       removing the device from device hierarchy
 
   int pm_runtime_idle(struct device *dev);
-    - execute the subsystem-level idle callback for the device; returns 0 on
-      success or error code on failure, where -EINPROGRESS means that
-      ->runtime_idle() is already being executed
+    - execute the subsystem-level idle callback for the device; returns an
+      error code on failure, where -EINPROGRESS means that ->runtime_idle() is
+      already being executed; if there is no callback or the callback returns 0
+      then run pm_runtime_suspend(dev) and return its result
 
   int pm_runtime_suspend(struct device *dev);
     - execute the subsystem-level suspend callback for the device; returns 0 on
@@ -660,11 +665,6 @@ Subsystems may wish to conserve code space by using the set of generic power
 management callbacks provided by the PM core, defined in
 driver/base/power/generic_ops.c:
 
-  int pm_generic_runtime_idle(struct device *dev);
-    - invoke the ->runtime_idle() callback provided by the driver of this
-      device, if defined, and call pm_runtime_suspend() for this device if the
-      return value is 0 or the callback is not defined
-
   int pm_generic_runtime_suspend(struct device *dev);
     - invoke the ->runtime_suspend() callback provided by the driver of this
       device and return its result, or return -EINVAL if not defined
diff --git a/Documentation/power/video_extension.txt b/Documentation/power/video_extension.txt
deleted file mode 100644 (file)
index b2f9b15..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-ACPI video extensions
-~~~~~~~~~~~~~~~~~~~~~
-
-This driver implement the ACPI Extensions For Display Adapters for
-integrated graphics devices on motherboard, as specified in ACPI 2.0
-Specification, Appendix B, allowing to perform some basic control like
-defining the video POST device, retrieving EDID information or to
-setup a video output, etc.  Note that this is an ref. implementation
-only.  It may or may not work for your integrated video device.
-
-Interfaces exposed to userland through /proc/acpi/video:
-
-VGA/info : display the supported video bus device capability like Video ROM, CRT/LCD/TV.
-VGA/ROM :  Used to get a copy of the display devices' ROM data (up to 4k).
-VGA/POST_info : Used to determine what options are implemented.
-VGA/POST : Used to get/set POST device.
-VGA/DOS : Used to get/set ownership of output switching:
-       Please refer ACPI spec B.4.1 _DOS
-VGA/CRT : CRT output
-VGA/LCD : LCD output
-VGA/TVO : TV output
-VGA/*/brightness : Used to get/set brightness of output device
-
-Notify event through /proc/acpi/event:
-
-#define ACPI_VIDEO_NOTIFY_SWITCH        0x80
-#define ACPI_VIDEO_NOTIFY_PROBE         0x81
-#define ACPI_VIDEO_NOTIFY_CYCLE         0x82
-#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT   0x83
-#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT   0x84
-
-#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS      0x82
-#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS        0x83
-#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS        0x84
-#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS       0x85
-#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF           0x86
-
index a9c16c979da215d35d774e8e739848fe535acdd1..717f5aa388b171bcdffa8115191491aac64f4bd2 100644 (file)
@@ -73,28 +73,44 @@ data structure. This structure includes lists of all devices and local master
 ports that form the same network. It also contains a pointer to the default
 master port that is used to communicate with devices within the network.
 
+2.5 Device Drivers
+
+RapidIO device-specific drivers follow Linux Kernel Driver Model and are
+intended to support specific RapidIO devices attached to the RapidIO network.
+
+2.6 Subsystem Interfaces
+
+RapidIO interconnect specification defines features that may be used to provide
+one or more common service layers for all participating RapidIO devices. These
+common services may act separately from device-specific drivers or be used by
+device-specific drivers. Example of such service provider is the RIONET driver
+which implements Ethernet-over-RapidIO interface. Because only one driver can be
+registered for a device, all common RapidIO services have to be registered as
+subsystem interfaces. This allows to have multiple common services attached to
+the same device without blocking attachment of a device-specific driver.
+
 3. Subsystem Initialization
 ---------------------------
 
 In order to initialize the RapidIO subsystem, a platform must initialize and
 register at least one master port within the RapidIO network. To register mport
-within the subsystem controller driver initialization code calls function
+within the subsystem controller driver's initialization code calls function
 rio_register_mport() for each available master port.
 
-RapidIO subsystem uses subsys_initcall() or device_initcall() to perform
-controller initialization (depending on controller device type).
-
 After all active master ports are registered with a RapidIO subsystem,
 an enumeration and/or discovery routine may be called automatically or
 by user-space command.
 
+RapidIO subsystem can be configured to be built as a statically linked or
+modular component of the kernel (see details below).
+
 4. Enumeration and Discovery
 ----------------------------
 
 4.1 Overview
 ------------
 
-RapidIO subsystem configuration options allow users to specify enumeration and
+RapidIO subsystem configuration options allow users to build enumeration and
 discovery methods as statically linked components or loadable modules.
 An enumeration/discovery method implementation and available input parameters
 define how any given method can be attached to available RapidIO mports:
@@ -115,8 +131,8 @@ several methods to initiate an enumeration and/or discovery process:
   endpoint waits for enumeration to be completed. If the specified timeout
   expires the discovery process is terminated without obtaining RapidIO network
   information. NOTE: a timed out discovery process may be restarted later using
-  a user-space command as it is described later if the given endpoint was
-  enumerated successfully.
+  a user-space command as it is described below (if the given endpoint was
+  enumerated successfully).
 
   (b) Statically linked enumeration and discovery process can be started by
   a command from user space. This initiation method provides more flexibility
@@ -138,15 +154,42 @@ When a network scan process is started it calls an enumeration or discovery
 routine depending on the configured role of a master port: host or agent.
 
 Enumeration is performed by a master port if it is configured as a host port by
-assigning a host device ID greater than or equal to zero. A host device ID is
-assigned to a master port through the kernel command line parameter "riohdid=",
-or can be configured in a platform-specific manner. If the host device ID for
-a specific master port is set to -1, the discovery process will be performed
-for it.
+assigning a host destination ID greater than or equal to zero. The host
+destination ID can be assigned to a master port using various methods depending
+on RapidIO subsystem build configuration:
+
+  (a) For a statically linked RapidIO subsystem core use command line parameter
+  "rapidio.hdid=" with a list of destination ID assignments in order of mport
+  device registration. For example, in a system with two RapidIO controllers
+  the command line parameter "rapidio.hdid=-1,7" will result in assignment of
+  the host destination ID=7 to the second RapidIO controller, while the first
+  one will be assigned destination ID=-1.
+
+  (b) If the RapidIO subsystem core is built as a loadable module, in addition
+  to the method shown above, the host destination ID(s) can be specified using
+  traditional methods of passing module parameter "hdid=" during its loading:
+  - from command line: "modprobe rapidio hdid=-1,7", or
+  - from modprobe configuration file using configuration command "options",
+    like in this example: "options rapidio hdid=-1,7". An example of modprobe
+    configuration file is provided in the section below.
+
+  NOTES:
+  (i) if "hdid=" parameter is omitted all available mport will be assigned
+  destination ID = -1;
+  (ii) the "hdid=" parameter in systems with multiple mports can have
+  destination ID assignments omitted from the end of list (default = -1).
+
+If the host device ID for a specific master port is set to -1, the discovery
+process will be performed for it.
 
 The enumeration and discovery routines use RapidIO maintenance transactions
 to access the configuration space of devices.
 
+NOTE: If RapidIO switch-specific device drivers are built as loadable modules
+they must be loaded before enumeration/discovery process starts.
+This requirement is cased by the fact that enumeration/discovery methods invoke
+vendor-specific callbacks on early stages.
+
 4.2 Automatic Start of Enumeration and Discovery
 ------------------------------------------------
 
@@ -266,7 +309,36 @@ method's module initialization routine calls rio_register_scan() to attach
 an enumerator to a specified mport device (or devices). The basic enumerator
 implementation demonstrates this process.
 
-5. References
+4.6 Using Loadable RapidIO Switch Drivers
+-----------------------------------------
+
+In the case when RapidIO switch drivers are built as loadable modules a user
+must ensure that they are loaded before the enumeration/discovery starts.
+This process can be automated by specifying pre- or post- dependencies in the
+RapidIO-specific modprobe configuration file as shown in the example below.
+
+  File /etc/modprobe.d/rapidio.conf:
+  ----------------------------------
+
+  # Configure RapidIO subsystem modules
+
+  # Set enumerator host destination ID (overrides kernel command line option)
+  options rapidio hdid=-1,2
+
+  # Load RapidIO switch drivers immediately after rapidio core module was loaded
+  softdep rapidio post: idt_gen2 idtcps tsi57x
+
+  # OR :
+
+  # Load RapidIO switch drivers just before rio-scan enumerator module is loaded
+  softdep rio-scan pre: idt_gen2 idtcps tsi57x
+
+  --------------------------
+
+NOTE: In the example above, one of "softdep" commands must be removed or
+commented out to keep required module loading sequence.
+
+A. References
 -------------
 
 [1] RapidIO Trade Association. RapidIO Interconnect Specifications.
index 19878179da4c78657967868fc36ce2abe35aae94..271438c0617f9be8b1ea2d23a2ac17eedd483bd3 100644 (file)
@@ -40,6 +40,7 @@ device_rev - returns the device revision level
              (see 4.1 for switch specific details)
    lprev   - returns name of previous device (switch) on the path to the device
              that that owns this attribute
+  modalias - returns the device modalias
 
 In addition to the files listed above, each device has a binary attribute file
 that allows read/write access to the device configuration registers using
index 33ed8007a8458893572046e3d5acf2248ca39e8e..a5bcd7f5c33fb4d1d818c35b2044b0382179d013 100644 (file)
@@ -384,7 +384,7 @@ priority back.
 __rt_mutex_adjust_prio examines the result of rt_mutex_getprio, and if the
 result does not equal the task's current priority, then rt_mutex_setprio
 is called to adjust the priority of the task to the new priority.
-Note that rt_mutex_setprio is defined in kernel/sched.c to implement the
+Note that rt_mutex_setprio is defined in kernel/sched/core.c to implement the
 actual change in priority.
 
 It is interesting to note that __rt_mutex_adjust_prio can either increase
index 32aa4002de4a9fbd9fe64045119f811df47886ae..596b60c08b7451a9739d22aa2a29cb3c5c2559c9 100644 (file)
@@ -153,9 +153,10 @@ since_epoch:        The number of seconds since the epoch according to the RTC
 time:           RTC-provided time
 wakealarm:      The time at which the clock will generate a system wakeup
                 event. This is a one shot wakeup event, so must be reset
-                after wake if a daily wakeup is required. Format is either
-                seconds since the epoch or, if there's a leading +, seconds
-                in the future.
+                after wake if a daily wakeup is required. Format is seconds since
+                the epoch by default, or if there's a leading +, seconds in the
+                future, or if there is a leading +=, seconds ahead of the current
+                alarm.
 
 IOCTL INTERFACE
 ---------------
index 443f0c76bab4ea93ed702ceb18c6a207f489c192..4af80b1c05aa9df0a294f79d8f0439f766ee9fd0 100644 (file)
@@ -25,7 +25,7 @@ is treated as one entity. The load of a group is defined as the sum of the
 load of each of its member CPUs, and only when the load of a group becomes
 out of balance are tasks moved between groups.
 
-In kernel/sched.c, trigger_load_balance() is run periodically on each CPU
+In kernel/sched/core.c, trigger_load_balance() is run periodically on each CPU
 through scheduler_tick(). It raises a softirq after the next regularly scheduled
 rebalancing event for the current runqueue has arrived. The actual load
 balancing workhorse, run_rebalance_domains()->rebalance_domains(), is then run
@@ -62,7 +62,7 @@ struct sched_domain fields, SD_FLAG_*, SD_*_INIT to get an idea of
 the specifics and what to tune.
 
 Architectures may retain the regular override the default SD_*_INIT flags
-while using the generic domain builder in kernel/sched.c if they wish to
+while using the generic domain builder in kernel/sched/core.c if they wish to
 retain the traditional SMT->SMP->NUMA topology (or some subset of that). This
 can be done by #define'ing ARCH_HASH_SCHED_TUNE.
 
index 77d68e23b2476f05993be8f9897b76f3bf08edea..809d72b8eff1a8217dc5e7666f3e895019421f9c 100644 (file)
@@ -21,41 +21,41 @@ ALC267/268
 ==========
   inv-dmic     Inverted internal mic workaround
 
-ALC269/270/275/276/280/282
+ALC269/270/275/276/28x/29x
 ======
-  laptop-amic  Laptops with analog-mic input
-  laptop-dmic  Laptops with digital-mic input
-  alc269-dmic  Enable ALC269(VA) digital mic workaround
-  alc271-dmic  Enable ALC271X digital mic workaround
-  inv-dmic     Inverted internal mic workaround
-  lenovo-dock   Enables docking station I/O for some Lenovos
+  laptop-amic          Laptops with analog-mic input
+  laptop-dmic          Laptops with digital-mic input
+  alc269-dmic          Enable ALC269(VA) digital mic workaround
+  alc271-dmic          Enable ALC271X digital mic workaround
+  inv-dmic             Inverted internal mic workaround
+  lenovo-dock          Enables docking station I/O for some Lenovos
   dell-headset-multi   Headset jack, which can also be used as mic-in
   dell-headset-dock    Headset jack (without mic-in), and also dock I/O
 
-ALC662/663/272
+ALC66x/67x/892
 ==============
-  mario                Chromebook mario model fixup
-  asus-mode1   ASUS
-  asus-mode2   ASUS
-  asus-mode3   ASUS
-  asus-mode4   ASUS
-  asus-mode5   ASUS
-  asus-mode6   ASUS
-  asus-mode7   ASUS
-  asus-mode8   ASUS
-  inv-dmic     Inverted internal mic workaround
+  mario                        Chromebook mario model fixup
+  asus-mode1           ASUS
+  asus-mode2           ASUS
+  asus-mode3           ASUS
+  asus-mode4           ASUS
+  asus-mode5           ASUS
+  asus-mode6           ASUS
+  asus-mode7           ASUS
+  asus-mode8           ASUS
+  inv-dmic             Inverted internal mic workaround
   dell-headset-multi   Headset jack, which can also be used as mic-in
 
 ALC680
 ======
   N/A
 
-ALC882/883/885/888/889
+ALC88x/898/1150
 ======================
   acer-aspire-4930g    Acer Aspire 4930G/5930G/6530G/6930G/7730G
   acer-aspire-8930g    Acer Aspire 8330G/6935G
   acer-aspire          Acer Aspire others
-  inv-dmic     Inverted internal mic workaround
+  inv-dmic             Inverted internal mic workaround
   no-primary-hp                VAIO Z/VGC-LN51JGB workaround (for fixed speaker DAC)
 
 ALC861/660
index 9dbe885ecd8d130e8a1e0300f05686dea59440c6..97eaf5727178f3b04dea397f0805ab2509d14635 100644 (file)
@@ -137,7 +137,7 @@ don't block on each other (and thus there is no dead-lock wrt interrupts.
 But when you do the write-lock, you have to use the irq-safe version. 
 
 For an example of being clever with rw-locks, see the "waitqueue_lock" 
-handling in kernel/sched.c - nothing ever _changes_ a wait-queue from
+handling in kernel/sched/core.c - nothing ever _changes_ a wait-queue from
 within an interrupt, they only read the queue in order to know whom to
 wake up. So read-locks are safe (which is good: they are very common
 indeed), while write-locks need to protect themselves against interrupts.
index ccd42589e124c0d7233bbba41bcf154e7ae7d87f..ab7d16efa96bf78bbfdddc029eb40b82da1e03fe 100644 (file)
@@ -70,12 +70,12 @@ show up in /proc/sys/kernel:
 - shmall
 - shmmax                      [ sysv ipc ]
 - shmmni
-- softlockup_thresh
 - stop-a                      [ SPARC only ]
 - sysrq                       ==> Documentation/sysrq.txt
 - tainted
 - threads-max
 - unknown_nmi_panic
+- watchdog_thresh
 - version
 
 ==============================================================
@@ -427,6 +427,32 @@ This file shows up if CONFIG_DEBUG_STACKOVERFLOW is enabled.
 
 ==============================================================
 
+perf_cpu_time_max_percent:
+
+Hints to the kernel how much CPU time it should be allowed to
+use to handle perf sampling events.  If the perf subsystem
+is informed that its samples are exceeding this limit, it
+will drop its sampling frequency to attempt to reduce its CPU
+usage.
+
+Some perf sampling happens in NMIs.  If these samples
+unexpectedly take too long to execute, the NMIs can become
+stacked up next to each other so much that nothing else is
+allowed to execute.
+
+0: disable the mechanism.  Do not monitor or correct perf's
+   sampling rate no matter how CPU time it takes.
+
+1-100: attempt to throttle perf's sample rate to this
+   percentage of CPU.  Note: the kernel calculates an
+   "expected" length of each sample event.  100 here means
+   100% of that expected length.  Even if this is set to
+   100, you may still see sample throttling if this
+   length is exceeded.  Set to 0 if you truly do not care
+   how much CPU is consumed.
+
+==============================================================
+
 
 pid_max:
 
@@ -604,15 +630,6 @@ without users and with a dead originative process will be destroyed.
 
 ==============================================================
 
-softlockup_thresh:
-
-This value can be used to lower the softlockup tolerance threshold.  The
-default threshold is 60 seconds.  If a cpu is locked up for 60 seconds,
-the kernel complains.  Valid values are 1-60 seconds.  Setting this
-tunable to zero will disable the softlockup detection altogether.
-
-==============================================================
-
 tainted:
 
 Non-zero if the kernel has been tainted.  Numeric values, which
@@ -648,3 +665,16 @@ that time, kernel debugging information is displayed on console.
 
 NMI switch that most IA32 servers have fires unknown NMI up, for
 example.  If a system hangs up, try pressing the NMI switch.
+
+==============================================================
+
+watchdog_thresh:
+
+This value can be used to control the frequency of hrtimer and NMI
+events and the soft and hard lockup thresholds. The default threshold
+is 10 seconds.
+
+The softlockup threshold is (2 * watchdog_thresh). Setting this
+tunable to zero will disable lockup detection altogether.
+
+==============================================================
index 5b5322024067b2e396e4413eeb4a0fbda728562a..88697584242b604945dac74ff8f3ff2a11df9c36 100644 (file)
@@ -7,21 +7,59 @@ efficiency and reducing OS jitter.  Reducing OS jitter is important for
 some types of computationally intensive high-performance computing (HPC)
 applications and for real-time applications.
 
-There are two main contexts in which the number of scheduling-clock
-interrupts can be reduced compared to the old-school approach of sending
-a scheduling-clock interrupt to all CPUs every jiffy whether they need
-it or not (CONFIG_HZ_PERIODIC=y or CONFIG_NO_HZ=n for older kernels):
+There are three main ways of managing scheduling-clock interrupts
+(also known as "scheduling-clock ticks" or simply "ticks"):
 
-1.     Idle CPUs (CONFIG_NO_HZ_IDLE=y or CONFIG_NO_HZ=y for older kernels).
+1.     Never omit scheduling-clock ticks (CONFIG_HZ_PERIODIC=y or
+       CONFIG_NO_HZ=n for older kernels).  You normally will -not-
+       want to choose this option.
 
-2.     CPUs having only one runnable task (CONFIG_NO_HZ_FULL=y).
+2.     Omit scheduling-clock ticks on idle CPUs (CONFIG_NO_HZ_IDLE=y or
+       CONFIG_NO_HZ=y for older kernels).  This is the most common
+       approach, and should be the default.
 
-These two cases are described in the following two sections, followed
+3.     Omit scheduling-clock ticks on CPUs that are either idle or that
+       have only one runnable task (CONFIG_NO_HZ_FULL=y).  Unless you
+       are running realtime applications or certain types of HPC
+       workloads, you will normally -not- want this option.
+
+These three cases are described in the following three sections, followed
 by a third section on RCU-specific considerations and a fourth and final
 section listing known issues.
 
 
-IDLE CPUs
+NEVER OMIT SCHEDULING-CLOCK TICKS
+
+Very old versions of Linux from the 1990s and the very early 2000s
+are incapable of omitting scheduling-clock ticks.  It turns out that
+there are some situations where this old-school approach is still the
+right approach, for example, in heavy workloads with lots of tasks
+that use short bursts of CPU, where there are very frequent idle
+periods, but where these idle periods are also quite short (tens or
+hundreds of microseconds).  For these types of workloads, scheduling
+clock interrupts will normally be delivered any way because there
+will frequently be multiple runnable tasks per CPU.  In these cases,
+attempting to turn off the scheduling clock interrupt will have no effect
+other than increasing the overhead of switching to and from idle and
+transitioning between user and kernel execution.
+
+This mode of operation can be selected using CONFIG_HZ_PERIODIC=y (or
+CONFIG_NO_HZ=n for older kernels).
+
+However, if you are instead running a light workload with long idle
+periods, failing to omit scheduling-clock interrupts will result in
+excessive power consumption.  This is especially bad on battery-powered
+devices, where it results in extremely short battery lifetimes.  If you
+are running light workloads, you should therefore read the following
+section.
+
+In addition, if you are running either a real-time workload or an HPC
+workload with short iterations, the scheduling-clock interrupts can
+degrade your applications performance.  If this describes your workload,
+you should read the following two sections.
+
+
+OMIT SCHEDULING-CLOCK TICKS FOR IDLE CPUs
 
 If a CPU is idle, there is little point in sending it a scheduling-clock
 interrupt.  After all, the primary purpose of a scheduling-clock interrupt
@@ -59,10 +97,12 @@ By default, CONFIG_NO_HZ_IDLE=y kernels boot with "nohz=on", enabling
 dyntick-idle mode.
 
 
-CPUs WITH ONLY ONE RUNNABLE TASK
+OMIT SCHEDULING-CLOCK TICKS FOR CPUs WITH ONLY ONE RUNNABLE TASK
 
 If a CPU has only one runnable task, there is little point in sending it
 a scheduling-clock interrupt because there is no other task to switch to.
+Note that omitting scheduling-clock ticks for CPUs with only one runnable
+task implies also omitting them for idle CPUs.
 
 The CONFIG_NO_HZ_FULL=y Kconfig option causes the kernel to avoid
 sending scheduling-clock interrupts to CPUs with a single runnable task,
@@ -238,6 +278,11 @@ o  Adaptive-ticks does not do anything unless there is only one
        single runnable SCHED_FIFO task and multiple runnable SCHED_OTHER
        tasks, even though these interrupts are unnecessary.
 
+       And even when there are multiple runnable tasks on a given CPU,
+       there is little point in interrupting that CPU until the current
+       running task's timeslice expires, which is almost always way
+       longer than the time of the next scheduling-clock interrupt.
+
        Better handling of these sorts of situations is future work.
 
 o      A reboot is required to reconfigure both adaptive idle and RCU
@@ -268,6 +313,16 @@ o  Unless all CPUs are idle, at least one CPU must keep the
        scheduling-clock interrupt going in order to support accurate
        timekeeping.
 
-o      If there are adaptive-ticks CPUs, there will be at least one
-       CPU keeping the scheduling-clock interrupt going, even if all
-       CPUs are otherwise idle.
+o      If there might potentially be some adaptive-ticks CPUs, there
+       will be at least one CPU keeping the scheduling-clock interrupt
+       going, even if all CPUs are otherwise idle.
+
+       Better handling of this situation is ongoing work.
+
+o      Some process-handling operations still require the occasional
+       scheduling-clock tick.  These operations include calculating CPU
+       load, maintaining sched average, computing CFS entity vruntime,
+       computing avenrun, and carrying out load balancing.  They are
+       currently accommodated by scheduling-clock tick every second
+       or so.  On-going work will eliminate the need even for these
+       infrequent scheduling-clock ticks.
diff --git a/Documentation/trace/events-nmi.txt b/Documentation/trace/events-nmi.txt
new file mode 100644 (file)
index 0000000..c03c8c8
--- /dev/null
@@ -0,0 +1,43 @@
+NMI Trace Events
+
+These events normally show up here:
+
+       /sys/kernel/debug/tracing/events/nmi
+
+--
+
+nmi_handler:
+
+You might want to use this tracepoint if you suspect that your
+NMI handlers are hogging large amounts of CPU time.  The kernel
+will warn if it sees long-running handlers:
+
+       INFO: NMI handler took too long to run: 9.207 msecs
+
+and this tracepoint will allow you to drill down and get some
+more details.
+
+Let's say you suspect that perf_event_nmi_handler() is causing
+you some problems and you only want to trace that handler
+specifically.  You need to find its address:
+
+       $ grep perf_event_nmi_handler /proc/kallsyms
+       ffffffff81625600 t perf_event_nmi_handler
+
+Let's also say you are only interested in when that function is
+really hogging a lot of CPU time, like a millisecond at a time.
+Note that the kernel's output is in milliseconds, but the input
+to the filter is in nanoseconds!  You can filter on 'delta_ns':
+
+cd /sys/kernel/debug/tracing/events/nmi/nmi_handler
+echo 'handler==0xffffffff81625600 && delta_ns>1000000' > filter
+echo 1 > enable
+
+Your output would then look like:
+
+$ cat /sys/kernel/debug/tracing/trace_pipe
+<idle>-0     [000] d.h3   505.397558: nmi_handler: perf_event_nmi_handler() delta_ns: 3236765 handled: 1
+<idle>-0     [000] d.h3   505.805893: nmi_handler: perf_event_nmi_handler() delta_ns: 3174234 handled: 1
+<idle>-0     [000] d.h3   506.158206: nmi_handler: perf_event_nmi_handler() delta_ns: 3084642 handled: 1
+<idle>-0     [000] d.h3   506.334346: nmi_handler: perf_event_nmi_handler() delta_ns: 3080351 handled: 1
+
index e1498ff8cf94df2bf5a4e14fb93c04c94444e803..3bd33b8dc7c460f71885b169077f3df9ec2adaac 100644 (file)
@@ -63,3 +63,34 @@ power_domain_target  "%s state=%lu cpu_id=%lu"
 The first parameter gives the power domain name (e.g. "mpu_pwrdm").
 The second parameter is the power domain target state.
 
+4. PM QoS events
+================
+The PM QoS events are used for QoS add/update/remove request and for
+target/flags update.
+
+pm_qos_add_request                 "pm_qos_class=%s value=%d"
+pm_qos_update_request              "pm_qos_class=%s value=%d"
+pm_qos_remove_request              "pm_qos_class=%s value=%d"
+pm_qos_update_request_timeout      "pm_qos_class=%s value=%d, timeout_us=%ld"
+
+The first parameter gives the QoS class name (e.g. "CPU_DMA_LATENCY").
+The second parameter is value to be added/updated/removed.
+The third parameter is timeout value in usec.
+
+pm_qos_update_target               "action=%s prev_value=%d curr_value=%d"
+pm_qos_update_flags                "action=%s prev_value=0x%x curr_value=0x%x"
+
+The first parameter gives the QoS action name (e.g. "ADD_REQ").
+The second parameter is the previous QoS value.
+The third parameter is the current QoS value to update.
+
+And, there are also events used for device PM QoS add/update/remove request.
+
+dev_pm_qos_add_request             "device=%s type=%s new_value=%d"
+dev_pm_qos_update_request          "device=%s type=%s new_value=%d"
+dev_pm_qos_remove_request          "device=%s type=%s new_value=%d"
+
+The first parameter gives the device name which tries to add/update/remove
+QoS requests.
+The second parameter gives the request type (e.g. "DEV_PM_QOS_LATENCY").
+The third parameter is value to be added/updated/removed.
index 5f91eda9164713faa1f66a613a998d36b44f5191..66dd2aa53ba4c762bb4d86c07f4cd32cb8a1fddb 100644 (file)
@@ -280,7 +280,7 @@ kvm_run' (see below).
 4.11 KVM_GET_REGS
 
 Capability: basic
-Architectures: all except ARM
+Architectures: all except ARM, arm64
 Type: vcpu ioctl
 Parameters: struct kvm_regs (out)
 Returns: 0 on success, -1 on error
@@ -301,7 +301,7 @@ struct kvm_regs {
 4.12 KVM_SET_REGS
 
 Capability: basic
-Architectures: all except ARM
+Architectures: all except ARM, arm64
 Type: vcpu ioctl
 Parameters: struct kvm_regs (in)
 Returns: 0 on success, -1 on error
@@ -587,7 +587,7 @@ struct kvm_fpu {
 4.24 KVM_CREATE_IRQCHIP
 
 Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64, ARM
+Architectures: x86, ia64, ARM, arm64
 Type: vm ioctl
 Parameters: none
 Returns: 0 on success, -1 on error
@@ -595,14 +595,14 @@ Returns: 0 on success, -1 on error
 Creates an interrupt controller model in the kernel.  On x86, creates a virtual
 ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a
 local APIC.  IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23
-only go to the IOAPIC.  On ia64, a IOSAPIC is created. On ARM, a GIC is
+only go to the IOAPIC.  On ia64, a IOSAPIC is created. On ARM/arm64, a GIC is
 created.
 
 
 4.25 KVM_IRQ_LINE
 
 Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64, arm
+Architectures: x86, ia64, arm, arm64
 Type: vm ioctl
 Parameters: struct kvm_irq_level
 Returns: 0 on success, -1 on error
@@ -612,9 +612,10 @@ On some architectures it is required that an interrupt controller model has
 been previously created with KVM_CREATE_IRQCHIP.  Note that edge-triggered
 interrupts require the level to be set to 1 and then back to 0.
 
-ARM can signal an interrupt either at the CPU level, or at the in-kernel irqchip
-(GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for
-specific cpus.  The irq field is interpreted like this:
+ARM/arm64 can signal an interrupt either at the CPU level, or at the
+in-kernel irqchip (GIC), and for in-kernel irqchip can tell the GIC to
+use PPIs designated for specific cpus.  The irq field is interpreted
+like this:
 
  Â bits:  | 31 ... 24 | 23  ... 16 | 15    ...    0 |
   field: | irq_type  | vcpu_index |     irq_id     |
@@ -1831,6 +1832,22 @@ ARM 32-bit VFP control registers have the following id bit patterns:
 ARM 64-bit FP registers have the following id bit patterns:
   0x4030 0000 0012 0 <regno:12>
 
+
+arm64 registers are mapped using the lower 32 bits. The upper 16 of
+that is the register group type, or coprocessor number:
+
+arm64 core/FP-SIMD registers have the following id bit patterns. Note
+that the size of the access is variable, as the kvm_regs structure
+contains elements ranging from 32 to 128 bits. The index is a 32bit
+value in the kvm_regs structure seen as a 32bit array.
+  0x60x0 0000 0010 <index into the kvm_regs struct:16>
+
+arm64 CCSIDR registers are demultiplexed by CSSELR value:
+  0x6020 0000 0011 00 <csselr:8>
+
+arm64 system registers have the following id bit patterns:
+  0x6030 0000 0013 <op0:2> <op1:3> <crn:4> <crm:4> <op2:3>
+
 4.69 KVM_GET_ONE_REG
 
 Capability: KVM_CAP_ONE_REG
@@ -2261,10 +2278,10 @@ return indicates the attribute is implemented.  It does not necessarily
 indicate that the attribute can be read or written in the device's
 current state.  "addr" is ignored.
 
-4.77 KVM_ARM_VCPU_INIT
+4.82 KVM_ARM_VCPU_INIT
 
 Capability: basic
-Architectures: arm
+Architectures: arm, arm64
 Type: vcpu ioctl
 Parameters: struct struct kvm_vcpu_init (in)
 Returns: 0 on success; -1 on error
@@ -2283,12 +2300,14 @@ should be created before this ioctl is invoked.
 Possible features:
        - KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state.
          Depends on KVM_CAP_ARM_PSCI.
+       - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode.
+         Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
 
 
-4.78 KVM_GET_REG_LIST
+4.83 KVM_GET_REG_LIST
 
 Capability: basic
-Architectures: arm
+Architectures: arm, arm64
 Type: vcpu ioctl
 Parameters: struct kvm_reg_list (in/out)
 Returns: 0 on success; -1 on error
@@ -2305,10 +2324,10 @@ This ioctl returns the guest registers that are supported for the
 KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
 
 
-4.80 KVM_ARM_SET_DEVICE_ADDR
+4.84 KVM_ARM_SET_DEVICE_ADDR
 
 Capability: KVM_CAP_ARM_SET_DEVICE_ADDR
-Architectures: arm
+Architectures: arm, arm64
 Type: vm ioctl
 Parameters: struct kvm_arm_device_address (in)
 Returns: 0 on success, -1 on error
@@ -2329,20 +2348,21 @@ can access emulated or directly exposed devices, which the host kernel needs
 to know about. The id field is an architecture specific identifier for a
 specific device.
 
-ARM divides the id field into two parts, a device id and an address type id
-specific to the individual device.
+ARM/arm64 divides the id field into two parts, a device id and an
+address type id specific to the individual device.
 
  Â bits:  | 63        ...       32 | 31    ...    16 | 15    ...    0 |
   field: |        0x00000000      |     device id   |  addr type id  |
 
-ARM currently only require this when using the in-kernel GIC support for the
-hardware VGIC features, using KVM_ARM_DEVICE_VGIC_V2 as the device id.  When
-setting the base address for the guest's mapping of the VGIC virtual CPU
-and distributor interface, the ioctl must be called after calling
-KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs.  Calling
-this ioctl twice for any of the base addresses will return -EEXIST.
+ARM/arm64 currently only require this when using the in-kernel GIC
+support for the hardware VGIC features, using KVM_ARM_DEVICE_VGIC_V2
+as the device id.  When setting the base address for the guest's
+mapping of the VGIC virtual CPU and distributor interface, the ioctl
+must be called after calling KVM_CREATE_IRQCHIP, but before calling
+KVM_RUN on any of the VCPUs.  Calling this ioctl twice for any of the
+base addresses will return -EEXIST.
 
-4.82 KVM_PPC_RTAS_DEFINE_TOKEN
+4.85 KVM_PPC_RTAS_DEFINE_TOKEN
 
 Capability: KVM_CAP_PPC_RTAS
 Architectures: ppc
index 43fcb761ed161f109c93baf9b5a73390de7612e6..290894176142f452ba794eab9f0d739901516865 100644 (file)
@@ -191,12 +191,12 @@ Shadow pages contain the following information:
     A counter keeping track of how many hardware registers (guest cr3 or
     pdptrs) are now pointing at the page.  While this counter is nonzero, the
     page cannot be destroyed.  See role.invalid.
-  multimapped:
-    Whether there exist multiple sptes pointing at this page.
-  parent_pte/parent_ptes:
-    If multimapped is zero, parent_pte points at the single spte that points at
-    this page's spt.  Otherwise, parent_ptes points at a data structure
-    with a list of parent_ptes.
+  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 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.
   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
@@ -210,6 +210,24 @@ Shadow pages contain the following information:
     A bitmap indicating which sptes in spt point (directly or indirectly) at
     pages that may be unsynchronized.  Used to quickly locate all unsychronized
     pages reachable from a given page.
+  mmu_valid_gen:
+    Generation number of the page.  It is compared with kvm->arch.mmu_valid_gen
+    during hash table lookup, and used to skip invalidated shadow pages (see
+    "Zapping all pages" below.)
+  clear_spte_count:
+    Only present on 32-bit hosts, where a 64-bit spte cannot be written
+    atomically.  The reader uses this while running out of the MMU lock
+    to detect in-progress updates and retry them until the writer has
+    finished the write.
+  write_flooding_count:
+    A guest may write to a page table many times, causing a lot of
+    emulations if the page needs to be write-protected (see "Synchronized
+    and unsynchronized pages" below).  Leaf pages can be unsynchronized
+    so that they do not trigger frequent emulation, but this is not
+    possible for non-leafs.  This field counts the number of emulations
+    since the last time the page table was actually used; if emulation
+    is triggered too frequently on this page, KVM will unmap the page
+    to avoid emulation in the future.
 
 Reverse map
 ===========
@@ -258,14 +276,26 @@ This is the most complicated event.  The cause of a page fault can be:
 
 Handling a page fault is performed as follows:
 
+ - if the RSV bit of the error code is set, the page fault is caused by guest
+   accessing MMIO and cached MMIO information is available.
+   - walk shadow page table
+   - check for valid generation number in the spte (see "Fast invalidation of
+     MMIO sptes" below)
+   - cache the information to vcpu->arch.mmio_gva, vcpu->arch.access and
+     vcpu->arch.mmio_gfn, and call the emulator
+ - If both P bit and R/W bit of error code are set, this could possibly
+   be handled as a "fast page fault" (fixed without taking the MMU lock).  See
+   the description in Documentation/virtual/kvm/locking.txt.
  - if needed, walk the guest page tables to determine the guest translation
    (gva->gpa or ngpa->gpa)
    - if permissions are insufficient, reflect the fault back to the guest
  - determine the host page
-   - if this is an mmio request, there is no host page; call the emulator
-     to emulate the instruction instead
+   - if this is an mmio request, there is no host page; cache the info to
+     vcpu->arch.mmio_gva, vcpu->arch.access and vcpu->arch.mmio_gfn
  - walk the shadow page table to find the spte for the translation,
    instantiating missing intermediate page tables as necessary
+   - If this is an mmio request, cache the mmio info to the spte and set some
+     reserved bit on the spte (see callers of kvm_mmu_set_mmio_spte_mask)
  - try to unsynchronize the page
    - if successful, we can let the guest continue and modify the gpte
  - emulate the instruction
@@ -351,6 +381,51 @@ causes its write_count to be incremented, thus preventing instantiation of
 a large spte.  The frames at the end of an unaligned memory slot have
 artificially inflated ->write_counts so they can never be instantiated.
 
+Zapping all pages (page generation count)
+=========================================
+
+For the large memory guests, walking and zapping all pages is really slow
+(because there are a lot of pages), and also blocks memory accesses of
+all VCPUs because it needs to hold the MMU lock.
+
+To make it be more scalable, kvm maintains a global generation number
+which is stored in kvm->arch.mmu_valid_gen.  Every shadow page stores
+the current global generation-number into sp->mmu_valid_gen when it
+is created.  Pages with a mismatching generation number are "obsolete".
+
+When KVM need zap all shadow pages sptes, it just simply increases the global
+generation-number then reload root shadow pages on all vcpus.  As the VCPUs
+create new shadow page tables, the old pages are not used because of the
+mismatching generation number.
+
+KVM then walks through all pages and zaps obsolete pages.  While the zap
+operation needs to take the MMU lock, the lock can be released periodically
+so that the VCPUs can make progress.
+
+Fast invalidation of MMIO sptes
+===============================
+
+As mentioned in "Reaction to events" above, kvm will cache MMIO
+information in leaf sptes.  When a new memslot is added or an existing
+memslot is changed, this information may become stale and needs to be
+invalidated.  This also needs to hold the MMU lock while walking all
+shadow pages, and is made more scalable with a similar technique.
+
+MMIO sptes have a few spare bits, which are used to store a
+generation number.  The global generation number is stored in
+kvm_memslots(kvm)->generation, and increased whenever guest memory info
+changes.  This generation number is distinct from the one described in
+the previous section.
+
+When KVM finds an MMIO spte, it checks the generation number of the spte.
+If the generation number of the spte does not equal the global generation
+number, it will ignore the cached MMIO information and handle the page
+fault through the slow path.
+
+Since only 19 bits are used to store generation-number on mmio spte, all
+pages are zapped when there is an overflow.
+
+
 Further reading
 ===============
 
index a5f8436753e7d4698bf98d1e3989a14d4a98a923..f4099ca6b4835403b99d905b508c21a0851d8e8d 100644 (file)
            at process_kern.c:156
        #3  0x1006a052 in switch_to (prev=0x50072000, next=0x507e8000, last=0x50072000)
            at process_kern.c:161
-       #4  0x10001d12 in schedule () at sched.c:777
+       #4  0x10001d12 in schedule () at core.c:777
        #5  0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71
        #6  0x1006aa10 in __down_failed () at semaphore.c:157
        #7  0x1006c5d8 in segv_handler (sc=0x5006e940) at trap_user.c:174
            at process_kern.c:161
        161       _switch_to(prev, next);
        (gdb)
-       #4  0x10001d12 in schedule () at sched.c:777
+       #4  0x10001d12 in schedule () at core.c:777
        777             switch_to(prev, next, prev);
        (gdb)
        #5  0x1006a744 in __down (sem=0x507d241c) at semaphore.c:71
index 7587493c67f11e809861b0e592c5d8458ab75030..fd7c3cfddd8e57adf971838735b67c278bc2cfd8 100644 (file)
@@ -15,7 +15,8 @@ There are three components to pagemap:
     * Bits 0-54  page frame number (PFN) if present
     * Bits 0-4   swap type if swapped
     * Bits 5-54  swap offset if swapped
-    * Bits 55-60 page shift (page size = 1<<page shift)
+    * Bit  55    pte is soft-dirty (see Documentation/vm/soft-dirty.txt)
+    * Bits 56-60 zero
     * Bit  61    page is file-page or shared-anon
     * Bit  62    page swapped
     * Bit  63    page present
diff --git a/Documentation/vm/soft-dirty.txt b/Documentation/vm/soft-dirty.txt
new file mode 100644 (file)
index 0000000..9a12a59
--- /dev/null
@@ -0,0 +1,36 @@
+                            SOFT-DIRTY PTEs
+
+  The soft-dirty is a bit on a PTE which helps to track which pages a task
+writes to. In order to do this tracking one should
+
+  1. Clear soft-dirty bits from the task's PTEs.
+
+     This is done by writing "4" into the /proc/PID/clear_refs file of the
+     task in question.
+
+  2. Wait some time.
+
+  3. Read soft-dirty bits from the PTEs.
+
+     This is done by reading from the /proc/PID/pagemap. The bit 55 of the
+     64-bit qword is the soft-dirty one. If set, the respective PTE was
+     written to since step 1.
+
+
+  Internally, to do this tracking, the writable bit is cleared from PTEs
+when the soft-dirty bit is cleared. So, after this, when the task tries to
+modify a page at some virtual address the #PF occurs and the kernel sets
+the soft-dirty bit on the respective PTE.
+
+  Note, that although all the task's address space is marked as r/o after the
+soft-dirty bits clear, the #PF-s that occur after that are processed fast.
+This is so, since the pages are still mapped to physical memory, and thus all
+the kernel does is finds this fact out and puts both writable and soft-dirty
+bits on the PTE.
+
+
+  This feature is actively used by the checkpoint-restore project. You
+can find more details about it on http://criu.org
+
+
+-- Pavel Emelyanov, Apr 9, 2013
diff --git a/Documentation/ww-mutex-design.txt b/Documentation/ww-mutex-design.txt
new file mode 100644 (file)
index 0000000..8a112dc
--- /dev/null
@@ -0,0 +1,344 @@
+Wait/Wound Deadlock-Proof Mutex Design
+======================================
+
+Please read mutex-design.txt first, as it applies to wait/wound mutexes too.
+
+Motivation for WW-Mutexes
+-------------------------
+
+GPU's do operations that commonly involve many buffers.  Those buffers
+can be shared across contexts/processes, exist in different memory
+domains (for example VRAM vs system memory), and so on.  And with
+PRIME / dmabuf, they can even be shared across devices.  So there are
+a handful of situations where the driver needs to wait for buffers to
+become ready.  If you think about this in terms of waiting on a buffer
+mutex for it to become available, this presents a problem because
+there is no way to guarantee that buffers appear in a execbuf/batch in
+the same order in all contexts.  That is directly under control of
+userspace, and a result of the sequence of GL calls that an application
+makes. Which results in the potential for deadlock.  The problem gets
+more complex when you consider that the kernel may need to migrate the
+buffer(s) into VRAM before the GPU operates on the buffer(s), which
+may in turn require evicting some other buffers (and you don't want to
+evict other buffers which are already queued up to the GPU), but for a
+simplified understanding of the problem you can ignore this.
+
+The algorithm that the TTM graphics subsystem came up with for dealing with
+this problem is quite simple.  For each group of buffers (execbuf) that need
+to be locked, the caller would be assigned a unique reservation id/ticket,
+from a global counter.  In case of deadlock while locking all the buffers
+associated with a execbuf, the one with the lowest reservation ticket (i.e.
+the oldest task) wins, and the one with the higher reservation id (i.e. the
+younger task) unlocks all of the buffers that it has already locked, and then
+tries again.
+
+In the RDBMS literature this deadlock handling approach is called wait/wound:
+The older tasks waits until it can acquire the contended lock. The younger tasks
+needs to back off and drop all the locks it is currently holding, i.e. the
+younger task is wounded.
+
+Concepts
+--------
+
+Compared to normal mutexes two additional concepts/objects show up in the lock
+interface for w/w mutexes:
+
+Acquire context: To ensure eventual forward progress it is important the a task
+trying to acquire locks doesn't grab a new reservation id, but keeps the one it
+acquired when starting the lock acquisition. This ticket is stored in the
+acquire context. Furthermore the acquire context keeps track of debugging state
+to catch w/w mutex interface abuse.
+
+W/w class: In contrast to normal mutexes the lock class needs to be explicit for
+w/w mutexes, since it is required to initialize the acquire context.
+
+Furthermore there are three different class of w/w lock acquire functions:
+
+* Normal lock acquisition with a context, using ww_mutex_lock.
+
+* Slowpath lock acquisition on the contending lock, used by the wounded task
+  after having dropped all already acquired locks. These functions have the
+  _slow postfix.
+
+  From a simple semantics point-of-view the _slow functions are not strictly
+  required, since simply calling the normal ww_mutex_lock functions on the
+  contending lock (after having dropped all other already acquired locks) will
+  work correctly. After all if no other ww mutex has been acquired yet there's
+  no deadlock potential and hence the ww_mutex_lock call will block and not
+  prematurely return -EDEADLK. The advantage of the _slow functions is in
+  interface safety:
+  - ww_mutex_lock has a __must_check int return type, whereas ww_mutex_lock_slow
+    has a void return type. Note that since ww mutex code needs loops/retries
+    anyway the __must_check doesn't result in spurious warnings, even though the
+    very first lock operation can never fail.
+  - When full debugging is enabled ww_mutex_lock_slow checks that all acquired
+    ww mutex have been released (preventing deadlocks) and makes sure that we
+    block on the contending lock (preventing spinning through the -EDEADLK
+    slowpath until the contended lock can be acquired).
+
+* Functions to only acquire a single w/w mutex, which results in the exact same
+  semantics as a normal mutex. This is done by calling ww_mutex_lock with a NULL
+  context.
+
+  Again this is not strictly required. But often you only want to acquire a
+  single lock in which case it's pointless to set up an acquire context (and so
+  better to avoid grabbing a deadlock avoidance ticket).
+
+Of course, all the usual variants for handling wake-ups due to signals are also
+provided.
+
+Usage
+-----
+
+Three different ways to acquire locks within the same w/w class. Common
+definitions for methods #1 and #2:
+
+static DEFINE_WW_CLASS(ww_class);
+
+struct obj {
+       struct ww_mutex lock;
+       /* obj data */
+};
+
+struct obj_entry {
+       struct list_head head;
+       struct obj *obj;
+};
+
+Method 1, using a list in execbuf->buffers that's not allowed to be reordered.
+This is useful if a list of required objects is already tracked somewhere.
+Furthermore the lock helper can use propagate the -EALREADY return code back to
+the caller as a signal that an object is twice on the list. This is useful if
+the list is constructed from userspace input and the ABI requires userspace to
+not have duplicate entries (e.g. for a gpu commandbuffer submission ioctl).
+
+int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+{
+       struct obj *res_obj = NULL;
+       struct obj_entry *contended_entry = NULL;
+       struct obj_entry *entry;
+
+       ww_acquire_init(ctx, &ww_class);
+
+retry:
+       list_for_each_entry (entry, list, head) {
+               if (entry->obj == res_obj) {
+                       res_obj = NULL;
+                       continue;
+               }
+               ret = ww_mutex_lock(&entry->obj->lock, ctx);
+               if (ret < 0) {
+                       contended_entry = entry;
+                       goto err;
+               }
+       }
+
+       ww_acquire_done(ctx);
+       return 0;
+
+err:
+       list_for_each_entry_continue_reverse (entry, list, head)
+               ww_mutex_unlock(&entry->obj->lock);
+
+       if (res_obj)
+               ww_mutex_unlock(&res_obj->lock);
+
+       if (ret == -EDEADLK) {
+               /* we lost out in a seqno race, lock and retry.. */
+               ww_mutex_lock_slow(&contended_entry->obj->lock, ctx);
+               res_obj = contended_entry->obj;
+               goto retry;
+       }
+       ww_acquire_fini(ctx);
+
+       return ret;
+}
+
+Method 2, using a list in execbuf->buffers that can be reordered. Same semantics
+of duplicate entry detection using -EALREADY as method 1 above. But the
+list-reordering allows for a bit more idiomatic code.
+
+int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+{
+       struct obj_entry *entry, *entry2;
+
+       ww_acquire_init(ctx, &ww_class);
+
+       list_for_each_entry (entry, list, head) {
+               ret = ww_mutex_lock(&entry->obj->lock, ctx);
+               if (ret < 0) {
+                       entry2 = entry;
+
+                       list_for_each_entry_continue_reverse (entry2, list, head)
+                               ww_mutex_unlock(&entry2->obj->lock);
+
+                       if (ret != -EDEADLK) {
+                               ww_acquire_fini(ctx);
+                               return ret;
+                       }
+
+                       /* we lost out in a seqno race, lock and retry.. */
+                       ww_mutex_lock_slow(&entry->obj->lock, ctx);
+
+                       /*
+                        * Move buf to head of the list, this will point
+                        * buf->next to the first unlocked entry,
+                        * restarting the for loop.
+                        */
+                       list_del(&entry->head);
+                       list_add(&entry->head, list);
+               }
+       }
+
+       ww_acquire_done(ctx);
+       return 0;
+}
+
+Unlocking works the same way for both methods #1 and #2:
+
+void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+{
+       struct obj_entry *entry;
+
+       list_for_each_entry (entry, list, head)
+               ww_mutex_unlock(&entry->obj->lock);
+
+       ww_acquire_fini(ctx);
+}
+
+Method 3 is useful if the list of objects is constructed ad-hoc and not upfront,
+e.g. when adjusting edges in a graph where each node has its own ww_mutex lock,
+and edges can only be changed when holding the locks of all involved nodes. w/w
+mutexes are a natural fit for such a case for two reasons:
+- They can handle lock-acquisition in any order which allows us to start walking
+  a graph from a starting point and then iteratively discovering new edges and
+  locking down the nodes those edges connect to.
+- Due to the -EALREADY return code signalling that a given objects is already
+  held there's no need for additional book-keeping to break cycles in the graph
+  or keep track off which looks are already held (when using more than one node
+  as a starting point).
+
+Note that this approach differs in two important ways from the above methods:
+- Since the list of objects is dynamically constructed (and might very well be
+  different when retrying due to hitting the -EDEADLK wound condition) there's
+  no need to keep any object on a persistent list when it's not locked. We can
+  therefore move the list_head into the object itself.
+- On the other hand the dynamic object list construction also means that the -EALREADY return
+  code can't be propagated.
+
+Note also that methods #1 and #2 and method #3 can be combined, e.g. to first lock a
+list of starting nodes (passed in from userspace) using one of the above
+methods. And then lock any additional objects affected by the operations using
+method #3 below. The backoff/retry procedure will be a bit more involved, since
+when the dynamic locking step hits -EDEADLK we also need to unlock all the
+objects acquired with the fixed list. But the w/w mutex debug checks will catch
+any interface misuse for these cases.
+
+Also, method 3 can't fail the lock acquisition step since it doesn't return
+-EALREADY. Of course this would be different when using the _interruptible
+variants, but that's outside of the scope of these examples here.
+
+struct obj {
+       struct ww_mutex ww_mutex;
+       struct list_head locked_list;
+};
+
+static DEFINE_WW_CLASS(ww_class);
+
+void __unlock_objs(struct list_head *list)
+{
+       struct obj *entry, *temp;
+
+       list_for_each_entry_safe (entry, temp, list, locked_list) {
+               /* need to do that before unlocking, since only the current lock holder is
+               allowed to use object */
+               list_del(&entry->locked_list);
+               ww_mutex_unlock(entry->ww_mutex)
+       }
+}
+
+void lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+{
+       struct obj *obj;
+
+       ww_acquire_init(ctx, &ww_class);
+
+retry:
+       /* re-init loop start state */
+       loop {
+               /* magic code which walks over a graph and decides which objects
+                * to lock */
+
+               ret = ww_mutex_lock(obj->ww_mutex, ctx);
+               if (ret == -EALREADY) {
+                       /* we have that one already, get to the next object */
+                       continue;
+               }
+               if (ret == -EDEADLK) {
+                       __unlock_objs(list);
+
+                       ww_mutex_lock_slow(obj, ctx);
+                       list_add(&entry->locked_list, list);
+                       goto retry;
+               }
+
+               /* locked a new object, add it to the list */
+               list_add_tail(&entry->locked_list, list);
+       }
+
+       ww_acquire_done(ctx);
+       return 0;
+}
+
+void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
+{
+       __unlock_objs(list);
+       ww_acquire_fini(ctx);
+}
+
+Method 4: Only lock one single objects. In that case deadlock detection and
+prevention is obviously overkill, since with grabbing just one lock you can't
+produce a deadlock within just one class. To simplify this case the w/w mutex
+api can be used with a NULL context.
+
+Implementation Details
+----------------------
+
+Design:
+  ww_mutex currently encapsulates a struct mutex, this means no extra overhead for
+  normal mutex locks, which are far more common. As such there is only a small
+  increase in code size if wait/wound mutexes are not used.
+
+  In general, not much contention is expected. The locks are typically used to
+  serialize access to resources for devices. The only way to make wakeups
+  smarter would be at the cost of adding a field to struct mutex_waiter. This
+  would add overhead to all cases where normal mutexes are used, and
+  ww_mutexes are generally less performance sensitive.
+
+Lockdep:
+  Special care has been taken to warn for as many cases of api abuse
+  as possible. Some common api abuses will be caught with
+  CONFIG_DEBUG_MUTEXES, but CONFIG_PROVE_LOCKING is recommended.
+
+  Some of the errors which will be warned about:
+   - Forgetting to call ww_acquire_fini or ww_acquire_init.
+   - Attempting to lock more mutexes after ww_acquire_done.
+   - Attempting to lock the wrong mutex after -EDEADLK and
+     unlocking all mutexes.
+   - Attempting to lock the right mutex after -EDEADLK,
+     before unlocking all mutexes.
+
+   - Calling ww_mutex_lock_slow before -EDEADLK was returned.
+
+   - Unlocking mutexes with the wrong unlock function.
+   - Calling one of the ww_acquire_* twice on the same context.
+   - Using a different ww_class for the mutex than for the ww_acquire_ctx.
+   - Normal lockdep errors that can result in deadlocks.
+
+  Some of the lockdep errors that can result in deadlocks:
+   - Calling ww_acquire_init to initialize a second ww_acquire_ctx before
+     having called ww_acquire_fini on the first.
+   - 'normal' deadlocks that can occur.
+
+FIXME: Update this section once we have the TASK_DEADLOCK task state flag magic
+implemented.
index 4aaf0dfb0cb879f32988eae4bd9a07c311069b83..d62bea6796dad967a2fb651ecb4974d6e4ad2886 100644 (file)
@@ -11,7 +11,8 @@ file and loaded to CPUs during boot time.
 The format of the combined initrd image is microcode in cpio format followed by
 the initrd image (maybe compressed). Kernel parses the combined initrd image
 during boot time. The microcode file in cpio name space is:
-kernel/x86/microcode/GenuineIntel.bin
+on Intel: kernel/x86/microcode/GenuineIntel.bin
+on AMD  : kernel/x86/microcode/AuthenticAMD.bin
 
 During BSP boot (before SMP starts), if the kernel finds the microcode file in
 the initrd file, it parses the microcode and saves matching microcode in memory.
@@ -34,10 +35,8 @@ original initrd image /boot/initrd-3.5.0.img.
 
 mkdir initrd
 cd initrd
-mkdir kernel
-mkdir kernel/x86
-mkdir kernel/x86/microcode
-cp ../microcode.bin kernel/x86/microcode/GenuineIntel.bin
-find .|cpio -oc >../ucode.cpio
+mkdir -p kernel/x86/microcode
+cp ../microcode.bin kernel/x86/microcode/GenuineIntel.bin (or AuthenticAMD.bin)
+find . | cpio -o -H newc >../ucode.cpio
 cd ..
 cat ucode.cpio /boot/initrd-3.5.0.img >/boot/initrd-3.5.0.ucode.img
index e626794c3860d075f5339b3760b9edfa3b18d8b6..3f7710151a758107944d35def280608008231bca 100644 (file)
@@ -242,6 +242,11 @@ F: drivers/acpi/
 F:     drivers/pnp/pnpacpi/
 F:     include/linux/acpi.h
 F:     include/acpi/
+F:     Documentation/acpi
+F:     Documentation/ABI/testing/sysfs-bus-acpi
+F:     drivers/pci/*acpi*
+F:     drivers/pci/*/*acpi*
+F:     drivers/pci/*/*/*acpi*
 
 ACPI FAN DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
@@ -1320,6 +1325,7 @@ W:        http://wiki.xilinx.com
 T:     git git://git.xilinx.com/linux-xlnx.git
 S:     Supported
 F:     arch/arm/mach-zynq/
+F:     drivers/cpuidle/cpuidle-zynq.c
 
 ARM64 PORT (AARCH64 ARCHITECTURE)
 M:     Catalin Marinas <catalin.marinas@arm.com>
@@ -1611,6 +1617,7 @@ F:        drivers/net/wireless/b43legacy/
 
 BACKLIGHT CLASS/SUBSYSTEM
 M:     Richard Purdie <rpurdie@rpsys.net>
+M:     Jingoo Han <jg1.han@samsung.com>
 S:     Maintained
 F:     drivers/video/backlight/
 F:     include/linux/backlight.h
@@ -2131,9 +2138,10 @@ M:       Mike Turquette <mturquette@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV)
 T:     git git://git.linaro.org/people/mturquette/linux.git
 S:     Maintained
-F:     drivers/clk/clk.c
-F:     drivers/clk/clk-*
+F:     drivers/clk/
+X:     drivers/clk/clkdev.c
 F:     include/linux/clk-pr*
+F:     include/linux/clk/
 
 COMMON INTERNET FILE SYSTEM (CIFS)
 M:     Steve French <sfrench@samba.org>
@@ -2226,7 +2234,8 @@ M:        Viresh Kumar <viresh.kumar@linaro.org>
 L:     cpufreq@vger.kernel.org
 L:     linux-pm@vger.kernel.org
 S:     Maintained
-T:     git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+T:     git git://git.linaro.org/people/vireshk/linux.git (For ARM Updates)
 F:     drivers/cpufreq/
 F:     include/linux/cpufreq.h
 
@@ -2527,7 +2536,7 @@ F:        drivers/usb/dwc3/
 DEVICE FREQUENCY (DEVFREQ)
 M:     MyungJoo Ham <myungjoo.ham@samsung.com>
 M:     Kyungmin Park <kyungmin.park@samsung.com>
-L:     linux-kernel@vger.kernel.org
+L:     linux-pm@vger.kernel.org
 S:     Maintained
 F:     drivers/devfreq/
 
@@ -3587,6 +3596,7 @@ GPIO SUBSYSTEM
 M:     Grant Likely <grant.likely@linaro.org>
 M:     Linus Walleij <linus.walleij@linaro.org>
 S:     Maintained
+L:     linux-gpio@vger.kernel.org
 T:     git git://git.secretlab.ca/git/linux-2.6.git
 F:     Documentation/gpio.txt
 F:     drivers/gpio/
@@ -3999,7 +4009,8 @@ S:        Maintained
 F:     arch/ia64/
 
 IBM Power in-Nest Crypto Acceleration
-M:     Kent Yoder <key@linux.vnet.ibm.com>
+M:     Marcelo Henrique Cerri <mhcerri@linux.vnet.ibm.com>
+M:     Fionnuala Gunter <fin@linux.vnet.ibm.com>
 L:     linux-crypto@vger.kernel.org
 S:     Supported
 F:     drivers/crypto/nx/
@@ -4128,6 +4139,7 @@ F:        drivers/ipack/
 
 INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
 M:     Mimi Zohar <zohar@us.ibm.com>
+M:     Dmitry Kasatkin <d.kasatkin@samsung.com>
 S:     Supported
 F:     security/integrity/ima/
 
@@ -4731,14 +4743,23 @@ F:      arch/s390/kvm/
 F:     drivers/s390/kvm/
 
 KERNEL VIRTUAL MACHINE (KVM) FOR ARM
-M:     Christoffer Dall <cdall@cs.columbia.edu>
+M:     Christoffer Dall <christoffer.dall@linaro.org>
 L:     kvmarm@lists.cs.columbia.edu
 W:     http://systems.cs.columbia.edu/projects/kvm-arm
-S:     Maintained
+S:     Supported
 F:     arch/arm/include/uapi/asm/kvm*
 F:     arch/arm/include/asm/kvm*
 F:     arch/arm/kvm/
 
+KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
+M:     Marc Zyngier <marc.zyngier@arm.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     kvmarm@lists.cs.columbia.edu
+S:     Maintained
+F:     arch/arm64/include/uapi/asm/kvm*
+F:     arch/arm64/include/asm/kvm*
+F:     arch/arm64/kvm/
+
 KEXEC
 M:     Eric Biederman <ebiederm@xmission.com>
 W:     http://kernel.org/pub/linux/utils/kernel/kexec/
@@ -5954,8 +5975,10 @@ M:       Willem Riede <osst@riede.org>
 L:     osst-users@lists.sourceforge.net
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
-F:     drivers/scsi/osst*
-F:     drivers/scsi/st*
+F:     Documentation/scsi/osst.txt
+F:     drivers/scsi/osst.*
+F:     drivers/scsi/osst_*.h
+F:     drivers/scsi/st.h
 
 OPENCORES I2C BUS DRIVER
 M:     Peter Korsgaard <jacmet@sunsite.dk>
@@ -6285,6 +6308,16 @@ L:       linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     drivers/pinctrl/pinctrl-at91.c
 
+PIN CONTROLLER - SAMSUNG
+M:     Tomasz Figa <t.figa@samsung.com>
+M:     Thomas Abraham <thomas.abraham@linaro.org>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/pinctrl/pinctrl-exynos.*
+F:     drivers/pinctrl/pinctrl-s3c*
+F:     drivers/pinctrl/pinctrl-samsung.*
+
 PIN CONTROLLER - ST SPEAR
 M:     Viresh Kumar <viresh.linux@gmail.com>
 L:     spear-devel@list.st.com
@@ -7103,7 +7136,8 @@ M:        Kai Mäkisara <Kai.Makisara@kolumbus.fi>
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
 F:     Documentation/scsi/st.txt
-F:     drivers/scsi/st*
+F:     drivers/scsi/st.*
+F:     drivers/scsi/st_*.h
 
 SCTP PROTOCOL
 M:     Vlad Yasevich <vyasevich@gmail.com>
@@ -8261,7 +8295,8 @@ S:        Odd fixes
 F:     drivers/media/usb/tm6000/
 
 TPM DEVICE DRIVER
-M:     Kent Yoder <key@linux.vnet.ibm.com>
+M:     Leonidas Da Silva Barbosa <leosilva@linux.vnet.ibm.com>
+M:     Ashley Lai <ashley@ashleylai.com>
 M:     Rajiv Andrade <mail@srajiv.net>
 W:     http://tpmdd.sourceforge.net
 M:     Marcel Selhorst <tpmdd@selhorst.net>
@@ -9135,6 +9170,13 @@ S:       Supported
 F:     arch/arm/xen/
 F:     arch/arm/include/asm/xen/
 
+XEN HYPERVISOR ARM64
+M:     Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
+S:     Supported
+F:     arch/arm64/xen/
+F:     arch/arm64/include/asm/xen/
+
 XEN NETWORK BACKEND DRIVER
 M:     Ian Campbell <ian.campbell@citrix.com>
 L:     xen-devel@lists.xensource.com (moderated for non-subscribers)
index a4429bcd609ec8a3761e064d200d0646c3cae5f1..8d2ae24b9f4a815e253340c75c633be0a18fae9d 100644 (file)
@@ -365,6 +365,9 @@ config HAVE_IRQ_TIME_ACCOUNTING
 config HAVE_ARCH_TRANSPARENT_HUGEPAGE
        bool
 
+config HAVE_ARCH_SOFT_DIRTY
+       bool
+
 config HAVE_MOD_ARCH_SPECIFIC
        bool
        help
index c5b5d6bac9ed1ac42b93275cf0602200ddf479f5..14ce27bccd24136a8808c10e325c0294bac96bb7 100644 (file)
@@ -71,8 +71,6 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p, int n)
 
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 
-#define VALID_PAGE(page)       (((page) - mem_map) < max_mapnr)
-
 #define pmd_page(pmd)          (pfn_to_page(pmd_val(pmd) >> 32))
 #define pgd_page(pgd)          (pfn_to_page(pgd_val(pgd) >> 32))
 #define pte_pfn(pte)           (pte_val(pte) >> 32)
index 6d9e805f18a77266504ab8217eaeb2310ec9532c..dfdadb0b4befa6619568d8179dd68f1850ef6151 100644 (file)
@@ -32,6 +32,7 @@
 #define O_SYNC         (__O_SYNC|O_DSYNC)
 
 #define O_PATH         040000000
+#define O_TMPFILE      0100000000
 
 #define F_GETLK                7
 #define F_SETLK                8
index 1d4aabfcf9a160318fd790bd22d98646c270bd74..837c0fa58317a2ff308c494aa69b7ad477b62e5e 100644 (file)
@@ -238,8 +238,8 @@ nautilus_init_pci(void)
        if (pci_mem < memtop)
                memtop = pci_mem;
        if (memtop > alpha_mv.min_mem_address) {
-               free_reserved_area((unsigned long)__va(alpha_mv.min_mem_address),
-                                  (unsigned long)__va(memtop), 0, NULL);
+               free_reserved_area(__va(alpha_mv.min_mem_address),
+                                  __va(memtop), -1, NULL);
                printk("nautilus_init_pci: %ldk freed\n",
                        (memtop - alpha_mv.min_mem_address) >> 10);
        }
index 0ba85ee4a466721b1b91a486d04b6752901a38f2..a1bea91df56ab996b92f33b0cfcd6738e4d2c072 100644 (file)
@@ -276,56 +276,25 @@ srm_paging_stop (void)
 }
 #endif
 
-#ifndef CONFIG_DISCONTIGMEM
-static void __init
-printk_memory_info(void)
-{
-       unsigned long codesize, reservedpages, datasize, initsize, tmp;
-       extern int page_is_ram(unsigned long) __init;
-
-       /* printk all informations */
-       reservedpages = 0;
-       for (tmp = 0; tmp < max_low_pfn; tmp++)
-               /*
-                * Only count reserved RAM pages
-                */
-               if (page_is_ram(tmp) && PageReserved(mem_map+tmp))
-                       reservedpages++;
-
-       codesize =  (unsigned long) &_etext - (unsigned long) &_text;
-       datasize =  (unsigned long) &_edata - (unsigned long) &_data;
-       initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
-       printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, %luk data, %luk init)\n",
-              nr_free_pages() << (PAGE_SHIFT-10),
-              max_mapnr << (PAGE_SHIFT-10),
-              codesize >> 10,
-              reservedpages << (PAGE_SHIFT-10),
-              datasize >> 10,
-              initsize >> 10);
-}
-
 void __init
 mem_init(void)
 {
-       max_mapnr = num_physpages = max_low_pfn;
-       totalram_pages += free_all_bootmem();
+       set_max_mapnr(max_low_pfn);
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
-
-       printk_memory_info();
+       free_all_bootmem();
+       mem_init_print_info(NULL);
 }
-#endif /* CONFIG_DISCONTIGMEM */
 
 void
 free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void
 free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
index 33885048fa3680cce1775bfc11a36e229a69c98e..d543d71c28b4e4ce08e30587e41bae3786a35f7f 100644 (file)
@@ -129,8 +129,6 @@ setup_memory_node(int nid, void *kernel_end)
        if (node_max_pfn > max_low_pfn)
                max_pfn = max_low_pfn = node_max_pfn;
 
-       num_physpages += node_max_pfn - node_min_pfn;
-
 #if 0 /* we'll try this one again in a little while */
        /* Cute trick to make sure our local node data is on local memory */
        node_data[nid] = (pg_data_t *)(__va(node_min_pfn << PAGE_SHIFT));
@@ -321,41 +319,3 @@ void __init paging_init(void)
        /* Initialize the kernel's ZERO_PGE. */
        memset((void *)ZERO_PGE, 0, PAGE_SIZE);
 }
-
-void __init mem_init(void)
-{
-       unsigned long codesize, reservedpages, datasize, initsize, pfn;
-       extern int page_is_ram(unsigned long) __init;
-       unsigned long nid, i;
-       high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
-
-       reservedpages = 0;
-       for_each_online_node(nid) {
-               /*
-                * This will free up the bootmem, ie, slot 0 memory
-                */
-               totalram_pages += free_all_bootmem_node(NODE_DATA(nid));
-
-               pfn = NODE_DATA(nid)->node_start_pfn;
-               for (i = 0; i < node_spanned_pages(nid); i++, pfn++)
-                       if (page_is_ram(pfn) &&
-                           PageReserved(nid_page_nr(nid, i)))
-                               reservedpages++;
-       }
-
-       codesize =  (unsigned long) &_etext - (unsigned long) &_text;
-       datasize =  (unsigned long) &_edata - (unsigned long) &_data;
-       initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
-       printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, "
-              "%luk data, %luk init)\n",
-              nr_free_pages() << (PAGE_SHIFT-10),
-              num_physpages << (PAGE_SHIFT-10),
-              codesize >> 10,
-              reservedpages << (PAGE_SHIFT-10),
-              datasize >> 10,
-              initsize >> 10);
-#if 0
-       mem_stress();
-#endif
-}
index 5917099470eaf74d259051b4f7451683cc52901a..4a0e54fc01b280f260af6549d4f2c543c95f7055 100644 (file)
@@ -184,6 +184,7 @@ config ARC_CACHE_PAGES
 
 config ARC_CACHE_VIPT_ALIASING
        bool "Support VIPT Aliasing D$"
+       depends on ARC_HAS_DCACHE
        default n
 
 endif  #ARC_CACHE
@@ -361,13 +362,6 @@ config ARC_MISALIGN_ACCESS
          Use ONLY-IF-ABS-NECESSARY as it will be very slow and also can hide
          potential bugs in code
 
-config ARC_STACK_NONEXEC
-       bool "Make stack non-executable"
-       default n
-       help
-         To disable the execute permissions of stack/heap of processes
-         which are enabled by default.
-
 config HZ
        int "Timer Frequency"
        default 100
index 183397fd289eb5e5146883147e2466538db984df..8c0b1aa56f7ef0f885bb51a94ff6291c867bbf82 100644 (file)
@@ -9,25 +9,27 @@
 UTS_MACHINE := arc
 
 ifeq ($(CROSS_COMPILE),)
-CROSS_COMPILE := arc-elf32-
+CROSS_COMPILE := arc-linux-uclibc-
 endif
 
 KBUILD_DEFCONFIG := fpga_defconfig
 
 cflags-y       += -mA7 -fno-common -pipe -fno-builtin -D__linux__
 
-LINUXINCLUDE   +=  -include ${src}/arch/arc/include/asm/defines.h
-
 ifdef CONFIG_ARC_CURR_IN_REG
 # For a global register defintion, make sure it gets passed to every file
 # We had a customer reported bug where some code built in kernel was NOT using
 # any kernel headers, and missing the r25 global register
-# Can't do unconditionally (like above) because of recursive include issues
+# Can't do unconditionally because of recursive include issues
 # due to <linux/thread_info.h>
 LINUXINCLUDE   +=  -include ${src}/arch/arc/include/asm/current.h
 endif
 
-atleast_gcc44 :=  $(call cc-ifversion, -gt, 0402, y)
+upto_gcc42    :=  $(call cc-ifversion, -le, 0402, y)
+upto_gcc44    :=  $(call cc-ifversion, -le, 0404, y)
+atleast_gcc44 :=  $(call cc-ifversion, -ge, 0404, y)
+atleast_gcc48 :=  $(call cc-ifversion, -ge, 0408, y)
+
 cflags-$(atleast_gcc44)                        += -fsection-anchors
 
 cflags-$(CONFIG_ARC_HAS_LLSC)          += -mlock
@@ -35,6 +37,11 @@ cflags-$(CONFIG_ARC_HAS_SWAPE)               += -mswape
 cflags-$(CONFIG_ARC_HAS_RTSC)          += -mrtsc
 cflags-$(CONFIG_ARC_DW2_UNWIND)                += -fasynchronous-unwind-tables
 
+# By default gcc 4.8 generates dwarf4 which kernel unwinder can't grok
+ifeq ($(atleast_gcc48),y)
+cflags-$(CONFIG_ARC_DW2_UNWIND)                += -gdwarf-2
+endif
+
 ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
 # Generic build system uses -O2, we want -O3
 cflags-y  += -O3
@@ -48,11 +55,10 @@ cflags-$(disable_small_data)                += -mno-sdata -fcall-used-gp
 cflags-$(CONFIG_CPU_BIG_ENDIAN)                += -mbig-endian
 ldflags-$(CONFIG_CPU_BIG_ENDIAN)       += -EB
 
-# STAR 9000518362:
+# STAR 9000518362: (fixed with binutils shipping with gcc 4.8)
 # arc-linux-uclibc-ld (buildroot) or arceb-elf32-ld (EZChip) don't accept
-# --build-id w/o "-marclinux".
-# Default arc-elf32-ld is OK
-ldflags-y                              += -marclinux
+# --build-id w/o "-marclinux". Default arc-elf32-ld is OK
+ldflags-$(upto_gcc44)                  += -marclinux
 
 ARC_LIBGCC                             := -mA7
 cflags-$(CONFIG_ARC_HAS_HW_MPY)                += -multcost=16
@@ -66,8 +72,8 @@ ifndef CONFIG_ARC_HAS_HW_MPY
 # With gcc 4.4.7, -mno-mpy is enough to make any other related adjustments,
 # e.g. increased cost of MPY. With gcc 4.2.1 this had to be explicitly hinted
 
-       ARC_LIBGCC              := -marc600
-       ifneq ($(atleast_gcc44),y)
+       ifeq ($(upto_gcc42),y)
+               ARC_LIBGCC      := -marc600
                cflags-y        += -multcost=30
        endif
 endif
index 95350be6ef6f5cd96685878ab081f320eafd3bd8..c109af320274f30665548463a07617b242d3279c 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-elf32-"
+CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
index 446c96c24eff59f17678f5fcc8382e13ed69d4ba..451af30914f660e14f81a6779292ca56d3c3ec99 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-elf32-"
+CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
index 4fa5cd9f22028bab678371baa14cf9f3ac0ce01d..6be6492442d640d3aba09b42239650995aa6e5be 100644 (file)
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-elf32-"
+CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_DEFAULT_HOSTNAME="tb10x"
 CONFIG_SYSVIPC=y
index 1b907c4656668cf5d68498a85111b78383263645..355cb470c2a4770f7ba9d06a93dd8aa162789680 100644 (file)
@@ -20,7 +20,6 @@
 #define ARC_REG_PERIBASE_BCR   0x69
 #define ARC_REG_FP_BCR         0x6B    /* Single-Precision FPU */
 #define ARC_REG_DPFP_BCR       0x6C    /* Dbl Precision FPU */
-#define ARC_REG_MMU_BCR                0x6f
 #define ARC_REG_DCCM_BCR       0x74    /* DCCM Present + SZ */
 #define ARC_REG_TIMERS_BCR     0x75
 #define ARC_REG_ICCM_BCR       0x78
 #define ARC_REG_D_UNCACH_BCR   0x6A
 
 /* status32 Bits Positions */
-#define STATUS_H_BIT           0       /* CPU Halted */
-#define STATUS_E1_BIT          1       /* Int 1 enable */
-#define STATUS_E2_BIT          2       /* Int 2 enable */
-#define STATUS_A1_BIT          3       /* Int 1 active */
-#define STATUS_A2_BIT          4       /* Int 2 active */
 #define STATUS_AE_BIT          5       /* Exception active */
 #define STATUS_DE_BIT          6       /* PC is in delay slot */
 #define STATUS_U_BIT           7       /* User/Kernel mode */
 #define STATUS_L_BIT           12      /* Loop inhibit */
 
 /* These masks correspond to the status word(STATUS_32) bits */
-#define STATUS_H_MASK          (1<<STATUS_H_BIT)
-#define STATUS_E1_MASK         (1<<STATUS_E1_BIT)
-#define STATUS_E2_MASK         (1<<STATUS_E2_BIT)
-#define STATUS_A1_MASK         (1<<STATUS_A1_BIT)
-#define STATUS_A2_MASK         (1<<STATUS_A2_BIT)
 #define STATUS_AE_MASK         (1<<STATUS_AE_BIT)
 #define STATUS_DE_MASK         (1<<STATUS_DE_BIT)
 #define STATUS_U_MASK          (1<<STATUS_U_BIT)
@@ -71,6 +60,7 @@
 #define ECR_V_ITLB_MISS                        0x21
 #define ECR_V_DTLB_MISS                        0x22
 #define ECR_V_PROTV                    0x23
+#define ECR_V_TRAP                     0x25
 
 /* Protection Violation Exception Cause Code Values */
 #define ECR_C_PROTV_INST_FETCH         0x00
 #define ECR_C_PROTV_XCHG               0x03
 #define ECR_C_PROTV_MISALIG_DATA       0x04
 
+#define ECR_C_BIT_PROTV_MISALIG_DATA   10
+
+/* Machine Check Cause Code Values */
+#define ECR_C_MCHK_DUP_TLB             0x01
+
 /* DTLB Miss Exception Cause Code Values */
 #define ECR_C_BIT_DTLB_LD_MISS         8
 #define ECR_C_BIT_DTLB_ST_MISS         9
 
+/* Dummy ECR values for Interrupts */
+#define event_IRQ1             0x0031abcd
+#define event_IRQ2             0x0032abcd
 
 /* Auxiliary registers */
 #define AUX_IDENTITY           4
 #define AUX_INTR_VEC_BASE      0x25
-#define AUX_IRQ_LEV            0x200   /* IRQ Priority: L1 or L2 */
-#define AUX_IRQ_HINT           0x201   /* For generating Soft Interrupts */
-#define AUX_IRQ_LV12           0x43    /* interrupt level register */
-
-#define AUX_IENABLE            0x40c
-#define AUX_ITRIGGER           0x40d
-#define AUX_IPULSE             0x415
-
-/* Timer related Aux registers */
-#define ARC_REG_TIMER0_LIMIT   0x23    /* timer 0 limit */
-#define ARC_REG_TIMER0_CTRL    0x22    /* timer 0 control */
-#define ARC_REG_TIMER0_CNT     0x21    /* timer 0 count */
-#define ARC_REG_TIMER1_LIMIT   0x102   /* timer 1 limit */
-#define ARC_REG_TIMER1_CTRL    0x101   /* timer 1 control */
-#define ARC_REG_TIMER1_CNT     0x100   /* timer 1 count */
-
-#define TIMER_CTRL_IE          (1 << 0) /* Interupt when Count reachs limit */
-#define TIMER_CTRL_NH          (1 << 1) /* Count only when CPU NOT halted */
-
-/* MMU Management regs */
-#define ARC_REG_TLBPD0         0x405
-#define ARC_REG_TLBPD1         0x406
-#define ARC_REG_TLBINDEX       0x407
-#define ARC_REG_TLBCOMMAND     0x408
-#define ARC_REG_PID            0x409
-#define ARC_REG_SCRATCH_DATA0  0x418
-
-/* Bits in MMU PID register */
-#define MMU_ENABLE             (1 << 31)       /* Enable MMU for process */
-
-/* Error code if probe fails */
-#define TLB_LKUP_ERR           0x80000000
-
-/* TLB Commands */
-#define TLBWrite    0x1
-#define TLBRead     0x2
-#define TLBGetIndex 0x3
-#define TLBProbe    0x4
-
-#if (CONFIG_ARC_MMU_VER >= 2)
-#define TLBWriteNI  0x5                /* write JTLB without inv uTLBs */
-#define TLBIVUTLB   0x6                /* explicitly inv uTLBs */
-#else
-#undef TLBWriteNI              /* These cmds don't exist on older MMU */
-#undef TLBIVUTLB
-#endif
 
-/* Instruction cache related Auxiliary registers */
-#define ARC_REG_IC_BCR         0x77    /* Build Config reg */
-#define ARC_REG_IC_IVIC                0x10
-#define ARC_REG_IC_CTRL                0x11
-#define ARC_REG_IC_IVIL                0x19
-#if (CONFIG_ARC_MMU_VER > 2)
-#define ARC_REG_IC_PTAG                0x1E
-#endif
-
-/* Bit val in IC_CTRL */
-#define IC_CTRL_CACHE_DISABLE   0x1
-
-/* Data cache related Auxiliary registers */
-#define ARC_REG_DC_BCR         0x72
-#define ARC_REG_DC_IVDC                0x47
-#define ARC_REG_DC_CTRL                0x48
-#define ARC_REG_DC_IVDL                0x4A
-#define ARC_REG_DC_FLSH                0x4B
-#define ARC_REG_DC_FLDL                0x4C
-#if (CONFIG_ARC_MMU_VER > 2)
-#define ARC_REG_DC_PTAG                0x5C
-#endif
-
-/* Bit val in DC_CTRL */
-#define DC_CTRL_INV_MODE_FLUSH  0x40
-#define DC_CTRL_FLUSH_STATUS    0x100
-
-/* MMU Management regs */
-#define ARC_REG_PID            0x409
-#define ARC_REG_SCRATCH_DATA0  0x418
-
-/* Bits in MMU PID register */
-#define MMU_ENABLE             (1 << 31)       /* Enable MMU for process */
 
 /*
  * Floating Pt Registers
@@ -293,24 +212,6 @@ struct bcr_identity {
 #endif
 };
 
-struct bcr_mmu_1_2 {
-#ifdef CONFIG_CPU_BIG_ENDIAN
-       unsigned int ver:8, ways:4, sets:4, u_itlb:8, u_dtlb:8;
-#else
-       unsigned int u_dtlb:8, u_itlb:8, sets:4, ways:4, ver:8;
-#endif
-};
-
-struct bcr_mmu_3 {
-#ifdef CONFIG_CPU_BIG_ENDIAN
-       unsigned int ver:8, ways:4, sets:4, osm:1, reserv:3, pg_sz:4,
-                    u_itlb:4, u_dtlb:4;
-#else
-       unsigned int u_dtlb:4, u_itlb:4, pg_sz:4, reserv:3, osm:1, sets:4,
-                    ways:4, ver:8;
-#endif
-};
-
 #define EXTN_SWAP_VALID     0x1
 #define EXTN_NORM_VALID     0x2
 #define EXTN_MINMAX_VALID   0x2
@@ -343,14 +244,6 @@ struct bcr_extn_xymem {
 #endif
 };
 
-struct bcr_cache {
-#ifdef CONFIG_CPU_BIG_ENDIAN
-       unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
-#else
-       unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
-#endif
-};
-
 struct bcr_perip {
 #ifdef CONFIG_CPU_BIG_ENDIAN
        unsigned int start:8, pad2:8, sz:8, pad:8;
@@ -403,7 +296,7 @@ struct cpuinfo_arc_mmu {
 };
 
 struct cpuinfo_arc_cache {
-       unsigned int has_aliasing, sz, line_len, assoc, ver;
+       unsigned int sz, line_len, assoc, ver;
 };
 
 struct cpuinfo_arc_ccm {
index 2ad8f9b1c54b047f91250285b65efdae32ce35c1..5b18e94c6678cd2b9eda3eace0dff4f9dd35585c 100644 (file)
@@ -18,9 +18,8 @@ struct task_struct;
 void show_regs(struct pt_regs *regs);
 void show_stacktrace(struct task_struct *tsk, struct pt_regs *regs);
 void show_kernel_fault_diag(const char *str, struct pt_regs *regs,
-                           unsigned long address, unsigned long cause_reg);
-void die(const char *str, struct pt_regs *regs, unsigned long address,
-        unsigned long cause_reg);
+                           unsigned long address);
+void die(const char *str, struct pt_regs *regs, unsigned long address);
 
 #define BUG()  do {                            \
        dump_stack();                                   \
index d5555fe4742a3f696c7c8ef72d6eae757b51469e..5802849a6caefa802b2a1d8cc6d26e845444767e 100644 (file)
 
 #define L1_CACHE_BYTES         (1 << L1_CACHE_SHIFT)
 
-#define ARC_ICACHE_WAYS        2
-#define ARC_DCACHE_WAYS        4
-
-/* Helpers */
+/* For a rare case where customers have differently config I/D */
 #define ARC_ICACHE_LINE_LEN    L1_CACHE_BYTES
 #define ARC_DCACHE_LINE_LEN    L1_CACHE_BYTES
 
 #define ICACHE_LINE_MASK       (~(ARC_ICACHE_LINE_LEN - 1))
 #define DCACHE_LINE_MASK       (~(ARC_DCACHE_LINE_LEN - 1))
 
-#if ARC_ICACHE_LINE_LEN != ARC_DCACHE_LINE_LEN
-#error "Need to fix some code as I/D cache lines not same"
-#else
-#define is_not_cache_aligned(p)        ((unsigned long)p & (~DCACHE_LINE_MASK))
-#endif
+/*
+ * ARC700 doesn't cache any access in top 256M.
+ * Ideal for wiring memory mapped peripherals as we don't need to do
+ * explicit uncached accesses (LD.di/ST.di) hence more portable drivers
+ */
+#define ARC_UNCACHED_ADDR_SPACE        0xc0000000
 
 #ifndef __ASSEMBLY__
 
 
 #define ARCH_DMA_MINALIGN      L1_CACHE_BYTES
 
-/*
- * ARC700 doesn't cache any access in top 256M.
- * Ideal for wiring memory mapped peripherals as we don't need to do
- * explicit uncached accesses (LD.di/ST.di) hence more portable drivers
- */
-#define ARC_UNCACHED_ADDR_SPACE        0xc0000000
-
 extern void arc_cache_init(void);
 extern char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len);
 extern void __init read_decode_cache_bcr(void);
-#endif
+
+#endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_CACHE_H */
index ef62682e8d9567670fc435be9bc5ddfddb5fa06b..6abc4972bc93bbba015c3ebe92ea40926c7413a8 100644 (file)
@@ -80,17 +80,20 @@ void flush_anon_page(struct vm_area_struct *vma,
 
 #endif /* CONFIG_ARC_CACHE_VIPT_ALIASING */
 
+/*
+ * A new pagecache page has PG_arch_1 clear - thus dcache dirty by default
+ * This works around some PIO based drivers which don't call flush_dcache_page
+ * to record that they dirtied the dcache
+ */
+#define PG_dc_clean    PG_arch_1
+
 /*
  * Simple wrapper over config option
  * Bootup code ensures that hardware matches kernel configuration
  */
 static inline int cache_is_vipt_aliasing(void)
 {
-#ifdef CONFIG_ARC_CACHE_VIPT_ALIASING
-       return 1;
-#else
-       return 0;
-#endif
+       return IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING);
 }
 
 #define CACHE_COLOR(addr)      (((unsigned long)(addr) >> (PAGE_SHIFT)) & 1)
diff --git a/arch/arc/include/asm/defines.h b/arch/arc/include/asm/defines.h
deleted file mode 100644 (file)
index 6097bb4..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ARC_ASM_DEFINES_H__
-#define __ARC_ASM_DEFINES_H__
-
-#if defined(CONFIG_ARC_MMU_V1)
-#define CONFIG_ARC_MMU_VER 1
-#elif defined(CONFIG_ARC_MMU_V2)
-#define CONFIG_ARC_MMU_VER 2
-#elif defined(CONFIG_ARC_MMU_V3)
-#define CONFIG_ARC_MMU_VER 3
-#endif
-
-#ifdef CONFIG_ARC_HAS_LLSC
-#define __CONFIG_ARC_HAS_LLSC_VAL 1
-#else
-#define __CONFIG_ARC_HAS_LLSC_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_SWAPE
-#define __CONFIG_ARC_HAS_SWAPE_VAL 1
-#else
-#define __CONFIG_ARC_HAS_SWAPE_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_RTSC
-#define __CONFIG_ARC_HAS_RTSC_VAL 1
-#else
-#define __CONFIG_ARC_HAS_RTSC_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_MMU_SASID
-#define __CONFIG_ARC_MMU_SASID_VAL 1
-#else
-#define __CONFIG_ARC_MMU_SASID_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_ICACHE
-#define __CONFIG_ARC_HAS_ICACHE        1
-#else
-#define __CONFIG_ARC_HAS_ICACHE        0
-#endif
-
-#ifdef CONFIG_ARC_HAS_DCACHE
-#define __CONFIG_ARC_HAS_DCACHE        1
-#else
-#define __CONFIG_ARC_HAS_DCACHE        0
-#endif
-
-#endif /* __ARC_ASM_DEFINES_H__ */
index eb2ae53187d95fe1240885bd7026d1f13c3c98a4..8943c028d4bbe3ae2aea2875aae5c2d7e3dd2bda 100644 (file)
  *      Eff Addr for load = [reg2]
  */
 
+.macro PUSH reg
+       st.a    \reg, [sp, -4]
+.endm
+
+.macro PUSHAX aux
+       lr      r9, [\aux]
+       PUSH    r9
+.endm
+
+.macro POP reg
+       ld.ab   \reg, [sp, 4]
+.endm
+
+.macro POPAX aux
+       POP     r9
+       sr      r9, [\aux]
+.endm
+
 /*--------------------------------------------------------------
- * Save caller saved registers (scratch registers) ( r0 - r12 )
- * Registers are pushed / popped in the order defined in struct ptregs
- * in asm/ptrace.h
+ * Helpers to save/restore Scratch Regs:
+ * used by Interrupt/Exception Prologue/Epilogue
  *-------------------------------------------------------------*/
-.macro  SAVE_CALLER_SAVED
-       st.a    r0, [sp, -4]
-       st.a    r1, [sp, -4]
-       st.a    r2, [sp, -4]
-       st.a    r3, [sp, -4]
-       st.a    r4, [sp, -4]
-       st.a    r5, [sp, -4]
-       st.a    r6, [sp, -4]
-       st.a    r7, [sp, -4]
-       st.a    r8, [sp, -4]
-       st.a    r9, [sp, -4]
-       st.a    r10, [sp, -4]
-       st.a    r11, [sp, -4]
-       st.a    r12, [sp, -4]
+.macro  SAVE_R0_TO_R12
+       PUSH    r0
+       PUSH    r1
+       PUSH    r2
+       PUSH    r3
+       PUSH    r4
+       PUSH    r5
+       PUSH    r6
+       PUSH    r7
+       PUSH    r8
+       PUSH    r9
+       PUSH    r10
+       PUSH    r11
+       PUSH    r12
+.endm
+
+.macro RESTORE_R12_TO_R0
+       POP     r12
+       POP     r11
+       POP     r10
+       POP     r9
+       POP     r8
+       POP     r7
+       POP     r6
+       POP     r5
+       POP     r4
+       POP     r3
+       POP     r2
+       POP     r1
+       POP     r0
+
+#ifdef CONFIG_ARC_CURR_IN_REG
+       ld      r25, [sp, 12]
+#endif
 .endm
 
 /*--------------------------------------------------------------
- * Restore caller saved registers (scratch registers)
+ * Helpers to save/restore callee-saved regs:
+ * used by several macros below
  *-------------------------------------------------------------*/
-.macro RESTORE_CALLER_SAVED
-       ld.ab   r12, [sp, 4]
-       ld.ab   r11, [sp, 4]
-       ld.ab   r10, [sp, 4]
-       ld.ab   r9, [sp, 4]
-       ld.ab   r8, [sp, 4]
-       ld.ab   r7, [sp, 4]
-       ld.ab   r6, [sp, 4]
-       ld.ab   r5, [sp, 4]
-       ld.ab   r4, [sp, 4]
-       ld.ab   r3, [sp, 4]
-       ld.ab   r2, [sp, 4]
-       ld.ab   r1, [sp, 4]
-       ld.ab   r0, [sp, 4]
+.macro SAVE_R13_TO_R24
+       PUSH    r13
+       PUSH    r14
+       PUSH    r15
+       PUSH    r16
+       PUSH    r17
+       PUSH    r18
+       PUSH    r19
+       PUSH    r20
+       PUSH    r21
+       PUSH    r22
+       PUSH    r23
+       PUSH    r24
+.endm
+
+.macro RESTORE_R24_TO_R13
+       POP     r24
+       POP     r23
+       POP     r22
+       POP     r21
+       POP     r20
+       POP     r19
+       POP     r18
+       POP     r17
+       POP     r16
+       POP     r15
+       POP     r14
+       POP     r13
 .endm
 
+#define OFF_USER_R25_FROM_R24  (SZ_CALLEE_REGS + SZ_PT_REGS - 8)/4
 
 /*--------------------------------------------------------------
- * Save callee saved registers (non scratch registers) ( r13 - r25 )
- *  on kernel stack.
- * User mode callee regs need to be saved in case of
- *    -fork and friends for replicating from parent to child
- *    -before going into do_signal( ) for ptrace/core-dump
- * Special case handling is required for r25 in case it is used by kernel
- *  for caching task ptr. Low level exception/ISR save user mode r25
- *  into task->thread.user_r25. So it needs to be retrieved from there and
- *  saved into kernel stack with rest of callee reg-file
+ * Collect User Mode callee regs as struct callee_regs - needed by
+ * fork/do_signal/unaligned-access-emulation.
+ * (By default only scratch regs are saved on entry to kernel)
+ *
+ * Special handling for r25 if used for caching Task Pointer.
+ * It would have been saved in task->thread.user_r25 already, but to keep
+ * the interface same it is copied into regular r25 placeholder in
+ * struct callee_regs.
  *-------------------------------------------------------------*/
 .macro SAVE_CALLEE_SAVED_USER
-       st.a    r13, [sp, -4]
-       st.a    r14, [sp, -4]
-       st.a    r15, [sp, -4]
-       st.a    r16, [sp, -4]
-       st.a    r17, [sp, -4]
-       st.a    r18, [sp, -4]
-       st.a    r19, [sp, -4]
-       st.a    r20, [sp, -4]
-       st.a    r21, [sp, -4]
-       st.a    r22, [sp, -4]
-       st.a    r23, [sp, -4]
-       st.a    r24, [sp, -4]
+
+       SAVE_R13_TO_R24
 
 #ifdef CONFIG_ARC_CURR_IN_REG
        ; Retrieve orig r25 and save it on stack
-       ld      r12, [r25, TASK_THREAD + THREAD_USER_R25]
+       ld.as   r12, [sp, OFF_USER_R25_FROM_R24]
        st.a    r12, [sp, -4]
 #else
-       st.a    r25, [sp, -4]
+       PUSH    r25
 #endif
 
-       /* move up by 1 word to "create" callee_regs->"stack_place_holder" */
-       sub sp, sp, 4
 .endm
 
 /*--------------------------------------------------------------
- * Save callee saved registers (non scratch registers) ( r13 - r25 )
- * kernel mode callee regs needed to be saved in case of context switch
- * If r25 is used for caching task pointer then that need not be saved
- * as it can be re-created from current task global
+ * Save kernel Mode callee regs at the time of Contect Switch.
+ *
+ * Special handling for r25 if used for caching Task Pointer.
+ * Kernel simply skips saving it since it will be loaded with
+ * incoming task pointer anyways
  *-------------------------------------------------------------*/
 .macro SAVE_CALLEE_SAVED_KERNEL
-       st.a    r13, [sp, -4]
-       st.a    r14, [sp, -4]
-       st.a    r15, [sp, -4]
-       st.a    r16, [sp, -4]
-       st.a    r17, [sp, -4]
-       st.a    r18, [sp, -4]
-       st.a    r19, [sp, -4]
-       st.a    r20, [sp, -4]
-       st.a    r21, [sp, -4]
-       st.a    r22, [sp, -4]
-       st.a    r23, [sp, -4]
-       st.a    r24, [sp, -4]
+
+       SAVE_R13_TO_R24
+
 #ifdef CONFIG_ARC_CURR_IN_REG
-       sub     sp, sp, 8
-#else
-       st.a    r25, [sp, -4]
        sub     sp, sp, 4
+#else
+       PUSH    r25
 #endif
 .endm
 
 /*--------------------------------------------------------------
- * RESTORE_CALLEE_SAVED_KERNEL:
- * Loads callee (non scratch) Reg File by popping from Kernel mode stack.
- *  This is reverse of SAVE_CALLEE_SAVED,
- *
- * NOTE:
- * Ideally this shd only be called in switch_to for loading
- *  switched-IN task's CALLEE Reg File.
- *  For all other cases RESTORE_CALLEE_SAVED_FAST must be used
- *  which simply pops the stack w/o touching regs.
+ * Opposite of SAVE_CALLEE_SAVED_KERNEL
  *-------------------------------------------------------------*/
 .macro RESTORE_CALLEE_SAVED_KERNEL
 
-
 #ifdef CONFIG_ARC_CURR_IN_REG
-       add     sp, sp, 8  /* skip callee_reg gutter and user r25 placeholder */
+       add     sp, sp, 4  /* skip usual r25 placeholder */
 #else
-       add     sp, sp, 4   /* skip "callee_regs->stack_place_holder" */
-       ld.ab   r25, [sp, 4]
+       POP     r25
 #endif
-
-       ld.ab   r24, [sp, 4]
-       ld.ab   r23, [sp, 4]
-       ld.ab   r22, [sp, 4]
-       ld.ab   r21, [sp, 4]
-       ld.ab   r20, [sp, 4]
-       ld.ab   r19, [sp, 4]
-       ld.ab   r18, [sp, 4]
-       ld.ab   r17, [sp, 4]
-       ld.ab   r16, [sp, 4]
-       ld.ab   r15, [sp, 4]
-       ld.ab   r14, [sp, 4]
-       ld.ab   r13, [sp, 4]
-
+       RESTORE_R24_TO_R13
 .endm
 
 /*--------------------------------------------------------------
- * RESTORE_CALLEE_SAVED_USER:
- * This is called after do_signal where tracer might have changed callee regs
- * thus we need to restore the reg file.
- * Special case handling is required for r25 in case it is used by kernel
- *  for caching task ptr. Ptrace would have modified on-kernel-stack value of
- *  r25, which needs to be shoved back into task->thread.user_r25 where from
- *  Low level exception/ISR return code will retrieve to populate with rest of
- *  callee reg-file.
+ * Opposite of SAVE_CALLEE_SAVED_USER
+ *
+ * ptrace tracer or unaligned-access fixup might have changed a user mode
+ * callee reg which is saved back to usual r25 storage location
  *-------------------------------------------------------------*/
 .macro RESTORE_CALLEE_SAVED_USER
 
-       add     sp, sp, 4   /* skip "callee_regs->stack_place_holder" */
-
 #ifdef CONFIG_ARC_CURR_IN_REG
        ld.ab   r12, [sp, 4]
-       st      r12, [r25, TASK_THREAD + THREAD_USER_R25]
+       st.as   r12, [sp, OFF_USER_R25_FROM_R24]
 #else
-       ld.ab   r25, [sp, 4]
+       POP     r25
 #endif
-
-       ld.ab   r24, [sp, 4]
-       ld.ab   r23, [sp, 4]
-       ld.ab   r22, [sp, 4]
-       ld.ab   r21, [sp, 4]
-       ld.ab   r20, [sp, 4]
-       ld.ab   r19, [sp, 4]
-       ld.ab   r18, [sp, 4]
-       ld.ab   r17, [sp, 4]
-       ld.ab   r16, [sp, 4]
-       ld.ab   r15, [sp, 4]
-       ld.ab   r14, [sp, 4]
-       ld.ab   r13, [sp, 4]
+       RESTORE_R24_TO_R13
 .endm
 
 /*--------------------------------------------------------------
  * Super FAST Restore callee saved regs by simply re-adjusting SP
  *-------------------------------------------------------------*/
 .macro DISCARD_CALLEE_SAVED_USER
-       add     sp, sp, 14 * 4
-.endm
-
-/*--------------------------------------------------------------
- * Restore User mode r25 saved in task_struct->thread.user_r25
- *-------------------------------------------------------------*/
-.macro RESTORE_USER_R25
-       ld  r25, [r25, TASK_THREAD + THREAD_USER_R25]
+       add     sp, sp, SZ_CALLEE_REGS
 .endm
 
 /*-------------------------------------------------------------
        ld  \out, [\tsk, TASK_THREAD_INFO]
 
        /* Go to end of page where stack begins (grows upwards) */
-       add2 \out, \out, (THREAD_SIZE - 4)/4   /* one word GUTTER */
+       add2 \out, \out, (THREAD_SIZE)/4
 
 .endm
 
         * safe-keeping not really needed, but it keeps the epilogue code
         * (SP restore) simpler/uniform.
         */
-       b.d     77f
-
-       st.a    sp, [sp, -12]   ; Make room for orig_r0 and orig_r8
+       b.d     66f
+       mov     r9, sp
 
 88: /*------Intr/Ecxp happened in user mode, "switch" stack ------ */
 
        GET_CURR_TASK_ON_CPU   r9
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-
-       /* If current task pointer cached in r25, time to
-        *  -safekeep USER r25 in task->thread_struct->user_r25
-        *  -load r25 with current task ptr
-        */
-       st.as   r25, [r9, (TASK_THREAD + THREAD_USER_R25)/4]
-       mov     r25, r9
-#endif
-
        /* With current tsk in r9, get it's kernel mode stack base */
        GET_TSK_STACK_BASE  r9, r9
 
-#ifdef PT_REGS_CANARY
-       st      0xabcdabcd, [r9, 0]
+66:
+#ifdef CONFIG_ARC_CURR_IN_REG
+       /*
+        * Treat r25 as scratch reg, save it on stack first
+        * Load it with current task pointer
+        */
+       st      r25, [r9, -4]
+       GET_CURR_TASK_ON_CPU   r25
 #endif
 
        /* Save Pre Intr/Exception User SP on kernel stack */
-       st.a    sp, [r9, -12]   ; Make room for orig_r0 and orig_r8
+       st.a    sp, [r9, -16]   ; Make room for orig_r0, ECR, user_r25
 
        /* CAUTION:
         * SP should be set at the very end when we are done with everything
        /* set SP to point to kernel mode stack */
        mov sp, r9
 
-77: /* ----- Stack Switched to kernel Mode, Now save REG FILE ----- */
+       /* ----- Stack Switched to kernel Mode, Now save REG FILE ----- */
 
 .endm
 
  * @reg [OUT] &thread_info of "current"
  */
 .macro GET_CURR_THR_INFO_FROM_SP  reg
-       and \reg, sp, ~(THREAD_SIZE - 1)
+       bic \reg, sp, (THREAD_SIZE - 1)
 .endm
 
 /*
  * Note that syscalls are implemented via TRAP which is also a exception
  * from CPU's point of view
  *-------------------------------------------------------------*/
-.macro SAVE_ALL_EXCEPTION   marker
+.macro SAVE_ALL_SYS
 
-       st      \marker, [sp, 8]        /* orig_r8 */
+       lr      r9, [ecr]
+       st      r9, [sp, 8]    /* ECR */
        st      r0, [sp, 4]    /* orig_r0, needed only for sys calls */
 
        /* Restore r9 used to code the early prologue */
        EXCPN_PROLOG_RESTORE_REG  r9
 
-       SAVE_CALLER_SAVED
-       st.a    r26, [sp, -4]   /* gp */
-       st.a    fp, [sp, -4]
-       st.a    blink, [sp, -4]
-       lr      r9, [eret]
-       st.a    r9, [sp, -4]
-       lr      r9, [erstatus]
-       st.a    r9, [sp, -4]
-       st.a    lp_count, [sp, -4]
-       lr      r9, [lp_end]
-       st.a    r9, [sp, -4]
-       lr      r9, [lp_start]
-       st.a    r9, [sp, -4]
-       lr      r9, [erbta]
-       st.a    r9, [sp, -4]
-
-#ifdef PT_REGS_CANARY
-       mov   r9, 0xdeadbeef
-       st    r9, [sp, -4]
-#endif
-
-       /* move up by 1 word to "create" pt_regs->"stack_place_holder" */
-       sub sp, sp, 4
-.endm
-
-/*--------------------------------------------------------------
- * Save scratch regs for exceptions
- *-------------------------------------------------------------*/
-.macro SAVE_ALL_SYS
-       SAVE_ALL_EXCEPTION  orig_r8_IS_EXCPN
-.endm
-
-/*--------------------------------------------------------------
- * Save scratch regs for sys calls
- *-------------------------------------------------------------*/
-.macro SAVE_ALL_TRAP
-       /*
-        * Setup pt_regs->orig_r8.
-        * Encode syscall number (r8) in upper short word of event type (r9)
-        * N.B. #1: This is already endian safe (see ptrace.h)
-        *      #2: Only r9 can be used as scratch as it is already clobbered
-        *          and it's contents are no longer needed by the latter part
-        *          of exception prologue
-        */
-       lsl  r9, r8, 16
-       or   r9, r9, orig_r8_IS_SCALL
-
-       SAVE_ALL_EXCEPTION  r9
+       SAVE_R0_TO_R12
+       PUSH    gp
+       PUSH    fp
+       PUSH    blink
+       PUSHAX  eret
+       PUSHAX  erstatus
+       PUSH    lp_count
+       PUSHAX  lp_end
+       PUSHAX  lp_start
+       PUSHAX  erbta
 .endm
 
 /*--------------------------------------------------------------
  * by hardware and that is not good.
  *-------------------------------------------------------------*/
 .macro RESTORE_ALL_SYS
+       POPAX   erbta
+       POPAX   lp_start
+       POPAX   lp_end
+
+       POP     r9
+       mov     lp_count, r9    ;LD to lp_count is not allowed
 
-       add sp, sp, 4       /* hop over unused "pt_regs->stack_place_holder" */
-
-       ld.ab   r9, [sp, 4]
-       sr      r9, [erbta]
-       ld.ab   r9, [sp, 4]
-       sr      r9, [lp_start]
-       ld.ab   r9, [sp, 4]
-       sr      r9, [lp_end]
-       ld.ab   r9, [sp, 4]
-       mov     lp_count, r9
-       ld.ab   r9, [sp, 4]
-       sr      r9, [erstatus]
-       ld.ab   r9, [sp, 4]
-       sr      r9, [eret]
-       ld.ab   blink, [sp, 4]
-       ld.ab   fp, [sp, 4]
-       ld.ab   r26, [sp, 4]    /* gp */
-       RESTORE_CALLER_SAVED
+       POPAX   erstatus
+       POPAX   eret
+       POP     blink
+       POP     fp
+       POP     gp
+       RESTORE_R12_TO_R0
 
        ld  sp, [sp] /* restore original sp */
-       /* orig_r0 and orig_r8 skipped automatically */
+       /* orig_r0, ECR, user_r25 skipped automatically */
 .endm
 
 
  *-------------------------------------------------------------*/
 .macro SAVE_ALL_INT1
 
-       /* restore original r9 , saved in int1_saved_reg
-       * It will be saved on stack in macro: SAVE_CALLER_SAVED
-       */
+       /* restore original r9 to be saved as part of reg-file */
 #ifdef CONFIG_SMP
        lr  r9, [ARC_REG_SCRATCH_DATA0]
 #else
 #endif
 
        /* now we are ready to save the remaining context :) */
-       st      orig_r8_IS_IRQ1, [sp, 8]    /* Event Type */
+       st      event_IRQ1, [sp, 8]    /* Dummy ECR */
        st      0, [sp, 4]    /* orig_r0 , N/A for IRQ */
-       SAVE_CALLER_SAVED
-       st.a    r26, [sp, -4]   /* gp */
-       st.a    fp, [sp, -4]
-       st.a    blink, [sp, -4]
-       st.a    ilink1, [sp, -4]
-       lr      r9, [status32_l1]
-       st.a    r9, [sp, -4]
-       st.a    lp_count, [sp, -4]
-       lr      r9, [lp_end]
-       st.a    r9, [sp, -4]
-       lr      r9, [lp_start]
-       st.a    r9, [sp, -4]
-       lr      r9, [bta_l1]
-       st.a    r9, [sp, -4]
-
-#ifdef PT_REGS_CANARY
-       mov   r9, 0xdeadbee1
-       st    r9, [sp, -4]
-#endif
-       /* move up by 1 word to "create" pt_regs->"stack_place_holder" */
-       sub sp, sp, 4
+
+       SAVE_R0_TO_R12
+       PUSH    gp
+       PUSH    fp
+       PUSH    blink
+       PUSH    ilink1
+       PUSHAX  status32_l1
+       PUSH    lp_count
+       PUSHAX  lp_end
+       PUSHAX  lp_start
+       PUSHAX  bta_l1
 .endm
 
 .macro SAVE_ALL_INT2
        ld  r9, [@int2_saved_reg]
 
        /* now we are ready to save the remaining context :) */
-       st      orig_r8_IS_IRQ2, [sp, 8]    /* Event Type */
+       st      event_IRQ2, [sp, 8]    /* Dummy ECR */
        st      0, [sp, 4]    /* orig_r0 , N/A for IRQ */
-       SAVE_CALLER_SAVED
-       st.a    r26, [sp, -4]   /* gp */
-       st.a    fp, [sp, -4]
-       st.a    blink, [sp, -4]
-       st.a    ilink2, [sp, -4]
-       lr      r9, [status32_l2]
-       st.a    r9, [sp, -4]
-       st.a    lp_count, [sp, -4]
-       lr      r9, [lp_end]
-       st.a    r9, [sp, -4]
-       lr      r9, [lp_start]
-       st.a    r9, [sp, -4]
-       lr      r9, [bta_l2]
-       st.a    r9, [sp, -4]
-
-#ifdef PT_REGS_CANARY
-       mov   r9, 0xdeadbee2
-       st    r9, [sp, -4]
-#endif
 
-       /* move up by 1 word to "create" pt_regs->"stack_place_holder" */
-       sub sp, sp, 4
+       SAVE_R0_TO_R12
+       PUSH    gp
+       PUSH    fp
+       PUSH    blink
+       PUSH    ilink2
+       PUSHAX  status32_l2
+       PUSH    lp_count
+       PUSHAX  lp_end
+       PUSHAX  lp_start
+       PUSHAX  bta_l2
 .endm
 
 /*--------------------------------------------------------------
  *-------------------------------------------------------------*/
 
 .macro RESTORE_ALL_INT1
-       add sp, sp, 4       /* hop over unused "pt_regs->stack_place_holder" */
-
-       ld.ab   r9, [sp, 4] /* Actual reg file */
-       sr      r9, [bta_l1]
-       ld.ab   r9, [sp, 4]
-       sr      r9, [lp_start]
-       ld.ab   r9, [sp, 4]
-       sr      r9, [lp_end]
-       ld.ab   r9, [sp, 4]
-       mov     lp_count, r9
-       ld.ab   r9, [sp, 4]
-       sr      r9, [status32_l1]
-       ld.ab   r9, [sp, 4]
-       mov     ilink1, r9
-       ld.ab   blink, [sp, 4]
-       ld.ab   fp, [sp, 4]
-       ld.ab   r26, [sp, 4]    /* gp */
-       RESTORE_CALLER_SAVED
+       POPAX   bta_l1
+       POPAX   lp_start
+       POPAX   lp_end
+
+       POP     r9
+       mov     lp_count, r9    ;LD to lp_count is not allowed
+
+       POPAX   status32_l1
+       POP     ilink1
+       POP     blink
+       POP     fp
+       POP     gp
+       RESTORE_R12_TO_R0
 
        ld  sp, [sp] /* restore original sp */
-       /* orig_r0 and orig_r8 skipped automatically */
+       /* orig_r0, ECR, user_r25 skipped automatically */
 .endm
 
 .macro RESTORE_ALL_INT2
-       add sp, sp, 4       /* hop over unused "pt_regs->stack_place_holder" */
-
-       ld.ab   r9, [sp, 4]
-       sr      r9, [bta_l2]
-       ld.ab   r9, [sp, 4]
-       sr      r9, [lp_start]
-       ld.ab   r9, [sp, 4]
-       sr      r9, [lp_end]
-       ld.ab   r9, [sp, 4]
-       mov     lp_count, r9
-       ld.ab   r9, [sp, 4]
-       sr      r9, [status32_l2]
-       ld.ab   r9, [sp, 4]
-       mov     ilink2, r9
-       ld.ab   blink, [sp, 4]
-       ld.ab   fp, [sp, 4]
-       ld.ab   r26, [sp, 4]    /* gp */
-       RESTORE_CALLER_SAVED
+       POPAX   bta_l2
+       POPAX   lp_start
+       POPAX   lp_end
 
-       ld  sp, [sp] /* restore original sp */
-       /* orig_r0 and orig_r8 skipped automatically */
+       POP     r9
+       mov     lp_count, r9    ;LD to lp_count is not allowed
 
+       POPAX   status32_l2
+       POP     ilink2
+       POP     blink
+       POP     fp
+       POP     gp
+       RESTORE_R12_TO_R0
+
+       ld  sp, [sp] /* restore original sp */
+       /* orig_r0, ECR, user_r25 skipped automatically */
 .endm
 
 
index 57898a17eb8219ac20ec8cd5fb116f10702082e5..c0a72105ee0b0946e57a094b24fa5bbb3cb8f425 100644 (file)
@@ -21,6 +21,6 @@
 extern void __init arc_init_IRQ(void);
 extern int __init get_hw_config_num_irq(void);
 
-void __cpuinit arc_local_timer_setup(unsigned int cpu);
+void arc_local_timer_setup(unsigned int cpu);
 
 #endif
index eac071668201a143bf0e93367cd277441b520fb8..d99f79bcf865a248ddb1c1dfa1eb35a58ae5f948 100644 (file)
 
 #include <asm/arcregs.h>
 
+/* status32 Reg bits related to Interrupt Handling */
+#define STATUS_E1_BIT          1       /* Int 1 enable */
+#define STATUS_E2_BIT          2       /* Int 2 enable */
+#define STATUS_A1_BIT          3       /* Int 1 active */
+#define STATUS_A2_BIT          4       /* Int 2 active */
+
+#define STATUS_E1_MASK         (1<<STATUS_E1_BIT)
+#define STATUS_E2_MASK         (1<<STATUS_E2_BIT)
+#define STATUS_A1_MASK         (1<<STATUS_A1_BIT)
+#define STATUS_A2_MASK         (1<<STATUS_A2_BIT)
+
+/* Other Interrupt Handling related Aux regs */
+#define AUX_IRQ_LEV            0x200   /* IRQ Priority: L1 or L2 */
+#define AUX_IRQ_HINT           0x201   /* For generating Soft Interrupts */
+#define AUX_IRQ_LV12           0x43    /* interrupt level register */
+
+#define AUX_IENABLE            0x40c
+#define AUX_ITRIGGER           0x40d
+#define AUX_IPULSE             0x415
+
 #ifndef __ASSEMBLY__
 
 /******************************************************************
index 4930957ca3d38c4cb312aa60f21ffa9cbb413087..b65fca7ffeb5e70d5e72e8bf011fc7834d9d33ea 100644 (file)
@@ -31,7 +31,7 @@ static inline void arch_kgdb_breakpoint(void)
        __asm__ __volatile__ ("trap_s   0x4\n");
 }
 
-extern void kgdb_trap(struct pt_regs *regs, int param);
+extern void kgdb_trap(struct pt_regs *regs);
 
 enum arc700_linux_regnums {
        _R0             = 0,
@@ -53,7 +53,7 @@ enum arc700_linux_regnums {
 };
 
 #else
-#define kgdb_trap(regs, param)
+#define kgdb_trap(regs)
 #endif
 
 #endif /* __ARC_KGDB_H__ */
index 4d9c211fce70a28fead34ae9faceb39927a139b5..944dbedb38b5949fdb61ebb6c59eff44b17642f0 100644 (file)
@@ -50,11 +50,9 @@ struct kprobe_ctlblk {
 
 int kprobe_fault_handler(struct pt_regs *regs, unsigned long cause);
 void kretprobe_trampoline(void);
-void trap_is_kprobe(unsigned long cause, unsigned long address,
-                          struct pt_regs *regs);
+void trap_is_kprobe(unsigned long address, struct pt_regs *regs);
 #else
-static void trap_is_kprobe(unsigned long cause, unsigned long address,
-                          struct pt_regs *regs)
+static void trap_is_kprobe(unsigned long address, struct pt_regs *regs)
 {
 }
 #endif
index 56b02320f1a928b3614f7ec6de3604b2ff9f65b4..7c03fe61759c2262d30550cfc6ad73dd363b2903 100644 (file)
@@ -9,6 +9,40 @@
 #ifndef _ASM_ARC_MMU_H
 #define _ASM_ARC_MMU_H
 
+#if defined(CONFIG_ARC_MMU_V1)
+#define CONFIG_ARC_MMU_VER 1
+#elif defined(CONFIG_ARC_MMU_V2)
+#define CONFIG_ARC_MMU_VER 2
+#elif defined(CONFIG_ARC_MMU_V3)
+#define CONFIG_ARC_MMU_VER 3
+#endif
+
+/* MMU Management regs */
+#define ARC_REG_MMU_BCR                0x06f
+#define ARC_REG_TLBPD0         0x405
+#define ARC_REG_TLBPD1         0x406
+#define ARC_REG_TLBINDEX       0x407
+#define ARC_REG_TLBCOMMAND     0x408
+#define ARC_REG_PID            0x409
+#define ARC_REG_SCRATCH_DATA0  0x418
+
+/* Bits in MMU PID register */
+#define MMU_ENABLE             (1 << 31)       /* Enable MMU for process */
+
+/* Error code if probe fails */
+#define TLB_LKUP_ERR           0x80000000
+
+/* TLB Commands */
+#define TLBWrite    0x1
+#define TLBRead     0x2
+#define TLBGetIndex 0x3
+#define TLBProbe    0x4
+
+#if (CONFIG_ARC_MMU_VER >= 2)
+#define TLBWriteNI  0x5                /* write JTLB without inv uTLBs */
+#define TLBIVUTLB   0x6                /* explicitly inv uTLBs */
+#endif
+
 #ifndef __ASSEMBLY__
 
 typedef struct {
@@ -18,6 +52,16 @@ typedef struct {
 #endif
 } mm_context_t;
 
+#ifdef CONFIG_ARC_DBG_TLB_PARANOIA
+void tlb_paranoid_check(unsigned int pid_sw, unsigned long address);
+#else
+#define tlb_paranoid_check(a, b)
 #endif
 
+void arc_mmu_init(void);
+extern char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len);
+void __init read_decode_mmu_bcr(void);
+
+#endif /* !__ASSEMBLY__ */
+
 #endif
index ab84bf131fe135a2070c4a22bc5c177020787759..9c8aa41e45c2248b0ee39a23c3802e4f7425d358 100644 (file)
@@ -96,13 +96,8 @@ typedef unsigned long pgtable_t;
 
 #define virt_addr_valid(kaddr)  pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
-/* Default Permissions for page, used in mmap.c */
-#ifdef CONFIG_ARC_STACK_NONEXEC
+/* Default Permissions for stack/heaps pages (Non Executable) */
 #define VM_DATA_DEFAULT_FLAGS   (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE)
-#else
-#define VM_DATA_DEFAULT_FLAGS   (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-#endif
 
 #define WANT_PAGE_VIRTUAL   1
 
index c110ac87d22bcc56ee2448da299f7cb48f6d6763..4749a0eee1cffcf3a06c916353af6db9facc19a1 100644 (file)
 /* ioremap */
 #define PAGE_KERNEL_NO_CACHE __pgprot(_K_PAGE_PERMS)
 
+/* Masks for actual TLB "PD"s */
+#define PTE_BITS_IN_PD0        (_PAGE_GLOBAL | _PAGE_PRESENT)
+#define PTE_BITS_IN_PD1        (PAGE_MASK | _PAGE_CACHEABLE | \
+                        _PAGE_U_EXECUTE | _PAGE_U_WRITE | _PAGE_U_READ | \
+                        _PAGE_K_EXECUTE | _PAGE_K_WRITE | _PAGE_K_READ)
+
 /**************************************************************************
  * Mapping of vm_flags (Generic VM) to PTE flags (arch specific)
  *
index 5f26b2c1cba0074f68123061efb8441061df1f96..15334ab66b56e110ac67152bac96317c3f8368ff 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef __ASSEMBLY__
 
 #include <asm/arcregs.h>       /* for STATUS_E1_MASK et all */
+#include <asm/ptrace.h>
 
 /* Arch specific stuff which needs to be saved per task.
  * However these items are not so important so as to earn a place in
@@ -28,10 +29,6 @@ struct thread_struct {
        unsigned long ksp;      /* kernel mode stack pointer */
        unsigned long callee_reg;       /* pointer to callee regs */
        unsigned long fault_address;    /* dbls as brkpt holder as well */
-       unsigned long cause_code;       /* Exception Cause Code (ECR) */
-#ifdef CONFIG_ARC_CURR_IN_REG
-       unsigned long user_r25;
-#endif
 #ifdef CONFIG_ARC_FPU_SAVE_RESTORE
        struct arc_fpu fpu;
 #endif
@@ -50,7 +47,7 @@ struct task_struct;
 unsigned long thread_saved_pc(struct task_struct *t);
 
 #define task_pt_regs(p) \
-       ((struct pt_regs *)(THREAD_SIZE - 4 + (void *)task_stack_page(p)) - 1)
+       ((struct pt_regs *)(THREAD_SIZE + (void *)task_stack_page(p)) - 1)
 
 /* Free all resources held by a thread. */
 #define release_thread(thread) do { } while (0)
@@ -75,11 +72,15 @@ unsigned long thread_saved_pc(struct task_struct *t);
 
 /*
  * Where abouts of Task's sp, fp, blink when it was last seen in kernel mode.
- * These can't be derived from pt_regs as that would give correp user-mode val
+ * Look in process.c for details of kernel stack layout
  */
 #define KSTK_ESP(tsk)   (tsk->thread.ksp)
-#define KSTK_BLINK(tsk) (*((unsigned int *)((KSTK_ESP(tsk)) + (13+1+1)*4)))
-#define KSTK_FP(tsk)    (*((unsigned int *)((KSTK_ESP(tsk)) + (13+1)*4)))
+
+#define KSTK_REG(tsk, off)     (*((unsigned int *)(KSTK_ESP(tsk) + \
+                                       sizeof(struct callee_regs) + off)))
+
+#define KSTK_BLINK(tsk) KSTK_REG(tsk, 4)
+#define KSTK_FP(tsk)    KSTK_REG(tsk, 0)
 
 /*
  * Do necessary setup to start up a newly executed thread.
index 6179de7e07c21ca4875017adc1107c0e7b0b46c4..c9938e7a7dbd3b596fc3c0021d8ff57548719402 100644 (file)
 /* THE pt_regs: Defines how regs are saved during entry into kernel */
 
 struct pt_regs {
-       /*
-        * 1 word gutter after reg-file has been saved
-        * Technically not needed, Since SP always points to a "full" location
-        * (vs. "empty"). But pt_regs is shared with tools....
-        */
-       long res;
 
        /* Real registers */
        long bta;       /* bta_l1, bta_l2, erbta */
@@ -50,22 +44,32 @@ struct pt_regs {
        long sp;        /* user/kernel sp depending on where we came from  */
        long orig_r0;
 
-       /*to distinguish bet excp, syscall, irq */
+       /*
+        * To distinguish bet excp, syscall, irq
+        * For traps and exceptions, Exception Cause Register.
+        *      ECR: <00> <VV> <CC> <PP>
+        *      Last word used by Linux for extra state mgmt (syscall-restart)
+        * For interrupts, use artificial ECR values to note current prio-level
+        */
        union {
+               struct {
 #ifdef CONFIG_CPU_BIG_ENDIAN
-               /* so that assembly code is same for LE/BE */
-               unsigned long orig_r8:16, event:16;
+                       unsigned long state:8, ecr_vec:8,
+                                     ecr_cause:8, ecr_param:8;
 #else
-               unsigned long event:16, orig_r8:16;
+                       unsigned long ecr_param:8, ecr_cause:8,
+                                     ecr_vec:8, state:8;
 #endif
-               long orig_r8_word;
+               };
+               unsigned long event;
        };
+
+       long user_r25;
 };
 
 /* Callee saved registers - need to be saved only when you are scheduled out */
 
 struct callee_regs {
-       long res;       /* Again this is not needed */
        long r25;
        long r24;
        long r23;
@@ -99,18 +103,20 @@ struct callee_regs {
 /* return 1 if PC in delay slot */
 #define delay_mode(regs) ((regs->status32 & STATUS_DE_MASK) == STATUS_DE_MASK)
 
-#define in_syscall(regs)    (regs->event & orig_r8_IS_SCALL)
-#define in_brkpt_trap(regs) (regs->event & orig_r8_IS_BRKPT)
+#define in_syscall(regs)    ((regs->ecr_vec == ECR_V_TRAP) && !regs->ecr_param)
+#define in_brkpt_trap(regs) ((regs->ecr_vec == ECR_V_TRAP) && regs->ecr_param)
+
+#define STATE_SCALL_RESTARTED  0x01
 
-#define syscall_wont_restart(regs) (regs->event |= orig_r8_IS_SCALL_RESTARTED)
-#define syscall_restartable(regs) !(regs->event &  orig_r8_IS_SCALL_RESTARTED)
+#define syscall_wont_restart(reg) (reg->state |= STATE_SCALL_RESTARTED)
+#define syscall_restartable(reg) !(reg->state &  STATE_SCALL_RESTARTED)
 
 #define current_pt_regs()                                      \
 ({                                                             \
        /* open-coded current_thread_info() */                  \
        register unsigned long sp asm ("sp");                   \
        unsigned long pg_start = (sp & ~(THREAD_SIZE - 1));     \
-       (struct pt_regs *)(pg_start + THREAD_SIZE - 4) - 1;     \
+       (struct pt_regs *)(pg_start + THREAD_SIZE) - 1; \
 })
 
 static inline long regs_return_value(struct pt_regs *regs)
@@ -120,11 +126,4 @@ static inline long regs_return_value(struct pt_regs *regs)
 
 #endif /* !__ASSEMBLY__ */
 
-#define orig_r8_IS_SCALL               0x0001
-#define orig_r8_IS_SCALL_RESTARTED     0x0002
-#define orig_r8_IS_BRKPT               0x0004
-#define orig_r8_IS_EXCPN               0x0008
-#define orig_r8_IS_IRQ1                        0x0010
-#define orig_r8_IS_IRQ2                        0x0020
-
 #endif /* __ASM_PTRACE_H */
index 33ab3048e9b20a6447475ec417b3fc10a91a309a..29de098043064a20112dd7ffd02f86059261ae44 100644 (file)
@@ -18,7 +18,7 @@ static inline long
 syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
 {
        if (user_mode(regs) && in_syscall(regs))
-               return regs->orig_r8;
+               return regs->r8;
        else
                return -1;
 }
@@ -26,8 +26,7 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
 static inline void
 syscall_rollback(struct task_struct *task, struct pt_regs *regs)
 {
-       /* XXX: I can't fathom how pt_regs->r8 will be clobbered ? */
-       regs->r8 = regs->orig_r8;
+       regs->r0 = regs->orig_r0;
 }
 
 static inline long
index a5ff961b1efcb09ca8db2826e4ad55d5b4e86a2f..8a1ec96012ae046e26d05e7d0ba47cb9c8c6efe1 100644 (file)
@@ -9,9 +9,9 @@
 #ifndef __ASM_TLB_MMU_V1_H__
 #define __ASM_TLB_MMU_V1_H__
 
-#if defined(__ASSEMBLY__) && defined(CONFIG_ARC_MMU_VER == 1)
+#include <asm/mmu.h>
 
-#include <asm/tlb.h>
+#if defined(__ASSEMBLY__) && (CONFIG_ARC_MMU_VER == 1)
 
 .macro TLB_WRITE_HEURISTICS
 
index cb0c708ca6654cd38d0d73f40e6f43135e34c01e..a9db5f62aaf37988fe8806ac4ee0a14edf713309 100644 (file)
@@ -9,18 +9,6 @@
 #ifndef _ASM_ARC_TLB_H
 #define _ASM_ARC_TLB_H
 
-#ifdef __KERNEL__
-
-#include <asm/pgtable.h>
-
-/* Masks for actual TLB "PD"s */
-#define PTE_BITS_IN_PD0        (_PAGE_GLOBAL | _PAGE_PRESENT)
-#define PTE_BITS_IN_PD1        (PAGE_MASK | _PAGE_CACHEABLE | \
-                        _PAGE_U_EXECUTE | _PAGE_U_WRITE | _PAGE_U_READ | \
-                        _PAGE_K_EXECUTE | _PAGE_K_WRITE | _PAGE_K_READ)
-
-#ifndef __ASSEMBLY__
-
 #define tlb_flush(tlb)                         \
 do {                                           \
        if (tlb->fullmm)                        \
@@ -56,18 +44,4 @@ do {                                                                 \
 #include <linux/pagemap.h>
 #include <asm-generic/tlb.h>
 
-#ifdef CONFIG_ARC_DBG_TLB_PARANOIA
-void tlb_paranoid_check(unsigned int pid_sw, unsigned long address);
-#else
-#define tlb_paranoid_check(a, b)
-#endif
-
-void arc_mmu_init(void);
-extern char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len);
-void __init read_decode_mmu_bcr(void);
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_ARC_TLB_H */
index 5dbe63f17b66e18dad73a28a1b96d53f649af25a..60702f3751d2bd7077286fbb929f86c676558e1e 100644 (file)
 
 #ifdef CONFIG_ARC_MISALIGN_ACCESS
 int misaligned_fixup(unsigned long address, struct pt_regs *regs,
-                    unsigned long cause, struct callee_regs *cregs);
+                    struct callee_regs *cregs);
 #else
 static inline int
 misaligned_fixup(unsigned long address, struct pt_regs *regs,
-                unsigned long cause, struct callee_regs *cregs)
+                struct callee_regs *cregs)
 {
        return 0;
 }
index 30333cec0fef274365aeb559084d58a5ee023a9b..2618cc13ba75ff1106f82f5604b54c691305bd76 100644 (file)
  *
  * This is to decouple pt_regs from user-space ABI, to be able to change it
  * w/o affecting the ABI.
- * Although the layout (initial padding) is similar to pt_regs to have some
- * optimizations when copying pt_regs to/from user_regs_struct.
+ *
+ * The intermediate pad,pad2 are relics of initial layout based on pt_regs
+ * for optimizations when copying pt_regs to/from user_regs_struct.
+ * We no longer need them, but can't be changed as they are part of ABI now.
  *
  * Also, sigcontext only care about the scratch regs as that is what we really
- * save/restore for signal handling.
+ * save/restore for signal handling. However gdb also uses the same struct
+ * hence callee regs need to be in there too.
 */
 struct user_regs_struct {
 
+       long pad;
        struct {
-               long pad;
                long bta, lp_start, lp_end, lp_count;
                long status32, ret, blink, fp, gp;
                long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
                long sp;
        } scratch;
+       long pad2;
        struct {
-               long pad;
                long r25, r24, r23, r22, r21, r20;
                long r19, r18, r17, r16, r15, r14, r13;
        } callee;
        long efa;       /* break pt addr, for break points in delay slots */
-       long stop_pc;   /* give dbg stop_pc directly after checking orig_r8 */
+       long stop_pc;   /* give dbg stop_pc after ensuring brkpt trap */
 };
 #endif /* !__ASSEMBLY__ */
 
index 7dcda70252411949b32f8b9b112c9e37bfec0edc..6c3aa0edb9b5bc1914d006b2a22b766f71adba9c 100644 (file)
@@ -24,9 +24,6 @@ int main(void)
 
        DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
        DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg));
-#ifdef CONFIG_ARC_CURR_IN_REG
-       DEFINE(THREAD_USER_R25, offsetof(struct thread_struct, user_r25));
-#endif
        DEFINE(THREAD_FAULT_ADDR,
               offsetof(struct thread_struct, fault_address));
 
@@ -49,7 +46,7 @@ int main(void)
        BLANK();
 
        DEFINE(PT_status32, offsetof(struct pt_regs, status32));
-       DEFINE(PT_orig_r8, offsetof(struct pt_regs, orig_r8_word));
+       DEFINE(PT_event, offsetof(struct pt_regs, event));
        DEFINE(PT_sp, offsetof(struct pt_regs, sp));
        DEFINE(PT_r0, offsetof(struct pt_regs, r0));
        DEFINE(PT_r1, offsetof(struct pt_regs, r1));
@@ -60,5 +57,7 @@ int main(void)
        DEFINE(PT_r6, offsetof(struct pt_regs, r6));
        DEFINE(PT_r7, offsetof(struct pt_regs, r7));
 
+       DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
+       DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
        return 0;
 }
index 60844dac6132a0c689d53351603ac448295598bb..34410eb1a308e7d801abbc6ece893db54975f9c7 100644 (file)
@@ -23,10 +23,6 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
        unsigned int tmp;
        unsigned int prev = (unsigned int)prev_task;
        unsigned int next = (unsigned int)next_task;
-       int num_words_to_skip = 1;
-#ifdef CONFIG_ARC_CURR_IN_REG
-       num_words_to_skip++;
-#endif
 
        __asm__ __volatile__(
                /* FP/BLINK save generated by gcc (standard function prologue */
@@ -44,8 +40,9 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
                "st.a    r24, [sp, -4]   \n\t"
 #ifndef CONFIG_ARC_CURR_IN_REG
                "st.a    r25, [sp, -4]   \n\t"
+#else
+               "sub     sp, sp, 4      \n\t"   /* usual r25 placeholder */
 #endif
-               "sub     sp, sp, %4      \n\t"  /* create gutter at top */
 
                /* set ksp of outgoing task in tsk->thread.ksp */
                "st.as   sp, [%3, %1]    \n\t"
@@ -76,10 +73,10 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
 
                /* start loading it's CALLEE reg file */
 
-               "add    sp, sp, %4     \n\t"    /* skip gutter at top */
-
 #ifndef CONFIG_ARC_CURR_IN_REG
                "ld.ab   r25, [sp, 4]   \n\t"
+#else
+               "add    sp, sp, 4       \n\t"
 #endif
                "ld.ab   r24, [sp, 4]   \n\t"
                "ld.ab   r23, [sp, 4]   \n\t"
@@ -100,8 +97,7 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
                /* FP/BLINK restore generated by gcc (standard func epilogue */
 
                : "=r"(tmp)
-               : "n"((TASK_THREAD + THREAD_KSP) / 4), "r"(next), "r"(prev),
-                 "n"(num_words_to_skip * 4)
+               : "n"((TASK_THREAD + THREAD_KSP) / 4), "r"(next), "r"(prev)
                : "blink"
        );
 
index 0c6d664d4a8379512c32c7b52d8fbd0d321cf70e..1d7165156e1708ee6a24391ed9218de330603ccf 100644 (file)
@@ -142,7 +142,7 @@ VECTOR   reserved                ; Reserved Exceptions
 .endr
 
 #include <linux/linkage.h>   /* ARC_{EXTRY,EXIT} */
-#include <asm/entry.h>       /* SAVE_ALL_{INT1,INT2,TRAP...} */
+#include <asm/entry.h>       /* SAVE_ALL_{INT1,INT2,SYS...} */
 #include <asm/errno.h>
 #include <asm/arcregs.h>
 #include <asm/irqflags.h>
@@ -274,10 +274,8 @@ ARC_ENTRY instr_service
        SWITCH_TO_KERNEL_STK
        SAVE_ALL_SYS
 
-       lr  r0, [ecr]
-       lr  r1, [efa]
-
-       mov r2, sp
+       lr  r0, [efa]
+       mov r1, sp
 
        FAKE_RET_FROM_EXCPN r9
 
@@ -298,9 +296,8 @@ ARC_ENTRY mem_service
        SWITCH_TO_KERNEL_STK
        SAVE_ALL_SYS
 
-       lr  r0, [ecr]
-       lr  r1, [efa]
-       mov r2, sp
+       lr  r0, [efa]
+       mov r1, sp
        bl  do_memory_error
        b   ret_from_exception
 ARC_EXIT mem_service
@@ -317,11 +314,14 @@ ARC_ENTRY EV_MachineCheck
        SWITCH_TO_KERNEL_STK
        SAVE_ALL_SYS
 
-       lr  r0, [ecr]
-       lr  r1, [efa]
-       mov r2, sp
+       lr  r2, [ecr]
+       lr  r0, [efa]
+       mov r1, sp
+
+       lsr     r3, r2, 8
+       bmsk    r3, r3, 7
+       brne    r3, ECR_C_MCHK_DUP_TLB, 1f
 
-       brne    r0, 0x200100, 1f
        bl      do_tlb_overlap_fault
        b       ret_from_exception
 
@@ -355,8 +355,8 @@ ARC_ENTRY EV_TLBProtV
        ;  ecr and efa were not saved in case an Intr sneaks in
        ;  after fake rtie
        ;
-       lr  r3, [ecr]
-       lr  r4, [efa]
+       lr  r2, [ecr]
+       lr  r1, [efa]   ; Faulting Data address
 
        ; --------(4) Return from CPU Exception Mode ---------
        ;  Fake a rtie, but rtie to next label
@@ -368,31 +368,25 @@ ARC_ENTRY EV_TLBProtV
        ;------ (5) Type of Protection Violation? ----------
        ;
        ; ProtV Hardware Exception is triggered for Access Faults of 2 types
-       ;   -Access Violaton (WRITE to READ ONLY Page) - for linux COW
-       ;   -Unaligned Access (READ/WRITE on odd boundary)
+       ;   -Access Violaton    : 00_23_(00|01|02|03)_00
+       ;                                x  r  w  r+w
+       ;   -Unaligned Access   : 00_23_04_00
        ;
-       cmp r3, 0x230400    ; Misaligned data access ?
-       beq 4f
+       bbit1 r2, ECR_C_BIT_PROTV_MISALIG_DATA, 4f
 
        ;========= (6a) Access Violation Processing ========
-       cmp r3, 0x230100
-       mov r1, 0x0              ; if LD exception ? write = 0
-       mov.ne r1, 0x1           ; else write = 1
-
-       mov r2, r4              ; faulting address
        mov r0, sp              ; pt_regs
        bl  do_page_fault
        b   ret_from_exception
 
        ;========== (6b) Non aligned access ============
 4:
-       mov r0, r3              ; cause code
-       mov r1, r4              ; faulting address
-       mov r2, sp              ; pt_regs
+       mov r0, r1
+       mov r1, sp              ; pt_regs
 
 #ifdef  CONFIG_ARC_MISALIGN_ACCESS
        SAVE_CALLEE_SAVED_USER
-       mov r3, sp              ; callee_regs
+       mov r2, sp              ; callee_regs
 
        bl  do_misaligned_access
 
@@ -419,9 +413,8 @@ ARC_ENTRY EV_PrivilegeV
        SWITCH_TO_KERNEL_STK
        SAVE_ALL_SYS
 
-       lr  r0, [ecr]
-       lr  r1, [efa]
-       mov r2, sp
+       lr  r0, [efa]
+       mov r1, sp
 
        FAKE_RET_FROM_EXCPN r9
 
@@ -440,9 +433,8 @@ ARC_ENTRY EV_Extension
        SWITCH_TO_KERNEL_STK
        SAVE_ALL_SYS
 
-       lr  r0, [ecr]
-       lr  r1, [efa]
-       mov r2, sp
+       lr  r0, [efa]
+       mov r1, sp
        bl  do_extension_fault
        b   ret_from_exception
 ARC_EXIT EV_Extension
@@ -498,11 +490,8 @@ tracesys_exit:
 trap_with_param:
 
        ; stop_pc info by gdb needs this info
-       stw orig_r8_IS_BRKPT, [sp, PT_orig_r8]
-
-       mov r0, r12
-       lr  r1, [efa]
-       mov r2, sp
+       lr  r0, [efa]
+       mov r1, sp
 
        ; Now that we have read EFA, its safe to do "fake" rtie
        ;   and get out of CPU exception mode
@@ -544,11 +533,11 @@ ARC_ENTRY EV_Trap
        lr  r9, [erstatus]
 
        SWITCH_TO_KERNEL_STK
-       SAVE_ALL_TRAP
+       SAVE_ALL_SYS
 
        ;------- (4) What caused the Trap --------------
        lr     r12, [ecr]
-       and.f  0, r12, ECR_PARAM_MASK
+       bmsk.f 0, r12, 7
        bnz    trap_with_param
 
        ; ======= (5a) Trap is due to System Call ========
@@ -589,11 +578,7 @@ ARC_ENTRY ret_from_exception
        ; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32
        ld  r8, [sp, PT_status32]   ; returning to User/Kernel Mode
 
-#ifdef CONFIG_PREEMPT
        bbit0  r8, STATUS_U_BIT, resume_kernel_mode
-#else
-       bbit0  r8, STATUS_U_BIT, restore_regs
-#endif
 
        ; Before returning to User mode check-for-and-complete any pending work
        ; such as rescheduling/signal-delivery etc.
@@ -653,10 +638,10 @@ resume_user_mode_begin:
        b      resume_user_mode_begin   ; unconditionally back to U mode ret chks
                                        ; for single exit point from this block
 
-#ifdef CONFIG_PREEMPT
-
 resume_kernel_mode:
 
+#ifdef CONFIG_PREEMPT
+
        ; Can't preempt if preemption disabled
        GET_CURR_THR_INFO_FROM_SP   r10
        ld  r8, [r10, THREAD_INFO_PREEMPT_COUNT]
@@ -687,17 +672,6 @@ restore_regs :
        ; XXX can this be optimised out
        IRQ_DISABLE_SAVE    r9, r10     ;@r10 has prisitine (pre-disable) copy
 
-#ifdef CONFIG_ARC_CURR_IN_REG
-       ; Restore User R25
-       ; Earlier this used to be only for returning to user mode
-       ; However with 2 levels of IRQ this can also happen even if
-       ; in kernel mode
-       ld r9, [sp, PT_sp]
-       brhs r9, VMALLOC_START, 8f
-       RESTORE_USER_R25
-8:
-#endif
-
        ; Restore REG File. In case multiple Events outstanding,
        ; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None
        ; Note that we use realtime STATUS32 (not pt_regs->status32) to
@@ -714,8 +688,17 @@ not_exception:
 
 #ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
 
+       ; Level 2 interrupt return Path - from hardware standpoint
        bbit0  r10, STATUS_A2_BIT, not_level2_interrupt
 
+       ;------------------------------------------------------------------
+       ; However the context returning might not have taken L2 intr itself
+       ; e.g. Task'A' user-code -> L2 intr -> schedule -> 'B' user-code ret
+       ; Special considerations needed for the context which took L2 intr
+
+       ld   r9, [sp, PT_event]        ; Ensure this is L2 intr context
+       brne r9, event_IRQ2, 149f
+
        ;------------------------------------------------------------------
        ; if L2 IRQ interrupted a L1 ISR,  we'd disbaled preemption earlier
        ; so that sched doesnt move to new task, causing L1 to be delayed
@@ -723,19 +706,15 @@ not_exception:
        ; things to what they were, before returning from L2 context
        ;----------------------------------------------------------------
 
-       ldw  r9, [sp, PT_orig_r8]      ; get orig_r8 to make sure it is
-       brne r9, orig_r8_IS_IRQ2, 149f ; infact a L2 ISR ret path
-
        ld r9, [sp, PT_status32]       ; get statu32_l2 (saved in pt_regs)
        bbit0 r9, STATUS_A1_BIT, 149f  ; L1 not active when L2 IRQ, so normal
 
-       ; A1 is set in status32_l2
        ; decrement thread_info->preempt_count (re-enable preemption)
        GET_CURR_THR_INFO_FROM_SP   r10
        ld      r9, [r10, THREAD_INFO_PREEMPT_COUNT]
 
        ; paranoid check, given A1 was active when A2 happened, preempt count
-       ; must not be 0 beccause we would have incremented it.
+       ; must not be 0 because we would have incremented it.
        ; If this does happen we simply HALT as it means a BUG !!!
        cmp     r9, 0
        bnz     2f
index 006dec3fc3534cbbf179e5c0d002d7c3c258a7af..2a913f85a74793ae47c19e90deea0f9ef69793e1 100644 (file)
@@ -27,6 +27,8 @@ stext:
        ; Don't clobber r0-r4 yet. It might have bootloader provided info
        ;-------------------------------------------------------------------
 
+       sr      @_int_vec_base_lds, [AUX_INTR_VEC_BASE]
+
 #ifdef CONFIG_SMP
        ; Only Boot (Master) proceeds. Others wait in platform dependent way
        ;       IDENTITY Reg [ 3  2  1  0 ]
index 8115fa531575f0d46d6fb030aa05270f7c7d6983..305b3f866aa7107a027a61aa1752d021c44ab393 100644 (file)
  * -Disable all IRQs (on CPU side)
  * -Optionally, setup the High priority Interrupts as Level 2 IRQs
  */
-void __cpuinit arc_init_IRQ(void)
+void arc_init_IRQ(void)
 {
        int level_mask = 0;
 
-       write_aux_reg(AUX_INTR_VEC_BASE, _int_vec_base_lds);
-
        /* Disable all IRQs: enable them as devices request */
        write_aux_reg(AUX_IENABLE, 0);
 
        /* setup any high priority Interrupts (Level2 in ARCompact jargon) */
-#ifdef CONFIG_ARC_IRQ3_LV2
-       level_mask |= (1 << 3);
-#endif
-#ifdef CONFIG_ARC_IRQ5_LV2
-       level_mask |= (1 << 5);
-#endif
-#ifdef CONFIG_ARC_IRQ6_LV2
-       level_mask |= (1 << 6);
-#endif
+       level_mask |= IS_ENABLED(CONFIG_ARC_IRQ3_LV2) << 3;
+       level_mask |= IS_ENABLED(CONFIG_ARC_IRQ5_LV2) << 5;
+       level_mask |= IS_ENABLED(CONFIG_ARC_IRQ6_LV2) << 6;
 
        if (level_mask) {
                pr_info("Level-2 interrupts bitset %x\n", level_mask);
index 52bdc83c1495b5bf31a685998f7a5d7b9a1bd15e..a7698fb148180bfb17f9c5f0c7cae1f229bf216e 100644 (file)
@@ -169,7 +169,7 @@ int kgdb_arch_init(void)
        return 0;
 }
 
-void kgdb_trap(struct pt_regs *regs, int param)
+void kgdb_trap(struct pt_regs *regs)
 {
        /* trap_s 3 is used for breakpoints that overwrite existing
         * instructions, while trap_s 4 is used for compiled breakpoints.
@@ -181,7 +181,7 @@ void kgdb_trap(struct pt_regs *regs, int param)
         * with trap_s 4 (compiled) breakpoints, continuation needs to
         * start after the breakpoint.
         */
-       if (param == 3)
+       if (regs->ecr_param == 3)
                instruction_pointer(regs) -= BREAK_INSTR_SIZE;
 
        kgdb_handle_exception(1, SIGTRAP, 0, regs);
index 5a7b80e2d883127bebd85d598142e352f1b928ef..72f97822784a4627da66e835002c309b84dc14d9 100644 (file)
@@ -517,8 +517,7 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p)
        return 0;
 }
 
-void trap_is_kprobe(unsigned long cause, unsigned long address,
-                   struct pt_regs *regs)
+void trap_is_kprobe(unsigned long address, struct pt_regs *regs)
 {
-       notify_die(DIE_TRAP, "kprobe_trap", regs, address, cause, SIGTRAP);
+       notify_die(DIE_TRAP, "kprobe_trap", regs, address, 0, SIGTRAP);
 }
index cad66851e0c4e67eb35bc5bbb3e4b6ec4b8f4929..07a3a968fe49a113e94c2a894895db09362108ac 100644 (file)
@@ -55,10 +55,8 @@ asmlinkage void ret_from_fork(void);
  * |     ...        |
  * |    unused      |
  * |                |
- * ------------------  <==== top of Stack (thread.ksp)
- * |   UNUSED 1 word|
  * ------------------
- * |     r25        |
+ * |     r25        |   <==== top of Stack (thread.ksp)
  * ~                ~
  * |    --to--      |   (CALLEE Regs of user mode)
  * |     r13        |
@@ -76,7 +74,10 @@ asmlinkage void ret_from_fork(void);
  * |    --to--      |   (scratch Regs of user mode)
  * |     r0         |
  * ------------------
- * |   UNUSED 1 word|
+ * |      SP        |
+ * |    orig_r0     |
+ * |    event/ECR   |
+ * |    user_r25    |
  * ------------------  <===== END of PAGE
  */
 int copy_thread(unsigned long clone_flags,
index c6a81c58d0f3ae9054a3935f6590cc317fedbba4..333238564b67f1239afde4ab4d584f16d8a48572 100644 (file)
@@ -40,7 +40,15 @@ static int genregs_get(struct task_struct *target,
                        offsetof(struct user_regs_struct, LOC), \
                        offsetof(struct user_regs_struct, LOC) + 4);
 
+#define REG_O_ZERO(LOC)                \
+       if (!ret)               \
+               ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
+                       offsetof(struct user_regs_struct, LOC), \
+                       offsetof(struct user_regs_struct, LOC) + 4);
+
+       REG_O_ZERO(pad);
        REG_O_CHUNK(scratch, callee, ptregs);
+       REG_O_ZERO(pad2);
        REG_O_CHUNK(callee, efa, cregs);
        REG_O_CHUNK(efa, stop_pc, &target->thread.fault_address);
 
@@ -88,8 +96,10 @@ static int genregs_set(struct task_struct *target,
                        offsetof(struct user_regs_struct, LOC), \
                        offsetof(struct user_regs_struct, LOC) + 4);
 
-       /* TBD: disallow updates to STATUS32, orig_r8 etc*/
-       REG_IN_CHUNK(scratch, callee, ptregs);  /* pt_regs[bta..orig_r8] */
+       REG_IGNORE_ONE(pad);
+       /* TBD: disallow updates to STATUS32 etc*/
+       REG_IN_CHUNK(scratch, pad2, ptregs);    /* pt_regs[bta..sp] */
+       REG_IGNORE_ONE(pad2);
        REG_IN_CHUNK(callee, efa, cregs);       /* callee_regs[r25..r13] */
        REG_IGNORE_ONE(efa);                    /* efa update invalid */
        REG_IN_ONE(stop_pc, &ptregs->ret);      /* stop_pc: PC update */
index b2b3731dd1e9c65638b69cd5402382ab2bbb275c..6b083454d0391d2177511ac1eb24300dfc19861c 100644 (file)
 int running_on_hw = 1; /* vs. on ISS */
 
 char __initdata command_line[COMMAND_LINE_SIZE];
-struct machine_desc *machine_desc __cpuinitdata;
+struct machine_desc *machine_desc;
 
 struct task_struct *_current_task[NR_CPUS];    /* For stack switching */
 
 struct cpuinfo_arc cpuinfo_arc700[NR_CPUS];
 
 
-void __cpuinit read_arc_build_cfg_regs(void)
+void read_arc_build_cfg_regs(void)
 {
        struct bcr_perip uncached_space;
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
@@ -182,7 +182,7 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
        FIX_PTR(cpu);
 #define IS_AVAIL1(var, str)    ((var) ? str : "")
 #define IS_AVAIL2(var, str)    ((var == 0x2) ? str : "")
-#define IS_USED(var)           ((var) ? "(in-use)" : "(not used)")
+#define IS_USED(cfg)           (IS_ENABLED(cfg) ? "(in-use)" : "(not used)")
 
        n += scnprintf(buf + n, len - n,
                       "Extn [700-Base]\t: %s %s %s %s %s %s\n",
@@ -202,9 +202,9 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
        if (cpu->core.family == 0x34) {
                n += scnprintf(buf + n, len - n,
                "Extn [700-4.10]\t: LLOCK/SCOND %s, SWAPE %s, RTSC %s\n",
-                              IS_USED(__CONFIG_ARC_HAS_LLSC_VAL),
-                              IS_USED(__CONFIG_ARC_HAS_SWAPE_VAL),
-                              IS_USED(__CONFIG_ARC_HAS_RTSC_VAL));
+                              IS_USED(CONFIG_ARC_HAS_LLSC),
+                              IS_USED(CONFIG_ARC_HAS_SWAPE),
+                              IS_USED(CONFIG_ARC_HAS_RTSC));
        }
 
        n += scnprintf(buf + n, len - n, "Extn [CCM]\t: %s",
@@ -237,7 +237,7 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
        return buf;
 }
 
-void __cpuinit arc_chk_ccms(void)
+void arc_chk_ccms(void)
 {
 #if defined(CONFIG_ARC_HAS_DCCM) || defined(CONFIG_ARC_HAS_ICCM)
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
@@ -272,7 +272,7 @@ void __cpuinit arc_chk_ccms(void)
  * hardware has dedicated regs which need to be saved/restored on ctx-sw
  * (Single Precision uses core regs), thus kernel is kind of oblivious to it
  */
-void __cpuinit arc_chk_fpu(void)
+void arc_chk_fpu(void)
 {
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
 
@@ -293,7 +293,7 @@ void __cpuinit arc_chk_fpu(void)
  *    such as only for boot CPU etc
  */
 
-void __cpuinit setup_processor(void)
+void setup_processor(void)
 {
        char str[512];
        int cpu_id = smp_processor_id();
index 5c7fd603d216c7bd8e0938074f32349358b6b84e..bca3052c956dab7edc2c5ccffba613f7a1d5cd39 100644 (file)
@@ -117,7 +117,7 @@ const char *arc_platform_smp_cpuinfo(void)
  * Called from asm stub in head.S
  * "current"/R25 already setup by low level boot code
  */
-void __cpuinit start_kernel_secondary(void)
+void start_kernel_secondary(void)
 {
        struct mm_struct *mm = &init_mm;
        unsigned int cpu = smp_processor_id();
@@ -154,7 +154,7 @@ void __cpuinit start_kernel_secondary(void)
  *
  * Essential requirements being where to run from (PC) and stack (SP)
 */
-int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
+int __cpu_up(unsigned int cpu, struct task_struct *idle)
 {
        unsigned long wait_till;
 
index ca0207b9d5b6f14d668be5f68735b52ccde1f54d..f8b7d880304dcc777db967a0d344515b2e6d2453 100644 (file)
@@ -79,7 +79,7 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
                 * assembly code
                 */
                frame_info->regs.r27 = 0;
-               frame_info->regs.r28 += 64;
+               frame_info->regs.r28 += 60;
                frame_info->call_frame = 0;
 
        } else {
index 09f4309aa2c035332153cd5c6b9734fd2262d95b..0e51e69cf30d772b646ef8a1d2c5605bf63b929a 100644 (file)
 #include <asm/clk.h>
 #include <asm/mach_desc.h>
 
+/* Timer related Aux registers */
+#define ARC_REG_TIMER0_LIMIT   0x23    /* timer 0 limit */
+#define ARC_REG_TIMER0_CTRL    0x22    /* timer 0 control */
+#define ARC_REG_TIMER0_CNT     0x21    /* timer 0 count */
+#define ARC_REG_TIMER1_LIMIT   0x102   /* timer 1 limit */
+#define ARC_REG_TIMER1_CTRL    0x101   /* timer 1 control */
+#define ARC_REG_TIMER1_CNT     0x100   /* timer 1 count */
+
+#define TIMER_CTRL_IE          (1 << 0) /* Interupt when Count reachs limit */
+#define TIMER_CTRL_NH          (1 << 1) /* Count only when CPU NOT halted */
+
 #define ARC_TIMER_MAX  0xFFFFFFFF
 
 /********** Clock Source Device *********/
 
 #ifdef CONFIG_ARC_HAS_RTSC
 
-int __cpuinit arc_counter_setup(void)
+int arc_counter_setup(void)
 {
        /* RTSC insn taps into cpu clk, needs no setup */
 
@@ -105,7 +116,7 @@ static bool is_usable_as_clocksource(void)
 /*
  * set 32bit TIMER1 to keep counting monotonically and wraparound
  */
-int __cpuinit arc_counter_setup(void)
+int arc_counter_setup(void)
 {
        write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX);
        write_aux_reg(ARC_REG_TIMER1_CNT, 0);
@@ -212,7 +223,7 @@ static struct irqaction arc_timer_irq = {
  * Setup the local event timer for @cpu
  * N.B. weak so that some exotic ARC SoCs can completely override it
  */
-void __attribute__((weak)) __cpuinit arc_local_timer_setup(unsigned int cpu)
+void __attribute__((weak)) arc_local_timer_setup(unsigned int cpu)
 {
        struct clock_event_device *clk = &per_cpu(arc_clockevent_device, cpu);
 
index 0471d9c9dd5448638593409f80a7823746761d02..e21692d2fdabc35a5f1120bb26bec82c828c4d0c 100644 (file)
@@ -28,10 +28,9 @@ void __init trap_init(void)
        return;
 }
 
-void die(const char *str, struct pt_regs *regs, unsigned long address,
-        unsigned long cause_reg)
+void die(const char *str, struct pt_regs *regs, unsigned long address)
 {
-       show_kernel_fault_diag(str, regs, address, cause_reg);
+       show_kernel_fault_diag(str, regs, address);
 
        /* DEAD END */
        __asm__("flag 1");
@@ -42,14 +41,13 @@ void die(const char *str, struct pt_regs *regs, unsigned long address,
  *  -for user faults enqueues requested signal
  *  -for kernel, chk if due to copy_(to|from)_user, otherwise die()
  */
-static noinline int handle_exception(unsigned long cause, char *str,
-                                    struct pt_regs *regs, siginfo_t *info)
+static noinline int
+handle_exception(const char *str, struct pt_regs *regs, siginfo_t *info)
 {
        if (user_mode(regs)) {
                struct task_struct *tsk = current;
 
                tsk->thread.fault_address = (__force unsigned int)info->si_addr;
-               tsk->thread.cause_code = cause;
 
                force_sig_info(info->si_signo, info, tsk);
 
@@ -58,14 +56,14 @@ static noinline int handle_exception(unsigned long cause, char *str,
                if (fixup_exception(regs))
                        return 0;
 
-               die(str, regs, (unsigned long)info->si_addr, cause);
+               die(str, regs, (unsigned long)info->si_addr);
        }
 
        return 1;
 }
 
 #define DO_ERROR_INFO(signr, str, name, sicode) \
-int name(unsigned long cause, unsigned long address, struct pt_regs *regs) \
+int name(unsigned long address, struct pt_regs *regs) \
 {                                              \
        siginfo_t info = {                      \
                .si_signo = signr,              \
@@ -73,7 +71,7 @@ int name(unsigned long cause, unsigned long address, struct pt_regs *regs) \
                .si_code  = sicode,             \
                .si_addr = (void __user *)address,      \
        };                                      \
-       return handle_exception(cause, str, regs, &info);\
+       return handle_exception(str, regs, &info);\
 }
 
 /*
@@ -90,11 +88,11 @@ DO_ERROR_INFO(SIGBUS, "Misaligned Access", do_misaligned_error, BUS_ADRALN)
 /*
  * Entry Point for Misaligned Data access Exception, for emulating in software
  */
-int do_misaligned_access(unsigned long cause, unsigned long address,
-                        struct pt_regs *regs, struct callee_regs *cregs)
+int do_misaligned_access(unsigned long address, struct pt_regs *regs,
+                        struct callee_regs *cregs)
 {
-       if (misaligned_fixup(address, regs, cause, cregs) != 0)
-               return do_misaligned_error(cause, address, regs);
+       if (misaligned_fixup(address, regs, cregs) != 0)
+               return do_misaligned_error(address, regs);
 
        return 0;
 }
@@ -104,10 +102,9 @@ int do_misaligned_access(unsigned long cause, unsigned long address,
  * Entry point for miscll errors such as Nested Exceptions
  *  -Duplicate TLB entry is handled seperately though
  */
-void do_machine_check_fault(unsigned long cause, unsigned long address,
-                           struct pt_regs *regs)
+void do_machine_check_fault(unsigned long address, struct pt_regs *regs)
 {
-       die("Machine Check Exception", regs, address, cause);
+       die("Machine Check Exception", regs, address);
 }
 
 
@@ -120,23 +117,22 @@ void do_machine_check_fault(unsigned long cause, unsigned long address,
  *  -1 used for software breakpointing (gdb)
  *  -2 used by kprobes
  */
-void do_non_swi_trap(unsigned long cause, unsigned long address,
-                       struct pt_regs *regs)
+void do_non_swi_trap(unsigned long address, struct pt_regs *regs)
 {
-       unsigned int param = cause & 0xff;
+       unsigned int param = regs->ecr_param;
 
        switch (param) {
        case 1:
-               trap_is_brkpt(cause, address, regs);
+               trap_is_brkpt(address, regs);
                break;
 
        case 2:
-               trap_is_kprobe(param, address, regs);
+               trap_is_kprobe(address, regs);
                break;
 
        case 3:
        case 4:
-               kgdb_trap(regs, param);
+               kgdb_trap(regs);
                break;
 
        default:
@@ -149,14 +145,14 @@ void do_non_swi_trap(unsigned long cause, unsigned long address,
  *  -For a corner case, ARC kprobes implementation resorts to using
  *   this exception, hence the check
  */
-void do_insterror_or_kprobe(unsigned long cause,
-                                      unsigned long address,
-                                      struct pt_regs *regs)
+void do_insterror_or_kprobe(unsigned long address, struct pt_regs *regs)
 {
+       int rc;
+
        /* Check if this exception is caused by kprobes */
-       if (notify_die(DIE_IERR, "kprobe_ierr", regs, address,
-                      cause, SIGILL) == NOTIFY_STOP)
+       rc = notify_die(DIE_IERR, "kprobe_ierr", regs, address, 0, SIGILL);
+       if (rc == NOTIFY_STOP)
                return;
 
-       insterror_is_error(cause, address, regs);
+       insterror_is_error(address, regs);
 }
index 11c301b81c92bfb7def6577a869c4e0f2c0432a3..73a7450ee622d843160d4fc7d0284c2fa407ce84 100644 (file)
@@ -101,7 +101,7 @@ static void show_faulting_vma(unsigned long address, char *buf)
                if (file) {
                        struct path *path = &file->f_path;
                        nm = d_path(path, buf, PAGE_SIZE - 1);
-                       inode = vma->vm_file->f_path.dentry->d_inode;
+                       inode = file_inode(vma->vm_file);
                        dev = inode->i_sb->s_dev;
                        ino = inode->i_ino;
                }
@@ -117,23 +117,22 @@ static void show_faulting_vma(unsigned long address, char *buf)
 
 static void show_ecr_verbose(struct pt_regs *regs)
 {
-       unsigned int vec, cause_code, cause_reg;
+       unsigned int vec, cause_code;
        unsigned long address;
 
-       cause_reg = current->thread.cause_code;
-       pr_info("\n[ECR   ]: 0x%08x => ", cause_reg);
+       pr_info("\n[ECR   ]: 0x%08lx => ", regs->event);
 
        /* For Data fault, this is data address not instruction addr */
        address = current->thread.fault_address;
 
-       vec = cause_reg >> 16;
-       cause_code = (cause_reg >> 8) & 0xFF;
+       vec = regs->ecr_vec;
+       cause_code = regs->ecr_cause;
 
        /* For DTLB Miss or ProtV, display the memory involved too */
        if (vec == ECR_V_DTLB_MISS) {
-               pr_cont("Invalid %s 0x%08lx by insn @ 0x%08lx\n",
-                      (cause_code == 0x01) ? "Read From" :
-                      ((cause_code == 0x02) ? "Write to" : "EX"),
+               pr_cont("Invalid %s 0x%08lx by insn @ 0x%08lx\n",
+                      (cause_code == 0x01) ? "Read" :
+                      ((cause_code == 0x02) ? "Write" : "EX"),
                       address, regs->ret);
        } else if (vec == ECR_V_ITLB_MISS) {
                pr_cont("Insn could not be fetched\n");
@@ -144,14 +143,12 @@ static void show_ecr_verbose(struct pt_regs *regs)
        } else if (vec == ECR_V_PROTV) {
                if (cause_code == ECR_C_PROTV_INST_FETCH)
                        pr_cont("Execute from Non-exec Page\n");
-               else if (cause_code == ECR_C_PROTV_LOAD)
-                       pr_cont("Read from Non-readable Page\n");
-               else if (cause_code == ECR_C_PROTV_STORE)
-                       pr_cont("Write to Non-writable Page\n");
-               else if (cause_code == ECR_C_PROTV_XCHG)
-                       pr_cont("Data exchange protection violation\n");
                else if (cause_code == ECR_C_PROTV_MISALIG_DATA)
                        pr_cont("Misaligned r/w from 0x%08lx\n", address);
+               else
+                       pr_cont("%s access not allowed on page\n",
+                               (cause_code == 0x01) ? "Read" :
+                               ((cause_code == 0x02) ? "Write" : "EX"));
        } else if (vec == ECR_V_INSN_ERR) {
                pr_cont("Illegal Insn\n");
        } else {
@@ -176,8 +173,7 @@ void show_regs(struct pt_regs *regs)
        print_task_path_n_nm(tsk, buf);
        show_regs_print_info(KERN_INFO);
 
-       if (current->thread.cause_code)
-               show_ecr_verbose(regs);
+       show_ecr_verbose(regs);
 
        pr_info("[EFA   ]: 0x%08lx\n[BLINK ]: %pS\n[ERET  ]: %pS\n",
                current->thread.fault_address,
@@ -213,10 +209,9 @@ void show_regs(struct pt_regs *regs)
 }
 
 void show_kernel_fault_diag(const char *str, struct pt_regs *regs,
-                           unsigned long address, unsigned long cause_reg)
+                           unsigned long address)
 {
        current->thread.fault_address = address;
-       current->thread.cause_code = cause_reg;
 
        /* Caller and Callee regs */
        show_regs(regs);
index 4cd81633febd2c8dc91aa290837feed7370d06ce..c0f832f595d319d1aa21f05228b01fb946ab5591 100644 (file)
@@ -187,7 +187,7 @@ fault:      state->fault = 1;
  * Returns 0 if successfully handled, 1 if some error happened
  */
 int misaligned_fixup(unsigned long address, struct pt_regs *regs,
-                    unsigned long cause, struct callee_regs *cregs)
+                    struct callee_regs *cregs)
 {
        struct disasm_state state;
        char buf[TASK_COMM_LEN];
index a8d02223da44aec8a8ea776df74acac4c746f2a3..e550b117ec4ffe4ccf3f79e4763fc511e5c9d7e9 100644 (file)
@@ -289,6 +289,8 @@ static void __init setup_unwind_table(struct unwind_table *table,
                         * instead of the initial loc addr
                         * return;
                         */
+                       WARN(1, "unwinder: FDE->initial_location NULL %p\n",
+                               (const u8 *)(fde + 1) + *fde);
                }
                ++n;
        }
index d3c92f52d4442452cb3a682f00276f9c330c7ed5..2555f5886af624dc508354e2938ca32b4373d450 100644 (file)
@@ -125,6 +125,11 @@ SECTIONS
                *(.debug_frame)
                __end_unwind = .;
        }
+       /*
+        * gcc 4.8 generates this for -fasynchonous-unwind-tables,
+        * while we still use the .debug_frame based unwinder
+        */
+       /DISCARD/ : {   *(.eh_frame) }
 #else
        /DISCARD/ : {   *(.debug_frame) }
 #endif
@@ -142,15 +147,18 @@ SECTIONS
                *(.arcextmap.*)
        }
 
+#ifndef CONFIG_DEBUG_INFO
        /* open-coded because we need .debug_frame seperately for unwinding */
-       .debug_aranges 0 : { *(.debug_aranges) }
-       .debug_pubnames 0 : { *(.debug_pubnames) }
-       .debug_info 0 : { *(.debug_info) }
-       .debug_abbrev 0 : { *(.debug_abbrev) }
-       .debug_line 0 : { *(.debug_line) }
-       .debug_str 0 : { *(.debug_str) }
-       .debug_loc 0 : { *(.debug_loc) }
-       .debug_macinfo 0 : { *(.debug_macinfo) }
+       /DISCARD/ : { *(.debug_aranges) }
+       /DISCARD/ : { *(.debug_pubnames) }
+       /DISCARD/ : { *(.debug_info) }
+       /DISCARD/ : { *(.debug_abbrev) }
+       /DISCARD/ : { *(.debug_line) }
+       /DISCARD/ : { *(.debug_str) }
+       /DISCARD/ : { *(.debug_loc) }
+       /DISCARD/ : { *(.debug_macinfo) }
+       /DISCARD/ : { *(.debug_ranges) }
+#endif
 
 #ifdef CONFIG_ARC_HAS_DCCM
        . = CONFIG_ARC_DCCM_BASE;
index aedce1905441cffb1958f00af149b0a939740371..f415d851b765888c500d70f887af96ed226fd88c 100644 (file)
 #include <asm/cachectl.h>
 #include <asm/setup.h>
 
+/* Instruction cache related Auxiliary registers */
+#define ARC_REG_IC_BCR         0x77    /* Build Config reg */
+#define ARC_REG_IC_IVIC                0x10
+#define ARC_REG_IC_CTRL                0x11
+#define ARC_REG_IC_IVIL                0x19
+#if (CONFIG_ARC_MMU_VER > 2)
+#define ARC_REG_IC_PTAG                0x1E
+#endif
+
+/* Bit val in IC_CTRL */
+#define IC_CTRL_CACHE_DISABLE   0x1
+
+/* Data cache related Auxiliary registers */
+#define ARC_REG_DC_BCR         0x72    /* Build Config reg */
+#define ARC_REG_DC_IVDC                0x47
+#define ARC_REG_DC_CTRL                0x48
+#define ARC_REG_DC_IVDL                0x4A
+#define ARC_REG_DC_FLSH                0x4B
+#define ARC_REG_DC_FLDL                0x4C
+#if (CONFIG_ARC_MMU_VER > 2)
+#define ARC_REG_DC_PTAG                0x5C
+#endif
+
+/* Bit val in DC_CTRL */
+#define DC_CTRL_INV_MODE_FLUSH  0x40
+#define DC_CTRL_FLUSH_STATUS    0x100
+
 char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len)
 {
        int n = 0;
@@ -89,8 +116,10 @@ char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len)
                        enb ?  "" : "DISABLED (kernel-build)");         \
 }
 
-       PR_CACHE(&cpuinfo_arc700[c].icache, __CONFIG_ARC_HAS_ICACHE, "I-Cache");
-       PR_CACHE(&cpuinfo_arc700[c].dcache, __CONFIG_ARC_HAS_DCACHE, "D-Cache");
+       PR_CACHE(&cpuinfo_arc700[c].icache, IS_ENABLED(CONFIG_ARC_HAS_ICACHE),
+                       "I-Cache");
+       PR_CACHE(&cpuinfo_arc700[c].dcache, IS_ENABLED(CONFIG_ARC_HAS_DCACHE),
+                       "D-Cache");
 
        return buf;
 }
@@ -100,17 +129,23 @@ char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len)
  * the cpuinfo structure for later use.
  * No Validation done here, simply read/convert the BCRs
  */
-void __cpuinit read_decode_cache_bcr(void)
+void read_decode_cache_bcr(void)
 {
-       struct bcr_cache ibcr, dbcr;
        struct cpuinfo_arc_cache *p_ic, *p_dc;
        unsigned int cpu = smp_processor_id();
+       struct bcr_cache {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+               unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
+#else
+               unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
+#endif
+       } ibcr, dbcr;
 
        p_ic = &cpuinfo_arc700[cpu].icache;
        READ_BCR(ARC_REG_IC_BCR, ibcr);
 
-       if (ibcr.config == 0x3)
-               p_ic->assoc = 2;
+       BUG_ON(ibcr.config != 3);
+       p_ic->assoc = 2;                /* Fixed to 2w set assoc */
        p_ic->line_len = 8 << ibcr.line_len;
        p_ic->sz = 0x200 << ibcr.sz;
        p_ic->ver = ibcr.ver;
@@ -118,8 +153,8 @@ void __cpuinit read_decode_cache_bcr(void)
        p_dc = &cpuinfo_arc700[cpu].dcache;
        READ_BCR(ARC_REG_DC_BCR, dbcr);
 
-       if (dbcr.config == 0x2)
-               p_dc->assoc = 4;
+       BUG_ON(dbcr.config != 2);
+       p_dc->assoc = 4;                /* Fixed to 4w set assoc */
        p_dc->line_len = 16 << dbcr.line_len;
        p_dc->sz = 0x200 << dbcr.sz;
        p_dc->ver = dbcr.ver;
@@ -132,14 +167,12 @@ void __cpuinit read_decode_cache_bcr(void)
  * 3. Enable the Caches, setup default flush mode for D-Cache
  * 3. Calculate the SHMLBA used by user space
  */
-void __cpuinit arc_cache_init(void)
+void arc_cache_init(void)
 {
-       unsigned int temp;
        unsigned int cpu = smp_processor_id();
        struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache;
        struct cpuinfo_arc_cache *dc = &cpuinfo_arc700[cpu].dcache;
-       int way_pg_ratio = way_pg_ratio;
-       int dcache_does_alias;
+       unsigned int dcache_does_alias, temp;
        char str[256];
 
        printk(arc_cache_mumbojumbo(0, str, sizeof(str)));
@@ -149,20 +182,11 @@ void __cpuinit arc_cache_init(void)
 
 #ifdef CONFIG_ARC_HAS_ICACHE
        /* 1. Confirm some of I-cache params which Linux assumes */
-       if ((ic->assoc != ARC_ICACHE_WAYS) ||
-           (ic->line_len != ARC_ICACHE_LINE_LEN)) {
+       if (ic->line_len != ARC_ICACHE_LINE_LEN)
                panic("Cache H/W doesn't match kernel Config");
-       }
-#if (CONFIG_ARC_MMU_VER > 2)
-       if (ic->ver != 3) {
-               if (running_on_hw)
-                       panic("Cache ver doesn't match MMU ver\n");
-
-               /* For ISS - suggest the toggles to use */
-               pr_err("Use -prop=icache_version=3,-prop=dcache_version=3\n");
 
-       }
-#endif
+       if (ic->ver != CONFIG_ARC_MMU_VER)
+               panic("Cache ver doesn't match MMU ver\n");
 #endif
 
        /* Enable/disable I-Cache */
@@ -181,14 +205,12 @@ chk_dc:
                return;
 
 #ifdef CONFIG_ARC_HAS_DCACHE
-       if ((dc->assoc != ARC_DCACHE_WAYS) ||
-           (dc->line_len != ARC_DCACHE_LINE_LEN)) {
+       if (dc->line_len != ARC_DCACHE_LINE_LEN)
                panic("Cache H/W doesn't match kernel Config");
-       }
-
-       dcache_does_alias = (dc->sz / ARC_DCACHE_WAYS) > PAGE_SIZE;
 
        /* check for D-Cache aliasing */
+       dcache_does_alias = (dc->sz / dc->assoc) > PAGE_SIZE;
+
        if (dcache_does_alias && !cache_is_vipt_aliasing())
                panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
        else if (!dcache_does_alias && cache_is_vipt_aliasing())
@@ -239,11 +261,9 @@ static inline void wait_for_flush(void)
  */
 static inline void __dc_entire_op(const int cacheop)
 {
-       unsigned long flags, tmp = tmp;
+       unsigned int tmp = tmp;
        int aux;
 
-       local_irq_save(flags);
-
        if (cacheop == OP_FLUSH_N_INV) {
                /* Dcache provides 2 cmd: FLUSH or INV
                 * INV inturn has sub-modes: DISCARD or FLUSH-BEFORE
@@ -267,8 +287,6 @@ static inline void __dc_entire_op(const int cacheop)
        /* Switch back the DISCARD ONLY Invalidate mode */
        if (cacheop == OP_FLUSH_N_INV)
                write_aux_reg(ARC_REG_DC_CTRL, tmp & ~DC_CTRL_INV_MODE_FLUSH);
-
-       local_irq_restore(flags);
 }
 
 /*
@@ -459,8 +477,15 @@ static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr,
        local_irq_restore(flags);
 }
 
+static inline void __ic_entire_inv(void)
+{
+       write_aux_reg(ARC_REG_IC_IVIC, 1);
+       read_aux_reg(ARC_REG_IC_CTRL);  /* blocks */
+}
+
 #else
 
+#define __ic_entire_inv()
 #define __ic_line_inv_vaddr(pstart, vstart, sz)
 
 #endif /* CONFIG_ARC_HAS_ICACHE */
@@ -487,7 +512,7 @@ void flush_dcache_page(struct page *page)
        struct address_space *mapping;
 
        if (!cache_is_vipt_aliasing()) {
-               set_bit(PG_arch_1, &page->flags);
+               clear_bit(PG_dc_clean, &page->flags);
                return;
        }
 
@@ -501,7 +526,7 @@ void flush_dcache_page(struct page *page)
         * Make a note that K-mapping is dirty
         */
        if (!mapping_mapped(mapping)) {
-               set_bit(PG_arch_1, &page->flags);
+               clear_bit(PG_dc_clean, &page->flags);
        } else if (page_mapped(page)) {
 
                /* kernel reading from page with U-mapping */
@@ -629,26 +654,13 @@ void ___flush_dcache_page(unsigned long paddr, unsigned long vaddr)
        __dc_line_op(paddr, vaddr & PAGE_MASK, PAGE_SIZE, OP_FLUSH_N_INV);
 }
 
-void flush_icache_all(void)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       write_aux_reg(ARC_REG_IC_IVIC, 1);
-
-       /* lr will not complete till the icache inv operation is not over */
-       read_aux_reg(ARC_REG_IC_CTRL);
-       local_irq_restore(flags);
-}
-
 noinline void flush_cache_all(void)
 {
        unsigned long flags;
 
        local_irq_save(flags);
 
-       flush_icache_all();
+       __ic_entire_inv();
        __dc_entire_op(OP_FLUSH_N_INV);
 
        local_irq_restore(flags);
@@ -667,7 +679,12 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long u_vaddr,
 {
        unsigned int paddr = pfn << PAGE_SHIFT;
 
-       __sync_icache_dcache(paddr, u_vaddr, PAGE_SIZE);
+       u_vaddr &= PAGE_MASK;
+
+       ___flush_dcache_page(paddr, u_vaddr);
+
+       if (vma->vm_flags & VM_EXEC)
+               __inv_icache_page(paddr, u_vaddr);
 }
 
 void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
@@ -717,7 +734,7 @@ void copy_user_highpage(struct page *to, struct page *from,
         * non copied user pages (e.g. read faults which wire in pagecache page
         * directly).
         */
-       set_bit(PG_arch_1, &to->flags);
+       clear_bit(PG_dc_clean, &to->flags);
 
        /*
         * if SRC was already usermapped and non-congruent to kernel mapping
@@ -725,15 +742,16 @@ void copy_user_highpage(struct page *to, struct page *from,
         */
        if (clean_src_k_mappings) {
                __flush_dcache_page(kfrom, kfrom);
+               set_bit(PG_dc_clean, &from->flags);
        } else {
-               set_bit(PG_arch_1, &from->flags);
+               clear_bit(PG_dc_clean, &from->flags);
        }
 }
 
 void clear_user_page(void *to, unsigned long u_vaddr, struct page *page)
 {
        clear_page(to);
-       set_bit(PG_arch_1, &page->flags);
+       clear_bit(PG_dc_clean, &page->flags);
 }
 
 
index 689ffd86d5e9d3dc786ac60e8bee1dab9ce7af8c..318164cabdfc5e72c771d5f686aad2da49e63d8f 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/uaccess.h>
 #include <linux/kdebug.h>
 #include <asm/pgalloc.h>
+#include <asm/mmu.h>
 
 static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long address)
 {
@@ -51,14 +52,14 @@ bad_area:
        return 1;
 }
 
-void do_page_fault(struct pt_regs *regs, int write, unsigned long address,
-                  unsigned long cause_code)
+void do_page_fault(struct pt_regs *regs, unsigned long address)
 {
        struct vm_area_struct *vma = NULL;
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
        siginfo_t info;
        int fault, ret;
+       int write = regs->ecr_cause & ECR_C_PROTV_STORE;  /* ST/EX */
        unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
                                (write ? FAULT_FLAG_WRITE : 0);
 
@@ -109,7 +110,8 @@ good_area:
 
        /* Handle protection violation, execute on heap or stack */
 
-       if (cause_code == ((ECR_V_PROTV << 16) | ECR_C_PROTV_INST_FETCH))
+       if ((regs->ecr_vec == ECR_V_PROTV) &&
+           (regs->ecr_cause == ECR_C_PROTV_INST_FETCH))
                goto bad_area;
 
        if (write) {
@@ -176,7 +178,6 @@ bad_area_nosemaphore:
        /* User mode accesses just cause a SIGSEGV */
        if (user_mode(regs)) {
                tsk->thread.fault_address = address;
-               tsk->thread.cause_code = cause_code;
                info.si_signo = SIGSEGV;
                info.si_errno = 0;
                /* info.si_code has been set above */
@@ -197,7 +198,7 @@ no_context:
        if (fixup_exception(regs))
                return;
 
-       die("Oops", regs, address, cause_code);
+       die("Oops", regs, address);
 
 out_of_memory:
        if (is_global_init(tsk)) {
@@ -218,7 +219,6 @@ do_sigbus:
                goto no_context;
 
        tsk->thread.fault_address = address;
-       tsk->thread.cause_code = cause_code;
        info.si_signo = SIGBUS;
        info.si_errno = 0;
        info.si_code = BUS_ADRERR;
index 4a177365b2c42a94abe000ec4d9de016e7f48abb..a08ce71854233e05510d45fc1183c19ecd35cb7c 100644 (file)
@@ -74,7 +74,7 @@ void __init setup_arch_memory(void)
        /* Last usable page of low mem (no HIGHMEM yet for ARC port) */
        max_low_pfn = max_pfn = PFN_DOWN(end_mem);
 
-       max_mapnr = num_physpages = max_low_pfn - min_low_pfn;
+       max_mapnr = max_low_pfn - min_low_pfn;
 
        /*------------- reserve kernel image -----------------------*/
        memblock_reserve(CONFIG_LINUX_LINK_BASE,
@@ -84,7 +84,7 @@ void __init setup_arch_memory(void)
 
        /*-------------- node setup --------------------------------*/
        memset(zones_size, 0, sizeof(zones_size));
-       zones_size[ZONE_NORMAL] = num_physpages;
+       zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
 
        /*
         * We can't use the helper free_area_init(zones[]) because it uses
@@ -106,39 +106,9 @@ void __init setup_arch_memory(void)
  */
 void __init mem_init(void)
 {
-       int codesize, datasize, initsize, reserved_pages, free_pages;
-       int tmp;
-
        high_memory = (void *)(CONFIG_LINUX_LINK_BASE + arc_mem_sz);
-
-       totalram_pages = free_all_bootmem();
-
-       /* count all reserved pages [kernel code/data/mem_map..] */
-       reserved_pages = 0;
-       for (tmp = 0; tmp < max_mapnr; tmp++)
-               if (PageReserved(mem_map + tmp))
-                       reserved_pages++;
-
-       /* XXX: nr_free_pages() is equivalent */
-       free_pages = max_mapnr - reserved_pages;
-
-       /*
-        * For the purpose of display below, split the "reserve mem"
-        * kernel code/data is already shown explicitly,
-        * Show any other reservations (mem_map[ ] et al)
-        */
-       reserved_pages -= (((unsigned int)_end - CONFIG_LINUX_LINK_BASE) >>
-                                                               PAGE_SHIFT);
-
-       codesize = _etext - _text;
-       datasize = _end - _etext;
-       initsize = __init_end - __init_begin;
-
-       pr_info("Memory Available: %dM / %ldM (%dK code, %dK data, %dK init, %dK reserv)\n",
-               PAGES_TO_MB(free_pages),
-               TO_MB(arc_mem_sz),
-               TO_KB(codesize), TO_KB(datasize), TO_KB(initsize),
-               PAGES_TO_KB(reserved_pages));
+       free_all_bootmem();
+       mem_init_print_info(NULL);
 }
 
 /*
@@ -146,13 +116,13 @@ void __init mem_init(void)
  */
 void __init_refok free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
 
index fe1c5a073afe4cf996d28b6486c6b296fbd94344..7957dc4e4d4a4c8acee3fe521d0ecf8bb939c39c 100644 (file)
@@ -55,7 +55,7 @@
 #include <asm/arcregs.h>
 #include <asm/setup.h>
 #include <asm/mmu_context.h>
-#include <asm/tlb.h>
+#include <asm/mmu.h>
 
 /*                     Need for ARC MMU v2
  *
@@ -97,6 +97,7 @@
  * J-TLB entry got evicted/replaced.
  */
 
+
 /* A copy of the ASID from the PID reg is kept in asid_cache */
 int asid_cache = FIRST_ASID;
 
@@ -432,9 +433,14 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
 {
        unsigned long vaddr = vaddr_unaligned & PAGE_MASK;
        unsigned long paddr = pte_val(*ptep) & PAGE_MASK;
+       struct page *page = pfn_to_page(pte_pfn(*ptep));
 
        create_tlb(vma, vaddr, ptep);
 
+       if (page == ZERO_PAGE(0)) {
+               return;
+       }
+
        /*
         * Exec page : Independent of aliasing/page-color considerations,
         *             since icache doesn't snoop dcache on ARC, any dirty
@@ -446,9 +452,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
         */
        if ((vma->vm_flags & VM_EXEC) ||
             addr_not_cache_congruent(paddr, vaddr)) {
-               struct page *page = pfn_to_page(pte_pfn(*ptep));
 
-               int dirty = test_and_clear_bit(PG_arch_1, &page->flags);
+               int dirty = !test_and_set_bit(PG_dc_clean, &page->flags);
                if (dirty) {
                        /* wback + inv dcache lines */
                        __flush_dcache_page(paddr, paddr);
@@ -464,12 +469,27 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
  * the cpuinfo structure for later use.
  * No Validation is done here, simply read/convert the BCRs
  */
-void __cpuinit read_decode_mmu_bcr(void)
+void read_decode_mmu_bcr(void)
 {
-       unsigned int tmp;
-       struct bcr_mmu_1_2 *mmu2;       /* encoded MMU2 attr */
-       struct bcr_mmu_3 *mmu3;         /* encoded MMU3 attr */
        struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
+       unsigned int tmp;
+       struct bcr_mmu_1_2 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+               unsigned int ver:8, ways:4, sets:4, u_itlb:8, u_dtlb:8;
+#else
+               unsigned int u_dtlb:8, u_itlb:8, sets:4, ways:4, ver:8;
+#endif
+       } *mmu2;
+
+       struct bcr_mmu_3 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       unsigned int ver:8, ways:4, sets:4, osm:1, reserv:3, pg_sz:4,
+                    u_itlb:4, u_dtlb:4;
+#else
+       unsigned int u_dtlb:4, u_itlb:4, pg_sz:4, reserv:3, osm:1, sets:4,
+                    ways:4, ver:8;
+#endif
+       } *mmu3;
 
        tmp = read_aux_reg(ARC_REG_MMU_BCR);
        mmu->ver = (tmp >> 24);
@@ -505,12 +525,12 @@ char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len)
                       "J-TLB %d (%dx%d), uDTLB %d, uITLB %d, %s\n",
                       p_mmu->num_tlb, p_mmu->sets, p_mmu->ways,
                       p_mmu->u_dtlb, p_mmu->u_itlb,
-                      __CONFIG_ARC_MMU_SASID_VAL ? "SASID" : "");
+                      IS_ENABLED(CONFIG_ARC_MMU_SASID) ? "SASID" : "");
 
        return buf;
 }
 
-void __cpuinit arc_mmu_init(void)
+void arc_mmu_init(void)
 {
        char str[256];
        struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
index 3357d26ffe54267a8ba9d26e596019b187e23bdd..5c5bb23001b071b02a0ea33dba44d72211656d28 100644 (file)
@@ -39,7 +39,7 @@
 
 #include <linux/linkage.h>
 #include <asm/entry.h>
-#include <asm/tlb.h>
+#include <asm/mmu.h>
 #include <asm/pgtable.h>
 #include <asm/arcregs.h>
 #include <asm/cache.h>
@@ -147,9 +147,9 @@ ex_saved_reg1:
 #ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT
        and.f 0, r0, _PAGE_PRESENT
        bz   1f
-       ld   r2, [num_pte_not_present]
-       add  r2, r2, 1
-       st   r2, [num_pte_not_present]
+       ld   r3, [num_pte_not_present]
+       add  r3, r3, 1
+       st   r3, [num_pte_not_present]
 1:
 #endif
 
@@ -271,22 +271,22 @@ ARC_ENTRY EV_TLBMissI
 #endif
 
        ;----------------------------------------------------------------
-       ; Get the PTE corresponding to V-addr accessed
+       ; Get the PTE corresponding to V-addr accessed, r2 is setup with EFA
        LOAD_FAULT_PTE
 
        ;----------------------------------------------------------------
        ; VERIFY_PTE: Check if PTE permissions approp for executing code
        cmp_s   r2, VMALLOC_START
-       mov.lo  r2, (_PAGE_PRESENT | _PAGE_U_READ | _PAGE_U_EXECUTE)
-       mov.hs  r2, (_PAGE_PRESENT | _PAGE_K_READ | _PAGE_K_EXECUTE)
+       mov.lo  r2, (_PAGE_PRESENT | _PAGE_U_EXECUTE)
+       mov.hs  r2, (_PAGE_PRESENT | _PAGE_K_EXECUTE)
 
        and     r3, r0, r2  ; Mask out NON Flag bits from PTE
        xor.f   r3, r3, r2  ; check ( ( pte & flags_test ) == flags_test )
        bnz     do_slow_path_pf
 
        ; Let Linux VM know that the page was accessed
-       or      r0, r0, (_PAGE_PRESENT | _PAGE_ACCESSED)  ; set Accessed Bit
-       st_s    r0, [r1]                                  ; Write back PTE
+       or      r0, r0, _PAGE_ACCESSED  ; set Accessed Bit
+       st_s    r0, [r1]                ; Write back PTE
 
        CONV_PTE_TO_TLB
        COMMIT_ENTRY_TO_MMU
@@ -311,7 +311,7 @@ ARC_ENTRY EV_TLBMissD
 
        ;----------------------------------------------------------------
        ; Get the PTE corresponding to V-addr accessed
-       ; If PTE exists, it will setup, r0 = PTE, r1 = Ptr to PTE
+       ; If PTE exists, it will setup, r0 = PTE, r1 = Ptr to PTE, r2 = EFA
        LOAD_FAULT_PTE
 
        ;----------------------------------------------------------------
@@ -345,7 +345,7 @@ ARC_ENTRY EV_TLBMissD
        ;----------------------------------------------------------------
        ; UPDATE_PTE: Let Linux VM know that page was accessed/dirty
        lr      r3, [ecr]
-       or      r0, r0, (_PAGE_PRESENT | _PAGE_ACCESSED) ; Accessed bit always
+       or      r0, r0, _PAGE_ACCESSED        ; Accessed bit always
        btst_s  r3,  ECR_C_BIT_DTLB_ST_MISS   ; See if it was a Write Access ?
        or.nz   r0, r0, _PAGE_MODIFIED        ; if Write, set Dirty bit as well
        st_s    r0, [r1]                      ; Write back PTE
@@ -381,18 +381,7 @@ do_slow_path_pf:
 
        ; ------- setup args for Linux Page fault Hanlder ---------
        mov_s r0, sp
-       lr  r2, [efa]
-       lr  r3, [ecr]
-
-       ; Both st and ex imply WRITE access of some sort, hence do_page_fault( )
-       ; invoked with write=1 for DTLB-st/ex Miss and write=0 for ITLB miss or
-       ; DTLB-ld Miss
-       ; DTLB Miss Cause code is ld = 0x01 , st = 0x02, ex = 0x03
-       ; Following code uses that fact that st/ex have one bit in common
-
-       btst_s r3,  ECR_C_BIT_DTLB_ST_MISS
-       mov.z  r1, 0
-       mov.nz r1, 1
+       lr  r1, [efa]
 
        ; We don't want exceptions to be disabled while the fault is handled.
        ; Now that we have saved the context we return from exception hence
index b3700c064c0670ab0d799c2401432a4d35962728..d71f3c3bcf24247653c0c3d4d702c80ce62bee43 100644 (file)
@@ -77,6 +77,7 @@ static void __init setup_bvci_lat_unit(void)
 
 /*----------------------- Platform Devices -----------------------------*/
 
+#if IS_ENABLED(CONFIG_SERIAL_ARC)
 static unsigned long arc_uart_info[] = {
        0,      /* uart->is_emulated (runtime @running_on_hw) */
        0,      /* uart->port.uartclk */
@@ -115,7 +116,7 @@ static struct platform_device arc_uart0_dev = {
 static struct platform_device *fpga_early_devs[] __initdata = {
        &arc_uart0_dev,
 };
-#endif
+#endif /* CONFIG_SERIAL_ARC_CONSOLE */
 
 static void arc_fpga_serial_init(void)
 {
@@ -152,8 +153,13 @@ static void arc_fpga_serial_init(void)
         * otherwise the early console never gets a chance to run.
         */
        add_preferred_console("ttyARC", 0, "115200");
-#endif
+#endif /* CONFIG_SERIAL_ARC_CONSOLE */
+}
+#else  /* !IS_ENABLED(CONFIG_SERIAL_ARC) */
+static void arc_fpga_serial_init(void)
+{
 }
+#endif
 
 static void __init plat_fpga_early_init(void)
 {
@@ -169,7 +175,7 @@ static void __init plat_fpga_early_init(void)
 }
 
 static struct of_dev_auxdata plat_auxdata_lookup[] __initdata = {
-#if defined(CONFIG_SERIAL_ARC) || defined(CONFIG_SERIAL_ARC_MODULE)
+#if IS_ENABLED(CONFIG_SERIAL_ARC)
        OF_DEV_AUXDATA("snps,arc-uart", UART0_BASE, "arc-uart", arc_uart_info),
 #endif
        {}
index de7049bdea857b291bab04b24362b50f096d68d7..531cdda016f92b69af9369b4a9024a74f77fa2a3 100644 (file)
@@ -175,6 +175,9 @@ config ARCH_HAS_CPUFREQ
          and that the relevant menu configurations are displayed for
          it.
 
+config ARCH_HAS_BANDGAP
+       bool
+
 config GENERIC_HWEIGHT
        bool
        default y
@@ -1450,7 +1453,7 @@ config SMP
        depends on CPU_V6K || CPU_V7
        depends on GENERIC_CLOCKEVENTS
        depends on HAVE_SMP
-       depends on MMU
+       depends on MMU || ARM_MPU
        select USE_GENERIC_SMP_HELPERS
        help
          This enables support for systems with more than one CPU. If you have
@@ -1471,7 +1474,7 @@ config SMP
 
 config SMP_ON_UP
        bool "Allow booting SMP kernel on uniprocessor systems (EXPERIMENTAL)"
-       depends on SMP && !XIP_KERNEL
+       depends on SMP && !XIP_KERNEL && MMU
        default y
        help
          SMP kernels contain instructions which fail on non-SMP processors.
@@ -1744,6 +1747,14 @@ config HW_PERF_EVENTS
          Enable hardware performance counter support for perf events. If
          disabled, perf events will use software events only.
 
+config SYS_SUPPORTS_HUGETLBFS
+       def_bool y
+       depends on ARM_LPAE
+
+config HAVE_ARCH_TRANSPARENT_HUGEPAGE
+       def_bool y
+       depends on ARM_LPAE
+
 source "mm/Kconfig"
 
 config FORCE_MAX_ZONEORDER
index c859495da48046e7b0427845ed265535f3f2aa3d..aed66d5df7f1546ac48cf93ee9c4f2aeb91d5b76 100644 (file)
@@ -50,3 +50,15 @@ config REMAP_VECTORS_TO_RAM
          Otherwise, say 'y' here.  In this case, the kernel will require
          external support to redirect the hardware exception vectors to
          the writable versions located at DRAM_BASE.
+
+config ARM_MPU
+       bool 'Use the ARM v7 PMSA Compliant MPU'
+       depends on CPU_V7
+       default y
+       help
+         Some ARM systems without an MMU have instead a Memory Protection
+         Unit (MPU) that defines the type and permissions for regions of
+         memory.
+
+         If your CPU has an MPU then you should choose 'y' here unless you
+         know that you do not want to use the MPU.
index ff4920b1f6c50bb3bf772f142b3c7fe28d89976e..e401a766c0bdaf633f9dd14977eb231d2b2656e9 100644 (file)
@@ -560,6 +560,13 @@ choice
                  of the tiles using the RS1 memory map, including all new A-class
                  core tiles, FPGA-based SMMs and software models.
 
+       config DEBUG_VEXPRESS_UART0_CRX
+               bool "Use PL011 UART0 at 0xb0090000 (Cortex-R compliant tiles)"
+               depends on ARCH_VEXPRESS && !MMU
+               help
+                 This option selects UART0 at 0xb0090000. This is appropriate for
+                 Cortex-R series tiles and SMMs, such as Cortex-R5 and Cortex-R7
+
        config DEBUG_VT8500_UART0
                bool "Use UART0 on VIA/Wondermedia SoCs"
                depends on ARCH_VT8500
@@ -789,7 +796,8 @@ config DEBUG_LL_INCLUDE
        default "debug/u300.S" if DEBUG_U300_UART
        default "debug/ux500.S" if DEBUG_UX500_UART
        default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT || \
-               DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1
+               DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1 || \
+               DEBUG_VEXPRESS_UART0_CRX
        default "debug/vt8500.S" if DEBUG_VT8500_UART0
        default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
        default "mach/debug-macro.S"
index 72caf82a8280c816e4517f05c9444261d77795b8..c0ac0f5e5e5c0900c5e0e081390e0af900005738 100644 (file)
@@ -59,38 +59,44 @@ comma = ,
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
-arch-$(CONFIG_CPU_32v7M)       :=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
-arch-$(CONFIG_CPU_32v7)                :=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
-arch-$(CONFIG_CPU_32v6)                :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
+arch-$(CONFIG_CPU_32v7M)       =-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
+arch-$(CONFIG_CPU_32v7)                =-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
+arch-$(CONFIG_CPU_32v6)                =-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
 # Only override the compiler option if ARMv6. The ARMv6K extensions are
 # always available in ARMv7
 ifeq ($(CONFIG_CPU_32v6),y)
-arch-$(CONFIG_CPU_32v6K)       :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k)
+arch-$(CONFIG_CPU_32v6K)       =-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k)
 endif
-arch-$(CONFIG_CPU_32v5)                :=-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t)
-arch-$(CONFIG_CPU_32v4T)       :=-D__LINUX_ARM_ARCH__=4 -march=armv4t
-arch-$(CONFIG_CPU_32v4)                :=-D__LINUX_ARM_ARCH__=4 -march=armv4
-arch-$(CONFIG_CPU_32v3)                :=-D__LINUX_ARM_ARCH__=3 -march=armv3
+arch-$(CONFIG_CPU_32v5)                =-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t)
+arch-$(CONFIG_CPU_32v4T)       =-D__LINUX_ARM_ARCH__=4 -march=armv4t
+arch-$(CONFIG_CPU_32v4)                =-D__LINUX_ARM_ARCH__=4 -march=armv4
+arch-$(CONFIG_CPU_32v3)                =-D__LINUX_ARM_ARCH__=3 -march=armv3
+
+# Evaluate arch cc-option calls now
+arch-y := $(arch-y)
 
 # This selects how we optimise for the processor.
-tune-$(CONFIG_CPU_ARM7TDMI)    :=-mtune=arm7tdmi
-tune-$(CONFIG_CPU_ARM720T)     :=-mtune=arm7tdmi
-tune-$(CONFIG_CPU_ARM740T)     :=-mtune=arm7tdmi
-tune-$(CONFIG_CPU_ARM9TDMI)    :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM940T)     :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM946E)     :=$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi)
-tune-$(CONFIG_CPU_ARM920T)     :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM922T)     :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM925T)     :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM926T)     :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_FA526)       :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_SA110)       :=-mtune=strongarm110
-tune-$(CONFIG_CPU_SA1100)      :=-mtune=strongarm1100
-tune-$(CONFIG_CPU_XSCALE)      :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
-tune-$(CONFIG_CPU_XSC3)                :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
-tune-$(CONFIG_CPU_FEROCEON)    :=$(call cc-option,-mtune=marvell-f,-mtune=xscale)
-tune-$(CONFIG_CPU_V6)          :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
-tune-$(CONFIG_CPU_V6K)         :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+tune-$(CONFIG_CPU_ARM7TDMI)    =-mtune=arm7tdmi
+tune-$(CONFIG_CPU_ARM720T)     =-mtune=arm7tdmi
+tune-$(CONFIG_CPU_ARM740T)     =-mtune=arm7tdmi
+tune-$(CONFIG_CPU_ARM9TDMI)    =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM940T)     =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM946E)     =$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi)
+tune-$(CONFIG_CPU_ARM920T)     =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM922T)     =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM925T)     =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM926T)     =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_FA526)       =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_SA110)       =-mtune=strongarm110
+tune-$(CONFIG_CPU_SA1100)      =-mtune=strongarm1100
+tune-$(CONFIG_CPU_XSCALE)      =$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
+tune-$(CONFIG_CPU_XSC3)                =$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
+tune-$(CONFIG_CPU_FEROCEON)    =$(call cc-option,-mtune=marvell-f,-mtune=xscale)
+tune-$(CONFIG_CPU_V6)          =$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+tune-$(CONFIG_CPU_V6K)         =$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+
+# Evaluate tune cc-option calls now
+tune-y := $(tune-y)
 
 ifeq ($(CONFIG_AEABI),y)
 CFLAGS_ABI     :=-mabi=aapcs-linux -mno-thumb-interwork
@@ -295,9 +301,10 @@ zImage Image xipImage bootpImage uImage: vmlinux
 zinstall uinstall install: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
 
-%.dtb: scripts
+%.dtb: scripts
        $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@
 
+PHONY += dtbs
 dtbs: scripts
        $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) dtbs
 
index 120b83bfde20e5b8f3d46b4f13ff4c82ef75a471..48d0a44270bd8b419555f48a0a46ed2c85de5cbb 100644 (file)
@@ -27,7 +27,7 @@ OBJS  += misc.o decompress.o
 ifeq ($(CONFIG_DEBUG_UNCOMPRESS),y)
 OBJS   += debug.o
 endif
-FONTC  = $(srctree)/drivers/video/console/font_acorn_8x8.c
+FONTC  = $(srctree)/lib/fonts/font_acorn_8x8.c
 
 # string library code (-Os is enforced to keep it much smaller)
 OBJS           += string.o
index aabc02a68482a912545ab67221070ad2ccf51e11..d1153c8a765a05c23d62e7a25d9197186902a3ea 100644 (file)
@@ -53,6 +53,17 @@ static const void *getprop(const void *fdt, const char *node_path,
        return fdt_getprop(fdt, offset, property, len);
 }
 
+static uint32_t get_cell_size(const void *fdt)
+{
+       int len;
+       uint32_t cell_size = 1;
+       const uint32_t *size_len =  getprop(fdt, "/", "#size-cells", &len);
+
+       if (size_len)
+               cell_size = fdt32_to_cpu(*size_len);
+       return cell_size;
+}
+
 static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
 {
        char cmdline[COMMAND_LINE_SIZE];
@@ -95,9 +106,11 @@ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
 int atags_to_fdt(void *atag_list, void *fdt, int total_space)
 {
        struct tag *atag = atag_list;
-       uint32_t mem_reg_property[2 * NR_BANKS];
+       /* In the case of 64 bits memory size, need to reserve 2 cells for
+        * address and size for each bank */
+       uint32_t mem_reg_property[2 * 2 * NR_BANKS];
        int memcount = 0;
-       int ret;
+       int ret, memsize;
 
        /* make sure we've got an aligned pointer */
        if ((u32)atag_list & 0x3)
@@ -137,8 +150,25 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)
                                continue;
                        if (!atag->u.mem.size)
                                continue;
-                       mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start);
-                       mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size);
+                       memsize = get_cell_size(fdt);
+
+                       if (memsize == 2) {
+                               /* if memsize is 2, that means that
+                                * each data needs 2 cells of 32 bits,
+                                * so the data are 64 bits */
+                               uint64_t *mem_reg_prop64 =
+                                       (uint64_t *)mem_reg_property;
+                               mem_reg_prop64[memcount++] =
+                                       cpu_to_fdt64(atag->u.mem.start);
+                               mem_reg_prop64[memcount++] =
+                                       cpu_to_fdt64(atag->u.mem.size);
+                       } else {
+                               mem_reg_property[memcount++] =
+                                       cpu_to_fdt32(atag->u.mem.start);
+                               mem_reg_property[memcount++] =
+                                       cpu_to_fdt32(atag->u.mem.size);
+                       }
+
                } else if (atag->hdr.tag == ATAG_INITRD2) {
                        uint32_t initrd_start, initrd_size;
                        initrd_start = atag->u.initrd.start;
@@ -150,8 +180,10 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)
                }
        }
 
-       if (memcount)
-               setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount);
+       if (memcount) {
+               setprop(fdt, "/memory", "reg", mem_reg_property,
+                       4 * memcount * memsize);
+       }
 
        return fdt_pack(fdt);
 }
index 032a8d987148b6a24c97d7ec05467bef14b82ab0..75189f13cf54c63d0db56b98ad2c41834a30893e 100644 (file)
@@ -142,7 +142,6 @@ start:
                mov     r7, r1                  @ save architecture ID
                mov     r8, r2                  @ save atags pointer
 
-#ifndef __ARM_ARCH_2__
                /*
                 * Booting from Angel - need to enter SVC mode and disable
                 * FIQs/IRQs (numeric definitions from angel arm.h source).
@@ -158,10 +157,6 @@ not_angel:
                safe_svcmode_maskall r0
                msr     spsr_cxsf, r9           @ Save the CPU boot mode in
                                                @ SPSR
-#else
-               teqp    pc, #0x0c000003         @ turn off interrupts
-#endif
-
                /*
                 * Note that some cache flushing and other stuff may
                 * be needed here - is there an Angel SWI call for this?
@@ -183,7 +178,19 @@ not_angel:
                ldr     r4, =zreladdr
 #endif
 
-               bl      cache_on
+               /*
+                * Set up a page table only if it won't overwrite ourself.
+                * That means r4 < pc && r4 - 16k page directory > &_end.
+                * Given that r4 > &_end is most unfrequent, we add a rough
+                * additional 1MB of room for a possible appended DTB.
+                */
+               mov     r0, pc
+               cmp     r0, r4
+               ldrcc   r0, LC0+32
+               addcc   r0, r0, pc
+               cmpcc   r4, r0
+               orrcc   r4, r4, #1              @ remember we skipped cache_on
+               blcs    cache_on
 
 restart:       adr     r0, LC0
                ldmia   r0, {r1, r2, r3, r6, r10, r11, r12}
@@ -229,7 +236,7 @@ restart:    adr     r0, LC0
  *   r0  = delta
  *   r2  = BSS start
  *   r3  = BSS end
- *   r4  = final kernel address
+ *   r4  = final kernel address (possibly with LSB set)
  *   r5  = appended dtb size (still unknown)
  *   r6  = _edata
  *   r7  = architecture ID
@@ -277,6 +284,7 @@ restart:    adr     r0, LC0
                 */
                cmp     r0, #1
                sub     r0, r4, #TEXT_OFFSET
+               bic     r0, r0, #1
                add     r0, r0, #0x100
                mov     r1, r6
                sub     r2, sp, r6
@@ -323,12 +331,13 @@ dtb_check_done:
 
 /*
  * Check to see if we will overwrite ourselves.
- *   r4  = final kernel address
+ *   r4  = final kernel address (possibly with LSB set)
  *   r9  = size of decompressed image
  *   r10 = end of this image, including  bss/stack/malloc space if non XIP
  * We basically want:
  *   r4 - 16k page directory >= r10 -> OK
  *   r4 + image length <= address of wont_overwrite -> OK
+ * Note: the possible LSB in r4 is harmless here.
  */
                add     r10, r10, #16384
                cmp     r4, r10
@@ -390,7 +399,8 @@ dtb_check_done:
                add     sp, sp, r6
 #endif
 
-               bl      cache_clean_flush
+               tst     r4, #1
+               bleq    cache_clean_flush
 
                adr     r0, BSYM(restart)
                add     r0, r0, r6
@@ -402,7 +412,7 @@ wont_overwrite:
  *   r0  = delta
  *   r2  = BSS start
  *   r3  = BSS end
- *   r4  = kernel execution address
+ *   r4  = kernel execution address (possibly with LSB set)
  *   r5  = appended dtb size (0 if not present)
  *   r7  = architecture ID
  *   r8  = atags pointer
@@ -465,6 +475,15 @@ not_relocated:     mov     r0, #0
                cmp     r2, r3
                blo     1b
 
+               /*
+                * Did we skip the cache setup earlier?
+                * That is indicated by the LSB in r4.
+                * Do it now if so.
+                */
+               tst     r4, #1
+               bic     r4, r4, #1
+               blne    cache_on
+
 /*
  * The C runtime environment should now be setup sufficiently.
  * Set up some pointers, and start decompressing.
@@ -513,6 +532,7 @@ LC0:                .word   LC0                     @ r1
                .word   _got_start              @ r11
                .word   _got_end                @ ip
                .word   .L_user_stack_end       @ sp
+               .word   _end - restart + 16384 + 1024*1024
                .size   LC0, . - LC0
 
 #ifdef CONFIG_ARCH_RPC
index 7d1a27949c13716c41e0fc3b72dd40b6998aff23..9866cd736deea9143ac684b3c5d5313e658ab391 100644 (file)
                };
 
                rtc-iobg {
-                       compatible = "sirf,prima2-rtciobg", "sirf-prima2-rtciobg-bus";
+                       compatible = "sirf,prima2-rtciobg", "sirf-prima2-rtciobg-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0x80030000 0x10000>;
index 17979d5f23b4a5a2d543e54f66108cdcc64a5045..c0cdf66f8964f7a800390ee0dd8c6899b5c0baad 100644 (file)
        };
 
        L2: l2-cache {
-                   compatible = "arm,pl310-cache";
-                   reg = <0x3ff20000 0x1000>;
-                   cache-unified;
-                   cache-level = <2>;
+               compatible = "bcm,bcm11351-a2-pl310-cache";
+               reg = <0x3ff20000 0x1000>;
+               cache-unified;
+               cache-level = <2>;
        };
 
        timer@35006000 {
index d61b535f682a178e2453afb8c2186070c293fbb1..e8559b753c9de009595bcc6f4f7dc981b131bbee 100644 (file)
@@ -33,6 +33,8 @@
                        calxeda,port-phys = <&combophy5 0 &combophy0 0
                                             &combophy0 1 &combophy0 2
                                             &combophy0 3>;
+                       calxeda,sgpio-gpio =<&gpioh 5 1 &gpioh 6 1 &gpioh 7 1>;
+                       calxeda,led-order = <4 0 1 2 3>;
                };
 
                sdhci@ffe0e000 {
index 02edd8965f8ae3f9f6f710a3290f4d84f7eb7a5e..05e9489cf95c835f4442e90fb47fd3eb92900e79 100644 (file)
                };
 
                rtc-iobg {
-                       compatible = "sirf,prima2-rtciobg", "sirf-prima2-rtciobg-bus";
+                       compatible = "sirf,prima2-rtciobg", "sirf-prima2-rtciobg-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0x80030000 0x10000>;
index 8178705c4b248a782f04cd29f5ff8298f5328e47..80f033614a1fa07d90de18de6673ce45ec0bf91b 100644 (file)
 1901:  adr     r0, 1902b
        bl      printascii
        mov     r0, r9
-       bl      printhex8
+       bl      printhex2
        adr     r0, 1903b
        bl      printascii
        mov     r0, r10
-       bl      printhex8
+       bl      printhex2
        adr     r0, 1904b
        bl      printascii
 #endif
index 3caed0db698614f45652476595ed54b42de54ffc..510e5b13aa2e2a4e65c01de1ce9a82635b01bce4 100644 (file)
 #include <asm/smp.h>
 #include <asm/smp_plat.h>
 
-static void __init simple_smp_init_cpus(void)
-{
-}
-
 static int __cpuinit mcpm_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
        unsigned int mpidr, pcpu, pcluster, ret;
@@ -74,7 +70,6 @@ static void mcpm_cpu_die(unsigned int cpu)
 #endif
 
 static struct smp_operations __initdata mcpm_smp_ops = {
-       .smp_init_cpus          = simple_smp_init_cpus,
        .smp_boot_secondary     = mcpm_boot_secondary,
        .smp_secondary_init     = mcpm_secondary_init,
 #ifdef CONFIG_HOTPLUG_CPU
index f9b7fccd795deecc6764891b9243d1369cc3405a..0870b5cd5533c7788965b9ba14a2a6d0fb6ade30 100644 (file)
@@ -38,6 +38,8 @@ CONFIG_NR_CPUS=2
 CONFIG_LEDS=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
 CONFIG_KEXEC=y
 CONFIG_FPE_NWFPE=y
@@ -156,6 +158,13 @@ CONFIG_W1=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_SENSORS_LM75=m
 CONFIG_WATCHDOG=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_CPU_THERMAL=y
 CONFIG_OMAP_WATCHDOG=y
 CONFIG_TWL4030_WATCHDOG=y
 CONFIG_MFD_TPS65217=y
@@ -242,7 +251,13 @@ CONFIG_RTC_DRV_TWL92330=y
 CONFIG_RTC_DRV_TWL4030=y
 CONFIG_RTC_DRV_OMAP=y
 CONFIG_DMADEVICES=y
+CONFIG_TI_EDMA=y
 CONFIG_DMA_OMAP=y
+CONFIG_TI_SOC_THERMAL=y
+CONFIG_TI_THERMAL=y
+CONFIG_OMAP4_THERMAL=y
+CONFIG_OMAP5_THERMAL=y
+CONFIG_DRA752_THERMAL=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
index 7c1bfc0aea0c200a268ec82c62fd4cb624c17ecf..accefe0991828e2984c5c1ff49b25dece76edcc0 100644 (file)
@@ -80,15 +80,6 @@ static inline u32 arch_timer_get_cntfrq(void)
        return val;
 }
 
-static inline u64 arch_counter_get_cntpct(void)
-{
-       u64 cval;
-
-       isb();
-       asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
-       return cval;
-}
-
 static inline u64 arch_counter_get_cntvct(void)
 {
        u64 cval;
index cedd3721318b2f1a4251717ab383ee865e2aef7c..6493802f880a9102148b2127b3f2d4edd4d86d1b 100644 (file)
 #define CR_RR  (1 << 14)       /* Round Robin cache replacement        */
 #define CR_L4  (1 << 15)       /* LDR pc can set T bit                 */
 #define CR_DT  (1 << 16)
+#ifdef CONFIG_MMU
+#define CR_HA  (1 << 17)       /* Hardware management of Access Flag   */
+#else
+#define CR_BR  (1 << 17)       /* MPU Background region enable (PMSA)  */
+#endif
 #define CR_IT  (1 << 18)
 #define CR_ST  (1 << 19)
 #define CR_FI  (1 << 21)       /* Fast interrupt (lower latency mode)  */
index d7deb62554c906d136de542c8aa278fb814d5bb5..8c25dc4e98514d85db8ce77f4d9e7fa8f828262d 100644 (file)
@@ -8,6 +8,7 @@
 #define CPUID_CACHETYPE        1
 #define CPUID_TCM      2
 #define CPUID_TLBTYPE  3
+#define CPUID_MPUIR    4
 #define CPUID_MPIDR    5
 
 #ifdef CONFIG_CPU_V7M
index fe92ccf1d0b0c7a43417f0d6675516840c149feb..191ada6e4d2db3393270ef9595e9cc083e441909 100644 (file)
@@ -46,7 +46,7 @@
        __rem;                                                  \
 })
 
-#if __GNUC__ < 4
+#if __GNUC__ < 4 || !defined(CONFIG_AEABI)
 
 /*
  * gcc versions earlier than 4.0 are simply too problematic for the
index e6168c0c18e923e4764031ef7e18f384f1f704ba..74a8b84f3cb1d1d35f9de0461483968cc93132bc 100644 (file)
 # endif
 #endif
 
-#ifdef CONFIG_CPU_PJ4B
+#ifdef CONFIG_CPU_V7M
 # ifdef CPU_NAME
 #  undef  MULTI_CPU
 #  define MULTI_CPU
 # else
-#  define CPU_NAME cpu_pj4b
+#  define CPU_NAME cpu_v7m
 # endif
 #endif
 
-#ifdef CONFIG_CPU_V7M
+#ifdef CONFIG_CPU_PJ4B
 # ifdef CPU_NAME
 #  undef  MULTI_CPU
 #  define MULTI_CPU
 # else
-#  define CPU_NAME cpu_v7m
+#  define CPU_NAME cpu_pj4b
 # endif
 #endif
 
diff --git a/arch/arm/include/asm/hugetlb-3level.h b/arch/arm/include/asm/hugetlb-3level.h
new file mode 100644 (file)
index 0000000..d4014fb
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * arch/arm/include/asm/hugetlb-3level.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * Based on arch/x86/include/asm/hugetlb.h.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ASM_ARM_HUGETLB_3LEVEL_H
+#define _ASM_ARM_HUGETLB_3LEVEL_H
+
+
+/*
+ * If our huge pte is non-zero then mark the valid bit.
+ * This allows pte_present(huge_ptep_get(ptep)) to return true for non-zero
+ * ptes.
+ * (The valid bit is automatically cleared by set_pte_at for PROT_NONE ptes).
+ */
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+       pte_t retval = *ptep;
+       if (pte_val(retval))
+               pte_val(retval) |= L_PTE_VALID;
+       return retval;
+}
+
+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);
+}
+
+#endif /* _ASM_ARM_HUGETLB_3LEVEL_H */
diff --git a/arch/arm/include/asm/hugetlb.h b/arch/arm/include/asm/hugetlb.h
new file mode 100644 (file)
index 0000000..1f1b1cd
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/include/asm/hugetlb.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * Based on arch/x86/include/asm/hugetlb.h
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ASM_ARM_HUGETLB_H
+#define _ASM_ARM_HUGETLB_H
+
+#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
+
+#include <asm/hugetlb-3level.h>
+
+static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
+                                         unsigned long addr, unsigned long end,
+                                         unsigned long floor,
+                                         unsigned long ceiling)
+{
+       free_pgd_range(tlb, addr, end, floor, ceiling);
+}
+
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+                                        unsigned long addr, unsigned long len)
+{
+       return 0;
+}
+
+static inline int prepare_hugepage_range(struct file *file,
+                                        unsigned long addr, unsigned long len)
+{
+       struct hstate *h = hstate_file(file);
+       if (len & ~huge_page_mask(h))
+               return -EINVAL;
+       if (addr & ~huge_page_mask(h))
+               return -EINVAL;
+       return 0;
+}
+
+static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
+{
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+       return pte_none(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+       return pte_wrprotect(pte);
+}
+
+static inline int arch_prepare_hugepage(struct page *page)
+{
+       return 0;
+}
+
+static inline void arch_release_hugepage(struct page *page)
+{
+}
+
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+       clear_bit(PG_dcache_clean, &page->flags);
+}
+
+#endif /* _ASM_ARM_HUGETLB_H */
index 652b56086de79d1c1922f06d2fb7cb87f5d29da2..d070741b2b37b24c8cc1fe4284ecdccc6eb306ba 100644 (file)
@@ -130,16 +130,16 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
  */
 extern void __iomem *__arm_ioremap_pfn_caller(unsigned long, unsigned long,
        size_t, unsigned int, void *);
-extern void __iomem *__arm_ioremap_caller(unsigned long, size_t, unsigned int,
+extern void __iomem *__arm_ioremap_caller(phys_addr_t, size_t, unsigned int,
        void *);
 
 extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
-extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int);
-extern void __iomem *__arm_ioremap_exec(unsigned long, size_t, bool cached);
+extern void __iomem *__arm_ioremap(phys_addr_t, size_t, unsigned int);
+extern void __iomem *__arm_ioremap_exec(phys_addr_t, size_t, bool cached);
 extern void __iounmap(volatile void __iomem *addr);
 extern void __arm_iounmap(volatile void __iomem *addr);
 
-extern void __iomem * (*arch_ioremap_caller)(unsigned long, size_t,
+extern void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
        unsigned int, void *);
 extern void (*arch_iounmap)(volatile void __iomem *);
 
index 124623e5ef14ab2bde6b6ab954901fa4d4b8c3a7..64e96960de297c850c480f1df3be1dc331ee891a 100644 (file)
 #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 S2_PGD_SIZE    (1 << S2_PGD_ORDER)
 
 /* Virtualization Translation Control Register (VTCR) bits */
 #define VTCR_SH0       (3 << 12)
index 18d50322a9e2fd147c361717097dba4d1a2ba35d..a2f43ddcc3004aeaa342666c4973277f076390cd 100644 (file)
 #define c5_AIFSR       15      /* Auxilary Instrunction Fault Status R */
 #define c6_DFAR                16      /* Data Fault Address Register */
 #define c6_IFAR                17      /* Instruction Fault Address Register */
-#define c9_L2CTLR      18      /* Cortex A15 L2 Control Register */
-#define c10_PRRR       19      /* Primary Region Remap Register */
-#define c10_NMRR       20      /* Normal Memory Remap Register */
-#define c12_VBAR       21      /* Vector Base Address Register */
-#define c13_CID                22      /* Context ID Register */
-#define c13_TID_URW    23      /* Thread ID, User R/W */
-#define c13_TID_URO    24      /* Thread ID, User R/O */
-#define c13_TID_PRIV   25      /* Thread ID, Privileged */
-#define c14_CNTKCTL    26      /* Timer Control Register (PL1) */
-#define NR_CP15_REGS   27      /* Number of regs (incl. invalid) */
+#define c7_PAR         18      /* Physical Address Register */
+#define c7_PAR_high    19      /* PAR top 32 bits */
+#define c9_L2CTLR      20      /* Cortex A15 L2 Control Register */
+#define c10_PRRR       21      /* Primary Region Remap Register */
+#define c10_NMRR       22      /* Normal Memory Remap Register */
+#define c12_VBAR       23      /* Vector Base Address Register */
+#define c13_CID                24      /* Context ID Register */
+#define c13_TID_URW    25      /* Thread ID, User R/W */
+#define c13_TID_URO    26      /* Thread ID, User R/O */
+#define c13_TID_PRIV   27      /* Thread ID, Privileged */
+#define c14_CNTKCTL    28      /* Timer Control Register (PL1) */
+#define NR_CP15_REGS   29      /* Number of regs (incl. invalid) */
 
 #define ARM_EXCEPTION_RESET      0
 #define ARM_EXCEPTION_UNDEFINED   1
@@ -72,8 +74,6 @@ extern char __kvm_hyp_vector[];
 extern char __kvm_hyp_code_start[];
 extern char __kvm_hyp_code_end[];
 
-extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
-
 extern void __kvm_flush_vm_context(void);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
 
index 82b4babead2c8b7bff97a2c9b0e3f3fc37ba63f7..a464e8d7b6c58f77c5f57fdda4202587f2331962 100644 (file)
@@ -65,11 +65,6 @@ static inline bool vcpu_mode_priv(struct kvm_vcpu *vcpu)
        return cpsr_mode > USR_MODE;;
 }
 
-static inline bool kvm_vcpu_reg_is_pc(struct kvm_vcpu *vcpu, int reg)
-{
-       return reg == 15;
-}
-
 static inline u32 kvm_vcpu_get_hsr(struct kvm_vcpu *vcpu)
 {
        return vcpu->arch.fault.hsr;
index 57cb786a6203de0d6444d1f265344a59abc0de09..7d22517d8071192e467a6653a177ab08742d2650 100644 (file)
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmio.h>
 #include <asm/fpstate.h>
-#include <asm/kvm_arch_timer.h>
+#include <kvm/arm_arch_timer.h>
 
+#if defined(CONFIG_KVM_ARM_MAX_VCPUS)
 #define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
+#else
+#define KVM_MAX_VCPUS 0
+#endif
+
 #define KVM_USER_MEM_SLOTS 32
 #define KVM_PRIVATE_MEM_SLOTS 4
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
@@ -38,7 +43,7 @@
 #define KVM_NR_PAGE_SIZES      1
 #define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
 
-#include <asm/kvm_vgic.h>
+#include <kvm/arm_vgic.h>
 
 struct kvm_vcpu;
 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
@@ -190,8 +195,8 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
 int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
                int exception_index);
 
-static inline void __cpu_init_hyp_mode(unsigned long long boot_pgd_ptr,
-                                      unsigned long long pgd_ptr,
+static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
+                                      phys_addr_t pgd_ptr,
                                       unsigned long hyp_stack_ptr,
                                       unsigned long vector_ptr)
 {
index 57870ab313c52cd103b327363b0191e76efad9f6..e750a938fd3ce283ccd351cb73ed9c3d8df84e75 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/types.h>
 #include <linux/sizes.h>
 
+#include <asm/cache.h>
+
 #ifdef CONFIG_NEED_MACH_MEMORY_H
 #include <mach/memory.h>
 #endif
 #define page_to_phys(page)     (__pfn_to_phys(page_to_pfn(page)))
 #define phys_to_page(phys)     (pfn_to_page(__phys_to_pfn(phys)))
 
+/*
+ * Minimum guaranted alignment in pgd_alloc().  The page table pointers passed
+ * around in head.S and proc-*.S are shifted by this amount, in order to
+ * leave spare high bits for systems with physical address extension.  This
+ * does not fully accomodate the 40-bit addressing capability of ARM LPAE, but
+ * gives us about 38-bits or so.
+ */
+#ifdef CONFIG_ARM_LPAE
+#define ARCH_PGD_SHIFT         L1_CACHE_SHIFT
+#else
+#define ARCH_PGD_SHIFT         0
+#endif
+#define ARCH_PGD_MASK          ((1 << ARCH_PGD_SHIFT) - 1)
+
 #ifndef __ASSEMBLY__
 
 /*
@@ -207,7 +223,7 @@ static inline unsigned long __phys_to_virt(unsigned long x)
  * direct-mapped view.  We assume this is the first page
  * of RAM in the mem_map as well.
  */
-#define PHYS_PFN_OFFSET        (PHYS_OFFSET >> PAGE_SHIFT)
+#define PHYS_PFN_OFFSET        ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT))
 
 /*
  * These are *only* valid on the kernel direct mapped RAM memory.
@@ -260,12 +276,6 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
 /*
  * Conversion between a struct page and a physical address.
  *
- * Note: when converting an unknown physical address to a
- * struct page, the resulting pointer must be validated
- * using VALID_PAGE().  It must return an invalid struct page
- * for any physical address not corresponding to a system
- * RAM address.
- *
  *  page_to_pfn(page)  convert a struct page * to a PFN number
  *  pfn_to_page(pfn)   convert a _valid_ PFN number to struct page *
  *
index a7b85e0d0cc154a90a2efadca763cc60d95e82d8..b5792b7fd8d3149c94c87f5650410b3ece3a2bd2 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
 #include <asm/proc-fns.h>
+#include <asm/smp_plat.h>
 #include <asm-generic/mm_hooks.h>
 
 void __check_vmalloc_seq(struct mm_struct *mm);
@@ -27,7 +28,15 @@ void __check_vmalloc_seq(struct mm_struct *mm);
 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; })
 
-DECLARE_PER_CPU(atomic64_t, active_asids);
+#ifdef CONFIG_ARM_ERRATA_798181
+void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
+                            cpumask_t *mask);
+#else  /* !CONFIG_ARM_ERRATA_798181 */
+static inline void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
+                                          cpumask_t *mask)
+{
+}
+#endif /* CONFIG_ARM_ERRATA_798181 */
 
 #else  /* !CONFIG_CPU_HAS_ASID */
 
@@ -98,12 +107,16 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
 #ifdef CONFIG_MMU
        unsigned int cpu = smp_processor_id();
 
-#ifdef CONFIG_SMP
-       /* check for possible thread migration */
-       if (!cpumask_empty(mm_cpumask(next)) &&
+       /*
+        * __sync_icache_dcache doesn't broadcast the I-cache invalidation,
+        * so check for possible thread migration and invalidate the I-cache
+        * if we're new to this CPU.
+        */
+       if (cache_ops_need_broadcast() &&
+           !cpumask_empty(mm_cpumask(next)) &&
            !cpumask_test_cpu(cpu, mm_cpumask(next)))
                __flush_icache_all();
-#endif
+
        if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) {
                check_and_switch_context(next, tsk);
                if (cache_is_vivt())
diff --git a/arch/arm/include/asm/mpu.h b/arch/arm/include/asm/mpu.h
new file mode 100644 (file)
index 0000000..c3247cc
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef __ARM_MPU_H
+#define __ARM_MPU_H
+
+#ifdef CONFIG_ARM_MPU
+
+/* MPUIR layout */
+#define MPUIR_nU               1
+#define MPUIR_DREGION          8
+#define MPUIR_IREGION          16
+#define MPUIR_DREGION_SZMASK   (0xFF << MPUIR_DREGION)
+#define MPUIR_IREGION_SZMASK   (0xFF << MPUIR_IREGION)
+
+/* ID_MMFR0 data relevant to MPU */
+#define MMFR0_PMSA             (0xF << 4)
+#define MMFR0_PMSAv7           (3 << 4)
+
+/* MPU D/I Size Register fields */
+#define MPU_RSR_SZ             1
+#define MPU_RSR_EN             0
+
+/* The D/I RSR value for an enabled region spanning the whole of memory */
+#define MPU_RSR_ALL_MEM                63
+
+/* Individual bits in the DR/IR ACR */
+#define MPU_ACR_XN             (1 << 12)
+#define MPU_ACR_SHARED         (1 << 2)
+
+/* C, B and TEX[2:0] bits only have semantic meanings when grouped */
+#define MPU_RGN_CACHEABLE      0xB
+#define MPU_RGN_SHARED_CACHEABLE (MPU_RGN_CACHEABLE | MPU_ACR_SHARED)
+#define MPU_RGN_STRONGLY_ORDERED 0
+
+/* Main region should only be shared for SMP */
+#ifdef CONFIG_SMP
+#define MPU_RGN_NORMAL         (MPU_RGN_CACHEABLE | MPU_ACR_SHARED)
+#else
+#define MPU_RGN_NORMAL         MPU_RGN_CACHEABLE
+#endif
+
+/* Access permission bits of ACR (only define those that we use)*/
+#define MPU_AP_PL1RW_PL0RW     (0x3 << 8)
+#define MPU_AP_PL1RW_PL0R0     (0x2 << 8)
+#define MPU_AP_PL1RW_PL0NA     (0x1 << 8)
+
+/* For minimal static MPU region configurations */
+#define MPU_PROBE_REGION       0
+#define MPU_BG_REGION          1
+#define MPU_RAM_REGION         2
+#define MPU_VECTORS_REGION     3
+
+/* Maximum number of regions Linux is interested in */
+#define MPU_MAX_REGIONS                16
+
+#define MPU_DATA_SIDE          0
+#define MPU_INSTR_SIDE         1
+
+#ifndef __ASSEMBLY__
+
+struct mpu_rgn {
+       /* Assume same attributes for d/i-side  */
+       u32 drbar;
+       u32 drsr;
+       u32 dracr;
+};
+
+struct mpu_rgn_info {
+       u32 mpuir;
+       struct mpu_rgn rgns[MPU_MAX_REGIONS];
+};
+extern struct mpu_rgn_info mpu_rgn_info;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_ARM_MPU */
+
+#endif
index 812a4944e78343469a2216327a746f37ce01b98c..6363f3d1d505292c57a26fbd3585b3f147738771 100644 (file)
@@ -13,7 +13,7 @@
 /* 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_MASK              (~((1 << PAGE_SHIFT) - 1))
 
 #ifndef __ASSEMBLY__
 
index 18f5cef82ad58988e1c8d9b77ab95eb995330bbf..626989fec4d334ef8c01f707f87de6a25c1d8a8e 100644 (file)
@@ -30,6 +30,7 @@
 #define PMD_TYPE_FAULT         (_AT(pmdval_t, 0) << 0)
 #define PMD_TYPE_TABLE         (_AT(pmdval_t, 3) << 0)
 #define PMD_TYPE_SECT          (_AT(pmdval_t, 1) << 0)
+#define PMD_TABLE_BIT          (_AT(pmdval_t, 1) << 1)
 #define PMD_BIT4               (_AT(pmdval_t, 0))
 #define PMD_DOMAIN(x)          (_AT(pmdval_t, 0))
 #define PMD_APTABLE_SHIFT      (61)
@@ -41,6 +42,8 @@
  */
 #define PMD_SECT_BUFFERABLE    (_AT(pmdval_t, 1) << 2)
 #define PMD_SECT_CACHEABLE     (_AT(pmdval_t, 1) << 3)
+#define PMD_SECT_USER          (_AT(pmdval_t, 1) << 6)         /* AP[1] */
+#define PMD_SECT_RDONLY                (_AT(pmdval_t, 1) << 7)         /* AP[2] */
 #define PMD_SECT_S             (_AT(pmdval_t, 3) << 8)
 #define PMD_SECT_AF            (_AT(pmdval_t, 1) << 10)
 #define PMD_SECT_nG            (_AT(pmdval_t, 1) << 11)
@@ -66,6 +69,7 @@
 #define PTE_TYPE_MASK          (_AT(pteval_t, 3) << 0)
 #define PTE_TYPE_FAULT         (_AT(pteval_t, 0) << 0)
 #define PTE_TYPE_PAGE          (_AT(pteval_t, 3) << 0)
+#define PTE_TABLE_BIT          (_AT(pteval_t, 1) << 1)
 #define PTE_BUFFERABLE         (_AT(pteval_t, 1) << 2)         /* AttrIndx[0] */
 #define PTE_CACHEABLE          (_AT(pteval_t, 1) << 3)         /* AttrIndx[1] */
 #define PTE_EXT_SHARED         (_AT(pteval_t, 3) << 8)         /* SH[1:0], inner shareable */
 #define PHYS_MASK_SHIFT                (40)
 #define PHYS_MASK              ((1ULL << PHYS_MASK_SHIFT) - 1)
 
+/*
+ * TTBR0/TTBR1 split (PAGE_OFFSET):
+ *   0x40000000: T0SZ = 2, T1SZ = 0 (not used)
+ *   0x80000000: T0SZ = 0, T1SZ = 1
+ *   0xc0000000: T0SZ = 0, T1SZ = 2
+ *
+ * Only use this feature if PHYS_OFFSET <= PAGE_OFFSET, otherwise
+ * booting secondary CPUs would end up using TTBR1 for the identity
+ * mapping set up in TTBR0.
+ */
+#if defined CONFIG_VMSPLIT_2G
+#define TTBR1_OFFSET   16                      /* skip two L1 entries */
+#elif defined CONFIG_VMSPLIT_3G
+#define TTBR1_OFFSET   (4096 * (1 + 3))        /* only L2, skip pgd + 3*pmd */
+#else
+#define TTBR1_OFFSET   0
+#endif
+
+#define TTBR1_SIZE     (((PAGE_OFFSET >> 30) - 1) << 16)
+
 #endif
index 86b8fe398b9514d89a9032658f6bb3ad221b069e..5689c18c85f5ebafb95a9bb2cc99fda227992976 100644 (file)
@@ -33,7 +33,7 @@
 #define PTRS_PER_PMD           512
 #define PTRS_PER_PGD           4
 
-#define PTE_HWTABLE_PTRS       (PTRS_PER_PTE)
+#define PTE_HWTABLE_PTRS       (0)
 #define PTE_HWTABLE_OFF                (0)
 #define PTE_HWTABLE_SIZE       (PTRS_PER_PTE * sizeof(u64))
 
 #define PMD_SHIFT              21
 
 #define PMD_SIZE               (1UL << PMD_SHIFT)
-#define PMD_MASK               (~(PMD_SIZE-1))
+#define PMD_MASK               (~((1 << PMD_SHIFT) - 1))
 #define PGDIR_SIZE             (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK             (~(PGDIR_SIZE-1))
+#define PGDIR_MASK             (~((1 << PGDIR_SHIFT) - 1))
 
 /*
  * section address mask and size definitions.
  */
 #define SECTION_SHIFT          21
 #define SECTION_SIZE           (1UL << SECTION_SHIFT)
-#define SECTION_MASK           (~(SECTION_SIZE-1))
+#define SECTION_MASK           (~((1 << SECTION_SHIFT) - 1))
 
 #define USER_PTRS_PER_PGD      (PAGE_OFFSET / PGDIR_SIZE)
 
+/*
+ * Hugetlb definitions.
+ */
+#define HPAGE_SHIFT            PMD_SHIFT
+#define HPAGE_SIZE             (_AC(1, UL) << HPAGE_SHIFT)
+#define HPAGE_MASK             (~(HPAGE_SIZE - 1))
+#define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
+
 /*
  * "Linux" PTE definitions for LPAE.
  *
 #define L_PTE_SPECIAL          (_AT(pteval_t, 1) << 56)        /* unused */
 #define L_PTE_NONE             (_AT(pteval_t, 1) << 57)        /* PROT_NONE */
 
+#define PMD_SECT_VALID         (_AT(pmdval_t, 1) << 0)
+#define PMD_SECT_DIRTY         (_AT(pmdval_t, 1) << 55)
+#define PMD_SECT_SPLITTING     (_AT(pmdval_t, 1) << 56)
+#define PMD_SECT_NONE          (_AT(pmdval_t, 1) << 57)
+
 /*
  * To be used in assembly code with the upper page attributes.
  */
@@ -166,8 +179,83 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
                clean_pmd_entry(pmdp);  \
        } while (0)
 
+/*
+ * For 3 levels of paging the PTE_EXT_NG bit will be set for user address ptes
+ * that are written to a page table but not for ptes created with mk_pte.
+ *
+ * In hugetlb_no_page, a new huge pte (new_pte) is generated and passed to
+ * hugetlb_cow, where it is compared with an entry in a page table.
+ * This comparison test fails erroneously leading ultimately to a memory leak.
+ *
+ * To correct this behaviour, we mask off PTE_EXT_NG for any pte that is
+ * present before running the comparison.
+ */
+#define __HAVE_ARCH_PTE_SAME
+#define pte_same(pte_a,pte_b)  ((pte_present(pte_a) ? pte_val(pte_a) & ~PTE_EXT_NG     \
+                                       : pte_val(pte_a))                               \
+                               == (pte_present(pte_b) ? pte_val(pte_b) & ~PTE_EXT_NG   \
+                                       : pte_val(pte_b)))
+
 #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,__pte(pte_val(pte)|(ext)))
 
+#define pte_huge(pte)          (pte_val(pte) && !(pte_val(pte) & PTE_TABLE_BIT))
+#define pte_mkhuge(pte)                (__pte(pte_val(pte) & ~PTE_TABLE_BIT))
+
+#define pmd_young(pmd)         (pmd_val(pmd) & PMD_SECT_AF)
+
+#define __HAVE_ARCH_PMD_WRITE
+#define pmd_write(pmd)         (!(pmd_val(pmd) & PMD_SECT_RDONLY))
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define pmd_trans_huge(pmd)    (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
+#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
+#endif
+
+#define PMD_BIT_FUNC(fn,op) \
+static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
+
+PMD_BIT_FUNC(wrprotect,        |= PMD_SECT_RDONLY);
+PMD_BIT_FUNC(mkold,    &= ~PMD_SECT_AF);
+PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING);
+PMD_BIT_FUNC(mkwrite,   &= ~PMD_SECT_RDONLY);
+PMD_BIT_FUNC(mkdirty,   |= PMD_SECT_DIRTY);
+PMD_BIT_FUNC(mkyoung,   |= PMD_SECT_AF);
+
+#define pmd_mkhuge(pmd)                (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
+
+#define pmd_pfn(pmd)           (((pmd_val(pmd) & PMD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
+#define pfn_pmd(pfn,prot)      (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+#define mk_pmd(page,prot)      pfn_pmd(page_to_pfn(page),prot)
+
+/* represent a notpresent pmd by zero, this is used by pmdp_invalidate */
+#define pmd_mknotpresent(pmd)  (__pmd(0))
+
+static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
+{
+       const pmdval_t mask = PMD_SECT_USER | PMD_SECT_XN | PMD_SECT_RDONLY |
+                               PMD_SECT_VALID | PMD_SECT_NONE;
+       pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask);
+       return pmd;
+}
+
+static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+                             pmd_t *pmdp, pmd_t pmd)
+{
+       BUG_ON(addr >= TASK_SIZE);
+
+       /* create a faulting entry if PROT_NONE protected */
+       if (pmd_val(pmd) & PMD_SECT_NONE)
+               pmd_val(pmd) &= ~PMD_SECT_VALID;
+
+       *pmdp = __pmd(pmd_val(pmd) | PMD_SECT_nG);
+       flush_pmd_entry(pmdp);
+}
+
+static inline int has_transparent_hugepage(void)
+{
+       return 1;
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_PGTABLE_3LEVEL_H */
index 229e0dde9c710d659eec8830fb1457dc53c39ad2..04aeb02d2e116f904e1871e416f433b249ec4086 100644 (file)
@@ -24,6 +24,9 @@
 #include <asm/memory.h>
 #include <asm/pgtable-hwdef.h>
 
+
+#include <asm/tlbflush.h>
+
 #ifdef CONFIG_ARM_LPAE
 #include <asm/pgtable-3level.h>
 #else
index f3628fb3d2b331a9dba24fc29fdb8bf4b3c6b3d1..5324c1112f3aeef9287567e83b012399a1e04fd2 100644 (file)
@@ -60,7 +60,7 @@ extern struct processor {
        /*
         * Set the page table
         */
-       void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm);
+       void (*switch_mm)(phys_addr_t pgd_phys, struct mm_struct *mm);
        /*
         * Set a possibly extended PTE.  Non-extended PTEs should
         * ignore 'ext'.
@@ -82,7 +82,7 @@ extern void cpu_proc_init(void);
 extern void cpu_proc_fin(void);
 extern int cpu_do_idle(void);
 extern void cpu_dcache_clean_area(void *, int);
-extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
+extern void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
 #ifdef CONFIG_ARM_LPAE
 extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte);
 #else
@@ -116,13 +116,25 @@ extern void cpu_resume(void);
 #define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
 
 #ifdef CONFIG_ARM_LPAE
+
+#define cpu_get_ttbr(nr)                                       \
+       ({                                                      \
+               u64 ttbr;                                       \
+               __asm__("mrrc   p15, " #nr ", %Q0, %R0, c2"     \
+                       : "=r" (ttbr));                         \
+               ttbr;                                           \
+       })
+
+#define cpu_set_ttbr(nr, val)                                  \
+       do {                                                    \
+               u64 ttbr = val;                                 \
+               __asm__("mcrr   p15, " #nr ", %Q0, %R0, c2"     \
+                       : : "r" (ttbr));                        \
+       } while (0)
+
 #define cpu_get_pgd()  \
        ({                                              \
-               unsigned long pg, pg2;                  \
-               __asm__("mrrc   p15, 0, %0, %1, c2"     \
-                       : "=r" (pg), "=r" (pg2)         \
-                       :                               \
-                       : "cc");                        \
+               u64 pg = cpu_get_ttbr(0);               \
                pg &= ~(PTRS_PER_PGD*sizeof(pgd_t)-1);  \
                (pgd_t *)phys_to_virt(pg);              \
        })
@@ -137,6 +149,10 @@ extern void cpu_resume(void);
        })
 #endif
 
+#else  /*!CONFIG_MMU */
+
+#define cpu_switch_mm(pgd,mm)  { }
+
 #endif
 
 #endif /* __ASSEMBLY__ */
index d3a22bebe6ce415c952cbb631929aa1a37157ea6..a8cae71caceb3fb89c1ec949063b7a0d621dbdca 100644 (file)
@@ -65,7 +65,10 @@ asmlinkage void secondary_start_kernel(void);
  * Initial data for bringing up a secondary CPU.
  */
 struct secondary_data {
-       unsigned long pgdir;
+       union {
+               unsigned long mpu_rgn_szr;
+               unsigned long pgdir;
+       };
        unsigned long swapper_pg_dir;
        void *stack;
 };
index e789832027374278b7c28cecf0f9562924c6e877..6462a721ebd4cc52105fec3e8f6970614ca1d82e 100644 (file)
@@ -26,6 +26,9 @@ static inline bool is_smp(void)
 }
 
 /* all SMP configurations have the extended CPUID registers */
+#ifndef CONFIG_MMU
+#define tlb_ops_need_broadcast()       0
+#else
 static inline int tlb_ops_need_broadcast(void)
 {
        if (!is_smp())
@@ -33,6 +36,7 @@ static inline int tlb_ops_need_broadcast(void)
 
        return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
 }
+#endif
 
 #if !defined(CONFIG_SMP) || __LINUX_ARM_ARCH__ >= 7
 #define cache_ops_need_broadcast()     0
@@ -66,4 +70,22 @@ static inline int get_logical_index(u32 mpidr)
        return -EINVAL;
 }
 
+/*
+ * NOTE ! Assembly code relies on the following
+ * structure memory layout in order to carry out load
+ * multiple from its base address. For more
+ * information check arch/arm/kernel/sleep.S
+ */
+struct mpidr_hash {
+       u32     mask; /* used by sleep.S */
+       u32     shift_aff[3]; /* used by sleep.S */
+       u32     bits;
+};
+
+extern struct mpidr_hash mpidr_hash;
+
+static inline u32 mpidr_hash_size(void)
+{
+       return 1 << mpidr_hash.bits;
+}
 #endif
index 18d1693736124a75205c765b5e5f588663f3b95f..0393fbab8dd5f1a572d35ccc0531af5449a398c5 100644 (file)
@@ -23,10 +23,21 @@ static inline unsigned long scu_a9_get_base(void)
        return pa;
 }
 
+#ifdef CONFIG_HAVE_ARM_SCU
 unsigned int scu_get_core_count(void __iomem *);
 int scu_power_mode(void __iomem *, unsigned int);
+#else
+static inline unsigned int scu_get_core_count(void __iomem *scu_base)
+{
+       return 0;
+}
+static inline int scu_power_mode(void __iomem *scu_base, unsigned int mode)
+{
+       return -EINVAL;
+}
+#endif
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) && defined(CONFIG_HAVE_ARM_SCU)
 void scu_enable(void __iomem *scu_base);
 #else
 static inline void scu_enable(void __iomem *scu_base) {}
index 6220e9fdf4c7d0917fe50dc54b23f70502ea43a5..f8b8965666e9b14842786742f48ccdef49000802 100644 (file)
@@ -97,19 +97,22 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
 
 static inline int arch_spin_trylock(arch_spinlock_t *lock)
 {
-       unsigned long tmp;
+       unsigned long contended, res;
        u32 slock;
 
-       __asm__ __volatile__(
-"      ldrex   %0, [%2]\n"
-"      subs    %1, %0, %0, ror #16\n"
-"      addeq   %0, %0, %3\n"
-"      strexeq %1, %0, [%2]"
-       : "=&r" (slock), "=&r" (tmp)
-       : "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
-       : "cc");
-
-       if (tmp == 0) {
+       do {
+               __asm__ __volatile__(
+               "       ldrex   %0, [%3]\n"
+               "       mov     %2, #0\n"
+               "       subs    %1, %0, %0, ror #16\n"
+               "       addeq   %0, %0, %4\n"
+               "       strexeq %2, %0, [%3]"
+               : "=&r" (slock), "=&r" (contended), "=r" (res)
+               : "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
+               : "cc");
+       } while (res);
+
+       if (!contended) {
                smp_mb();
                return 1;
        } else {
index 1c0a551ae375490c8f81c589ae92511d509f0bb0..cd20029bcd94796ca0f52485ca85efa643b01641 100644 (file)
@@ -1,6 +1,11 @@
 #ifndef __ASM_ARM_SUSPEND_H
 #define __ASM_ARM_SUSPEND_H
 
+struct sleep_save_sp {
+       u32 *save_ptr_stash;
+       u32 save_ptr_stash_phys;
+};
+
 extern void cpu_resume(void);
 extern int cpu_suspend(unsigned long, int (*)(unsigned long));
 
index 1995d1a840609f3df26114e2ca3eed388a0d5f8e..214d4158089afce9c04102604fe07c5257c454e5 100644 (file)
@@ -58,7 +58,7 @@ struct thread_info {
        struct cpu_context_save cpu_context;    /* cpu context */
        __u32                   syscall;        /* syscall number */
        __u8                    used_cp[16];    /* thread used copro */
-       unsigned long           tp_value;
+       unsigned long           tp_value[2];    /* TLS registers */
 #ifdef CONFIG_CRUNCH
        struct crunch_state     crunchstate;
 #endif
index bdf2b8458ec1d3bb0366ff6ce8aa6623e234aa02..46e7cfb3e7219d2ac4db9013d5dc673c155167ed 100644 (file)
@@ -204,6 +204,12 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
 #endif
 }
 
+static inline void
+tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr)
+{
+       tlb_add_flush(tlb, addr);
+}
+
 #define pte_free_tlb(tlb, ptep, addr)  __pte_free_tlb(tlb, ptep, addr)
 #define pmd_free_tlb(tlb, pmdp, addr)  __pmd_free_tlb(tlb, pmdp, addr)
 #define pud_free_tlb(tlb, pudp, addr)  pud_free((tlb)->mm, pudp)
index a3625d141c1d417389e14a176d175ce359ebf081..fdbb9e369745c4b09d776a4568caa52702b7e9a7 100644 (file)
@@ -535,8 +535,33 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
 }
 #endif
 
+#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
+
 #endif
 
-#endif /* CONFIG_MMU */
+#elif defined(CONFIG_SMP)      /* !CONFIG_MMU */
+
+#ifndef __ASSEMBLY__
+
+#include <linux/mm_types.h>
+
+static inline void local_flush_tlb_all(void)                                                                   { }
+static inline void local_flush_tlb_mm(struct mm_struct *mm)                                                    { }
+static inline void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)                       { }
+static inline void local_flush_tlb_kernel_page(unsigned long kaddr)                                            { }
+static inline void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)   { }
+static inline void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)                                { }
+static inline void local_flush_bp_all(void)                                                                    { }
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
+extern void flush_tlb_kernel_page(unsigned long kaddr);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void flush_bp_all(void);
+#endif /* __ASSEMBLY__ */
+
+#endif
 
 #endif
index 73409e6c0251001b5b03f27ae811a523cc605f62..83259b8733337e05091c82d9705d8e6c224118f4 100644 (file)
@@ -2,27 +2,30 @@
 #define __ASMARM_TLS_H
 
 #ifdef __ASSEMBLY__
-       .macro set_tls_none, tp, tmp1, tmp2
+#include <asm/asm-offsets.h>
+       .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2
        .endm
 
-       .macro set_tls_v6k, tp, tmp1, tmp2
+       .macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2
+       mrc     p15, 0, \tmp2, c13, c0, 2       @ get the user r/w register
        mcr     p15, 0, \tp, c13, c0, 3         @ set TLS register
-       mov     \tmp1, #0
-       mcr     p15, 0, \tmp1, c13, c0, 2       @ clear user r/w TLS register
+       mcr     p15, 0, \tpuser, c13, c0, 2     @ and the user r/w register
+       str     \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
        .endm
 
-       .macro set_tls_v6, tp, tmp1, tmp2
+       .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
        ldr     \tmp1, =elf_hwcap
        ldr     \tmp1, [\tmp1, #0]
        mov     \tmp2, #0xffff0fff
        tst     \tmp1, #HWCAP_TLS               @ hardware TLS available?
-       mcrne   p15, 0, \tp, c13, c0, 3         @ yes, set TLS register
-       movne   \tmp1, #0
-       mcrne   p15, 0, \tmp1, c13, c0, 2       @ clear user r/w TLS register
        streq   \tp, [\tmp2, #-15]              @ set TLS value at 0xffff0ff0
+       mrcne   p15, 0, \tmp2, c13, c0, 2       @ get the user r/w register
+       mcrne   p15, 0, \tp, c13, c0, 3         @ yes, set TLS register
+       mcrne   p15, 0, \tpuser, c13, c0, 2     @ set user r/w register
+       strne   \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
        .endm
 
-       .macro set_tls_software, tp, tmp1, tmp2
+       .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
        mov     \tmp1, #0xffff0fff
        str     \tp, [\tmp1, #-15]              @ set TLS value at 0xffff0ff0
        .endm
 #ifdef CONFIG_TLS_REG_EMUL
 #define tls_emu                1
 #define has_tls_reg            1
-#define set_tls                set_tls_none
+#define switch_tls     switch_tls_none
 #elif defined(CONFIG_CPU_V6)
 #define tls_emu                0
 #define has_tls_reg            (elf_hwcap & HWCAP_TLS)
-#define set_tls                set_tls_v6
+#define switch_tls     switch_tls_v6
 #elif defined(CONFIG_CPU_32v6K)
 #define tls_emu                0
 #define has_tls_reg            1
-#define set_tls                set_tls_v6k
+#define switch_tls     switch_tls_v6k
 #else
 #define tls_emu                0
 #define has_tls_reg            0
-#define set_tls                set_tls_software
+#define switch_tls     switch_tls_software
 #endif
 
+#ifndef __ASSEMBLY__
+static inline unsigned long get_tpuser(void)
+{
+       unsigned long reg = 0;
+
+       if (has_tls_reg && !tls_emu)
+               __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (reg));
+
+       return reg;
+}
+#endif
 #endif /* __ASMARM_TLS_H */
index 30cdacb675af149e41a113450a7b59a3eb5ef0a2..359a7b50b158c4987edf6cc0582174a4cf678473 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _ASM_ARM_XEN_PAGE_H
 #define _ASM_ARM_XEN_PAGE_H
 
-#include <asm/mach/map.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
@@ -88,6 +87,6 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
        return __set_phys_to_machine(pfn, mfn);
 }
 
-#define xen_remap(cookie, size) __arm_ioremap((cookie), (size), MT_MEMORY);
+#define xen_remap(cookie, size) ioremap_cached((cookie), (size));
 
 #endif /* _ASM_ARM_XEN_PAGE_H */
index dc8e882a6257e1e24ef6d20e4752ee3904a6b781..acafb229e2b691d4a4a467a3f0a17aba37c21a5d 100644 (file)
@@ -16,6 +16,8 @@
 #define DEBUG_LL_PHYS_BASE_RS1         0x1c000000
 #define DEBUG_LL_UART_OFFSET_RS1       0x00090000
 
+#define DEBUG_LL_UART_PHYS_CRX         0xb0090000
+
 #define DEBUG_LL_VIRT_BASE             0xf8000000
 
 #if defined(CONFIG_DEBUG_VEXPRESS_UART0_DETECT)
 
 #include <asm/hardware/debug-pl01x.S>
 
+#elif defined(CONFIG_DEBUG_VEXPRESS_UART0_CRX)
+
+               .macro  addruart,rp,tmp,tmp2
+               ldr     \rp, =DEBUG_LL_UART_PHYS_CRX
+               .endm
+
+#include <asm/hardware/debug-pl01x.S>
+
 #else /* CONFIG_DEBUG_LL_UART_NONE */
 
                .macro  addruart, rp, rv, tmp
index 3688fd15a32dd5a5e5f81aef148cf397022fc2d7..6d34d080372abe0fd14769c7c6e7360aece5dfdd 100644 (file)
@@ -25,6 +25,6 @@
 #define HWCAP_IDIVT    (1 << 18)
 #define HWCAP_VFPD32   (1 << 19)       /* set if VFP has 32 regs (not 16) */
 #define HWCAP_IDIV     (HWCAP_IDIVA | HWCAP_IDIVT)
-
+#define HWCAP_LPAE     (1 << 20)
 
 #endif /* _UAPI__ASMARM_HWCAP_H */
index f4285b5ffb05aba08a3e3b87cdae8c0c5e476b26..fccfbdb03df183d840d5a4f1191606df243d05d8 100644 (file)
@@ -38,7 +38,10 @@ obj-$(CONFIG_ARTHUR)         += arthur.o
 obj-$(CONFIG_ISA_DMA)          += dma-isa.o
 obj-$(CONFIG_PCI)              += bios32.o isa.o
 obj-$(CONFIG_ARM_CPU_SUSPEND)  += sleep.o suspend.o
-obj-$(CONFIG_SMP)              += smp.o smp_tlb.o
+obj-$(CONFIG_SMP)              += smp.o
+ifdef CONFIG_MMU
+obj-$(CONFIG_SMP)              += smp_tlb.o
+endif
 obj-$(CONFIG_HAVE_ARM_SCU)     += smp_scu.o
 obj-$(CONFIG_HAVE_ARM_TWD)     += smp_twd.o
 obj-$(CONFIG_ARM_ARCH_TIMER)   += arch_timer.o
index ee68cce6b48e4cfc5a65609b199b55ed6642594d..ded041711beb55fea6b8489996a0ada3e1c8d6c0 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/thread_info.h>
 #include <asm/memory.h>
 #include <asm/procinfo.h>
+#include <asm/suspend.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <linux/kbuild.h>
 
@@ -144,6 +145,11 @@ int main(void)
 #endif
 #ifdef MULTI_CACHE
   DEFINE(CACHE_FLUSH_KERN_ALL, offsetof(struct cpu_cache_fns, flush_kern_all));
+#endif
+#ifdef CONFIG_ARM_CPU_SUSPEND
+  DEFINE(SLEEP_SAVE_SP_SZ,     sizeof(struct sleep_save_sp));
+  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
   BLANK();
   DEFINE(DMA_BIDIRECTIONAL,    DMA_BIDIRECTIONAL);
index 582b405befc527202f69ccbbc349c77d8d06caf8..a39cfc2a1f905f7a4e09d9db8810dcd4ce8ac995 100644 (file)
@@ -685,15 +685,16 @@ ENTRY(__switch_to)
  UNWIND(.fnstart       )
  UNWIND(.cantunwind    )
        add     ip, r1, #TI_CPU_SAVE
-       ldr     r3, [r2, #TI_TP_VALUE]
  ARM(  stmia   ip!, {r4 - sl, fp, sp, lr} )    @ Store most regs on stack
  THUMB(        stmia   ip!, {r4 - sl, fp}         )    @ Store most regs on stack
  THUMB(        str     sp, [ip], #4               )
  THUMB(        str     lr, [ip], #4               )
+       ldr     r4, [r2, #TI_TP_VALUE]
+       ldr     r5, [r2, #TI_TP_VALUE + 4]
 #ifdef CONFIG_CPU_USE_DOMAINS
        ldr     r6, [r2, #TI_CPU_DOMAIN]
 #endif
-       set_tls r3, r4, r5
+       switch_tls r1, r4, r5, r3, r7
 #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
        ldr     r7, [r2, #TI_TASK]
        ldr     r8, =__stack_chk_guard
index 85a72b0809ca11c445352c4f49b54a5b0638ba48..94104bf69719f896e51836ca8a048077086fbb0a 100644 (file)
@@ -366,6 +366,16 @@ ENTRY(vector_swi)
 #endif
        zero_fp
 
+#ifdef CONFIG_ALIGNMENT_TRAP
+       ldr     ip, __cr_alignment
+       ldr     ip, [ip]
+       mcr     p15, 0, ip, c1, c0              @ update control register
+#endif
+
+       enable_irq
+       ct_user_exit
+       get_thread_info tsk
+
        /*
         * Get the system call number.
         */
@@ -379,9 +389,9 @@ ENTRY(vector_swi)
 #ifdef CONFIG_ARM_THUMB
        tst     r8, #PSR_T_BIT
        movne   r10, #0                         @ no thumb OABI emulation
      ldreq   r10, [lr, #-4]                  @ get SWI instruction
USER( ldreq   r10, [lr, #-4]          )       @ get SWI instruction
 #else
      ldr     r10, [lr, #-4]                  @ get SWI instruction
USER( ldr     r10, [lr, #-4]          )       @ get SWI instruction
 #endif
 #ifdef CONFIG_CPU_ENDIAN_BE8
        rev     r10, r10                        @ little endian instruction
@@ -396,22 +406,13 @@ ENTRY(vector_swi)
        /* Legacy ABI only, possibly thumb mode. */
        tst     r8, #PSR_T_BIT                  @ this is SPSR from save_user_regs
        addne   scno, r7, #__NR_SYSCALL_BASE    @ put OS number in
-       ldreq   scno, [lr, #-4]
+ USER( ldreq   scno, [lr, #-4]         )
 
 #else
        /* Legacy ABI only. */
      ldr     scno, [lr, #-4]                 @ get SWI instruction
USER( ldr     scno, [lr, #-4]         )       @ get SWI instruction
 #endif
 
-#ifdef CONFIG_ALIGNMENT_TRAP
-       ldr     ip, __cr_alignment
-       ldr     ip, [ip]
-       mcr     p15, 0, ip, c1, c0              @ update control register
-#endif
-       enable_irq
-       ct_user_exit
-
-       get_thread_info tsk
        adr     tbl, sys_call_table             @ load syscall table pointer
 
 #if defined(CONFIG_OABI_COMPAT)
@@ -446,6 +447,21 @@ local_restart:
        eor     r0, scno, #__NR_SYSCALL_BASE    @ put OS number back
        bcs     arm_syscall     
        b       sys_ni_syscall                  @ not private func
+
+#if defined(CONFIG_OABI_COMPAT) || !defined(CONFIG_AEABI)
+       /*
+        * We failed to handle a fault trying to access the page
+        * containing the swi instruction, but we're not really in a
+        * position to return -EFAULT. Instead, return back to the
+        * instruction and re-enter the user fault handling path trying
+        * to page it in. This will likely result in sending SEGV to the
+        * current task.
+        */
+9001:
+       sub     lr, lr, #4
+       str     lr, [sp, #S_PC]
+       b       ret_fast_syscall
+#endif
 ENDPROC(vector_swi)
 
        /*
index 8812ce88f7a1f289e64e8c787efc5a4db3df0ec9..75f14cc3e07310050cec95feddcfa63f1191fe82 100644 (file)
 #include <asm/assembler.h>
 #include <asm/ptrace.h>
 #include <asm/asm-offsets.h>
+#include <asm/memory.h>
 #include <asm/cp15.h>
 #include <asm/thread_info.h>
 #include <asm/v7m.h>
+#include <asm/mpu.h>
+#include <asm/page.h>
 
 /*
  * Kernel startup entry point.
@@ -63,12 +66,74 @@ ENTRY(stext)
        movs    r10, r5                         @ invalid processor (r5=0)?
        beq     __error_p                               @ yes, error 'p'
 
-       adr     lr, BSYM(__after_proc_init)     @ return (PIC) address
+#ifdef CONFIG_ARM_MPU
+       /* Calculate the size of a region covering just the kernel */
+       ldr     r5, =PHYS_OFFSET                @ Region start: PHYS_OFFSET
+       ldr     r6, =(_end)                     @ Cover whole kernel
+       sub     r6, r6, r5                      @ Minimum size of region to map
+       clz     r6, r6                          @ Region size must be 2^N...
+       rsb     r6, r6, #31                     @ ...so round up region size
+       lsl     r6, r6, #MPU_RSR_SZ             @ Put size in right field
+       orr     r6, r6, #(1 << MPU_RSR_EN)      @ Set region enabled bit
+       bl      __setup_mpu
+#endif
+       ldr     r13, =__mmap_switched           @ address to jump to after
+                                               @ initialising sctlr
+       adr     lr, BSYM(1f)                    @ return (PIC) address
  ARM(  add     pc, r10, #PROCINFO_INITFUNC     )
  THUMB(        add     r12, r10, #PROCINFO_INITFUNC    )
  THUMB(        mov     pc, r12                         )
+ 1:    b       __after_proc_init
 ENDPROC(stext)
 
+#ifdef CONFIG_SMP
+       __CPUINIT
+ENTRY(secondary_startup)
+       /*
+        * Common entry point for secondary CPUs.
+        *
+        * Ensure that we're in SVC mode, and IRQs are disabled.  Lookup
+        * the processor type - there is no need to check the machine type
+        * as it has already been validated by the primary processor.
+        */
+       setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
+#ifndef CONFIG_CPU_CP15
+       ldr     r9, =CONFIG_PROCESSOR_ID
+#else
+       mrc     p15, 0, r9, c0, c0              @ get processor id
+#endif
+       bl      __lookup_processor_type         @ r5=procinfo r9=cpuid
+       movs    r10, r5                         @ invalid processor?
+       beq     __error_p                       @ yes, error 'p'
+
+       adr     r4, __secondary_data
+       ldmia   r4, {r7, r12}
+
+#ifdef CONFIG_ARM_MPU
+       /* Use MPU region info supplied by __cpu_up */
+       ldr     r6, [r7]                        @ get secondary_data.mpu_szr
+       bl      __setup_mpu                     @ Initialize the MPU
+#endif
+
+       adr     lr, BSYM(__after_proc_init)     @ return address
+       mov     r13, r12                        @ __secondary_switched address
+ ARM(  add     pc, r10, #PROCINFO_INITFUNC     )
+ THUMB(        add     r12, r10, #PROCINFO_INITFUNC    )
+ THUMB(        mov     pc, r12                         )
+ENDPROC(secondary_startup)
+
+ENTRY(__secondary_switched)
+       ldr     sp, [r7, #8]                    @ set up the stack pointer
+       mov     fp, #0
+       b       secondary_start_kernel
+ENDPROC(__secondary_switched)
+
+       .type   __secondary_data, %object
+__secondary_data:
+       .long   secondary_data
+       .long   __secondary_switched
+#endif /* CONFIG_SMP */
+
 /*
  * Set the Control Register and Read the process ID.
  */
@@ -99,10 +164,97 @@ __after_proc_init:
 #endif
        mcr     p15, 0, r0, c1, c0, 0           @ write control reg
 #endif /* CONFIG_CPU_CP15 */
-
-       b       __mmap_switched                 @ clear the BSS and jump
-                                               @ to start_kernel
+       mov     pc, r13
 ENDPROC(__after_proc_init)
        .ltorg
 
+#ifdef CONFIG_ARM_MPU
+
+
+/* Set which MPU region should be programmed */
+.macro set_region_nr tmp, rgnr
+       mov     \tmp, \rgnr                     @ Use static region numbers
+       mcr     p15, 0, \tmp, c6, c2, 0         @ Write RGNR
+.endm
+
+/* Setup a single MPU region, either D or I side (D-side for unified) */
+.macro setup_region bar, acr, sr, side = MPU_DATA_SIDE
+       mcr     p15, 0, \bar, c6, c1, (0 + \side)       @ I/DRBAR
+       mcr     p15, 0, \acr, c6, c1, (4 + \side)       @ I/DRACR
+       mcr     p15, 0, \sr, c6, c1, (2 + \side)                @ I/DRSR
+.endm
+
+/*
+ * Setup the MPU and initial MPU Regions. We create the following regions:
+ * Region 0: Use this for probing the MPU details, so leave disabled.
+ * Region 1: Background region - covers the whole of RAM as strongly ordered
+ * Region 2: Normal, Shared, cacheable for RAM. From PHYS_OFFSET, size from r6
+ * Region 3: Normal, shared, inaccessible from PL0 to protect the vectors page
+ *
+ * r6: Value to be written to DRSR (and IRSR if required) for MPU_RAM_REGION
+*/
+
+ENTRY(__setup_mpu)
+
+       /* Probe for v7 PMSA compliance */
+       mrc     p15, 0, r0, c0, c1, 4           @ Read ID_MMFR0
+       and     r0, r0, #(MMFR0_PMSA)           @ PMSA field
+       teq     r0, #(MMFR0_PMSAv7)             @ PMSA v7
+       bne     __error_p                       @ Fail: ARM_MPU on NOT v7 PMSA
+
+       /* Determine whether the D/I-side memory map is unified. We set the
+        * flags here and continue to use them for the rest of this function */
+       mrc     p15, 0, r0, c0, c0, 4           @ MPUIR
+       ands    r5, r0, #MPUIR_DREGION_SZMASK   @ 0 size d region => No MPU
+       beq     __error_p                       @ Fail: ARM_MPU and no MPU
+       tst     r0, #MPUIR_nU                   @ MPUIR_nU = 0 for unified
+
+       /* Setup second region first to free up r6 */
+       set_region_nr r0, #MPU_RAM_REGION
+       isb
+       /* Full access from PL0, PL1, shared for CONFIG_SMP, cacheable */
+       ldr     r0, =PHYS_OFFSET                @ RAM starts at PHYS_OFFSET
+       ldr     r5,=(MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL)
+
+       setup_region r0, r5, r6, MPU_DATA_SIDE  @ PHYS_OFFSET, shared, enabled
+       beq     1f                              @ Memory-map not unified
+       setup_region r0, r5, r6, MPU_INSTR_SIDE @ PHYS_OFFSET, shared, enabled
+1:     isb
+
+       /* First/background region */
+       set_region_nr r0, #MPU_BG_REGION
+       isb
+       /* Execute Never,  strongly ordered, inaccessible to PL0, rw PL1  */
+       mov     r0, #0                          @ BG region starts at 0x0
+       ldr     r5,=(MPU_ACR_XN | MPU_RGN_STRONGLY_ORDERED | MPU_AP_PL1RW_PL0NA)
+       mov     r6, #MPU_RSR_ALL_MEM            @ 4GB region, enabled
+
+       setup_region r0, r5, r6, MPU_DATA_SIDE  @ 0x0, BG region, enabled
+       beq     2f                              @ Memory-map not unified
+       setup_region r0, r5, r6, MPU_INSTR_SIDE @ 0x0, BG region, enabled
+2:     isb
+
+       /* Vectors region */
+       set_region_nr r0, #MPU_VECTORS_REGION
+       isb
+       /* Shared, inaccessible to PL0, rw PL1 */
+       mov     r0, #CONFIG_VECTORS_BASE        @ Cover from VECTORS_BASE
+       ldr     r5,=(MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL)
+       /* Writing N to bits 5:1 (RSR_SZ) --> region size 2^N+1 */
+       mov     r6, #(((PAGE_SHIFT - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN)
+
+       setup_region r0, r5, r6, MPU_DATA_SIDE  @ VECTORS_BASE, PL0 NA, enabled
+       beq     3f                              @ Memory-map not unified
+       setup_region r0, r5, r6, MPU_INSTR_SIDE @ VECTORS_BASE, PL0 NA, enabled
+3:     isb
+
+       /* Enable the MPU */
+       mrc     p15, 0, r0, c1, c0, 0           @ Read SCTLR
+       bic     r0, r0, #CR_BR                  @ Disable the 'default mem-map'
+       orr     r0, r0, #CR_M                   @ Set SCTRL.M (MPU on)
+       mcr     p15, 0, r0, c1, c0, 0           @ Enable MPU
+       isb
+       mov pc,lr
+ENDPROC(__setup_mpu)
+#endif
 #include "head-common.S"
index 8bac553fe213def562dec9e30cad88c827d6239c..45e8935cae4e44198ca4d197a66f219b7e7b8105 100644 (file)
@@ -156,7 +156,7 @@ ENDPROC(stext)
  *
  * Returns:
  *  r0, r3, r5-r7 corrupted
- *  r4 = physical page table address
+ *  r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
  */
 __create_page_tables:
        pgtbl   r4, r8                          @ page table address
@@ -331,6 +331,7 @@ __create_page_tables:
 #endif
 #ifdef CONFIG_ARM_LPAE
        sub     r4, r4, #0x1000         @ point to the PGD table
+       mov     r4, r4, lsr #ARCH_PGD_SHIFT
 #endif
        mov     pc, lr
 ENDPROC(__create_page_tables)
@@ -408,7 +409,7 @@ __secondary_data:
  *  r0  = cp#15 control register
  *  r1  = machine ID
  *  r2  = atags or dtb pointer
- *  r4  = page table pointer
+ *  r4  = page table (see ARCH_PGD_SHIFT in asm/memory.h)
  *  r9  = processor ID
  *  r13 = *virtual* address to jump to upon completion
  */
@@ -427,10 +428,7 @@ __enable_mmu:
 #ifdef CONFIG_CPU_ICACHE_DISABLE
        bic     r0, r0, #CR_I
 #endif
-#ifdef CONFIG_ARM_LPAE
-       mov     r5, #0
-       mcrr    p15, 0, r4, r5, c2              @ load TTBR0
-#else
+#ifndef CONFIG_ARM_LPAE
        mov     r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
                      domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
                      domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
index 1315c4ccfa563a04928347ec560ed618dcd3f958..4910232c48330d4dc857d6bf32754bfd781008b5 100644 (file)
@@ -153,6 +153,13 @@ THUMB(     orr     r7, #(1 << 30)  )       @ HSCTLR.TE
        mrc     p15, 4, r7, c14, c1, 0  @ CNTHCTL
        orr     r7, r7, #3              @ PL1PCEN | PL1PCTEN
        mcr     p15, 4, r7, c14, c1, 0  @ CNTHCTL
+       mov     r7, #0
+       mcrr    p15, 4, r7, r7, c14     @ CNTVOFF
+
+       @ Disable virtual timer in case it was counting
+       mrc     p15, 0, r7, c14, c3, 1  @ CNTV_CTL
+       bic     r7, #1                  @ Clear ENABLE
+       mcr     p15, 0, r7, c14, c3, 1  @ CNTV_CTL
 1:
 #endif
 
index 8c3094d0f7b78426e367e2cf3ed538e54d686cbd..d9f5cd4e533fef948f68510e3a6fb3b4996b750b 100644 (file)
@@ -569,6 +569,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
                return;
        }
 
+       perf_callchain_store(entry, regs->ARM_pc);
        tail = (struct frame_tail __user *)regs->ARM_fp - 1;
 
        while ((entry->nr < PERF_MAX_STACK_DEPTH) &&
index 6e8931ccf13ed048f0b93880476a3911b3a9b587..7f1efcd4a6e90ff0350abdfa6f492e60cfbbd028 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/thread_notify.h>
 #include <asm/stacktrace.h>
 #include <asm/mach/time.h>
+#include <asm/tls.h>
 
 #ifdef CONFIG_CC_STACKPROTECTOR
 #include <linux/stackprotector.h>
@@ -374,7 +375,8 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
        clear_ptrace_hw_breakpoint(p);
 
        if (clone_flags & CLONE_SETTLS)
-               thread->tp_value = childregs->ARM_r3;
+               thread->tp_value[0] = childregs->ARM_r3;
+       thread->tp_value[1] = get_tpuser();
 
        thread_notify(THREAD_NOTIFY_COPY, thread);
 
index 23a11424c568c4bd11968cee55fbe7700977e273..219f1d73572a588d431dca2e0bb7f7b598ea9899 100644 (file)
@@ -68,8 +68,6 @@ void __ref psci_cpu_die(unsigned int cpu)
        /* We should never return */
        panic("psci: cpu %d failed to shutdown\n", cpu);
 }
-#else
-#define psci_cpu_die NULL
 #endif
 
 bool __init psci_smp_available(void)
@@ -80,5 +78,7 @@ bool __init psci_smp_available(void)
 
 struct smp_operations __initdata psci_smp_ops = {
        .smp_boot_secondary     = psci_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
        .cpu_die                = psci_cpu_die,
+#endif
 };
index 03deeffd9f6d06e6ff380126592e10dbf7bf1a25..2bc1514d6dbe84955d0d070db1ae2ac6e65a5fbd 100644 (file)
@@ -849,7 +849,7 @@ long arch_ptrace(struct task_struct *child, long request,
 #endif
 
                case PTRACE_GET_THREAD_AREA:
-                       ret = put_user(task_thread_info(child)->tp_value,
+                       ret = put_user(task_thread_info(child)->tp_value[0],
                                       datap);
                        break;
 
index 1c8278de6c46c65e76d72962c76031d5457ea1bf..9b653278c9e8932c354e31383cb995ebf594789e 100644 (file)
@@ -367,7 +367,7 @@ void __init early_print(const char *str, ...)
 
 static void __init cpuid_init_hwcaps(void)
 {
-       unsigned int divide_instrs;
+       unsigned int divide_instrs, vmsa;
 
        if (cpu_architecture() < CPU_ARCH_ARMv7)
                return;
@@ -380,6 +380,11 @@ static void __init cpuid_init_hwcaps(void)
        case 1:
                elf_hwcap |= HWCAP_IDIVT;
        }
+
+       /* LPAE implies atomic ldrd/strd instructions */
+       vmsa = (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xf) >> 0;
+       if (vmsa >= 5)
+               elf_hwcap |= HWCAP_LPAE;
 }
 
 static void __init feat_v6_fixup(void)
@@ -470,9 +475,82 @@ void __init smp_setup_processor_id(void)
        for (i = 1; i < nr_cpu_ids; ++i)
                cpu_logical_map(i) = i == cpu ? 0 : i;
 
+       /*
+        * clear __my_cpu_offset on boot CPU to avoid hang caused by
+        * using percpu variable early, for example, lockdep will
+        * access percpu variable inside lock_release
+        */
+       set_my_cpu_offset(0);
+
        printk(KERN_INFO "Booting Linux on physical CPU 0x%x\n", mpidr);
 }
 
+struct mpidr_hash mpidr_hash;
+#ifdef CONFIG_SMP
+/**
+ * smp_build_mpidr_hash - Pre-compute shifts required at each affinity
+ *                       level in order to build a linear index from an
+ *                       MPIDR value. Resulting algorithm is a collision
+ *                       free hash carried out through shifting and ORing
+ */
+static void __init smp_build_mpidr_hash(void)
+{
+       u32 i, affinity;
+       u32 fs[3], bits[3], ls, mask = 0;
+       /*
+        * Pre-scan the list of MPIDRS and filter out bits that do
+        * not contribute to affinity levels, ie they never toggle.
+        */
+       for_each_possible_cpu(i)
+               mask |= (cpu_logical_map(i) ^ cpu_logical_map(0));
+       pr_debug("mask of set bits 0x%x\n", mask);
+       /*
+        * Find and stash the last and first bit set at all affinity levels to
+        * check how many bits are required to represent them.
+        */
+       for (i = 0; i < 3; i++) {
+               affinity = MPIDR_AFFINITY_LEVEL(mask, i);
+               /*
+                * Find the MSB bit and LSB bits position
+                * to determine how many bits are required
+                * to express the affinity level.
+                */
+               ls = fls(affinity);
+               fs[i] = affinity ? ffs(affinity) - 1 : 0;
+               bits[i] = ls - fs[i];
+       }
+       /*
+        * An index can be created from the MPIDR by isolating the
+        * significant bits at each affinity level and by shifting
+        * them in order to compress the 24 bits values space to a
+        * compressed set of values. This is equivalent to hashing
+        * the MPIDR through shifting and ORing. It is a collision free
+        * hash though not minimal since some levels might contain a number
+        * of CPUs that is not an exact power of 2 and their bit
+        * representation might contain holes, eg MPIDR[7:0] = {0x2, 0x80}.
+        */
+       mpidr_hash.shift_aff[0] = fs[0];
+       mpidr_hash.shift_aff[1] = MPIDR_LEVEL_BITS + fs[1] - bits[0];
+       mpidr_hash.shift_aff[2] = 2*MPIDR_LEVEL_BITS + fs[2] -
+                                               (bits[1] + bits[0]);
+       mpidr_hash.mask = mask;
+       mpidr_hash.bits = bits[2] + bits[1] + bits[0];
+       pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] mask[0x%x] bits[%u]\n",
+                               mpidr_hash.shift_aff[0],
+                               mpidr_hash.shift_aff[1],
+                               mpidr_hash.shift_aff[2],
+                               mpidr_hash.mask,
+                               mpidr_hash.bits);
+       /*
+        * 4x is an arbitrary value used to warn on a hash table much bigger
+        * than expected on most systems.
+        */
+       if (mpidr_hash_size() > 4 * num_possible_cpus())
+               pr_warn("Large number of MPIDR hash buckets detected\n");
+       sync_cache_w(&mpidr_hash);
+}
+#endif
+
 static void __init setup_processor(void)
 {
        struct proc_info_list *list;
@@ -820,6 +898,7 @@ void __init setup_arch(char **cmdline_p)
                                smp_set_ops(mdesc->smp);
                }
                smp_init_cpus();
+               smp_build_mpidr_hash();
        }
 #endif
 
@@ -892,6 +971,7 @@ static const char *hwcap_str[] = {
        "vfpv4",
        "idiva",
        "idivt",
+       "lpae",
        NULL
 };
 
index 296786bdbb737870d8fa99479127f9bc5bd8c271..1c16c35c271af5a3cb4de53736344a9ed286d7d9 100644 (file)
@@ -392,14 +392,19 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
                if (ksig->ka.sa.sa_flags & SA_SIGINFO)
                        idx += 3;
 
+               /*
+                * Put the sigreturn code on the stack no matter which return
+                * mechanism we use in order to remain ABI compliant
+                */
                if (__put_user(sigreturn_codes[idx],   rc) ||
                    __put_user(sigreturn_codes[idx+1], rc+1))
                        return 1;
 
-               if (cpsr & MODE32_BIT) {
+               if ((cpsr & MODE32_BIT) && !IS_ENABLED(CONFIG_ARM_MPU)) {
                        /*
                         * 32-bit code can use the new high-page
-                        * signal return code support.
+                        * signal return code support except when the MPU has
+                        * protected the vectors page from PL0
                         */
                        retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
                } else {
index 987dcf33415c420f70dc08852da45bd654a21ea2..db1536b8b30b497fe11923dfe9f67a72f86f7954 100644 (file)
@@ -6,6 +6,49 @@
 #include <asm/glue-proc.h>
        .text
 
+/*
+ * Implementation of MPIDR hash algorithm through shifting
+ * and OR'ing.
+ *
+ * @dst: register containing hash result
+ * @rs0: register containing affinity level 0 bit shift
+ * @rs1: register containing affinity level 1 bit shift
+ * @rs2: register containing affinity level 2 bit shift
+ * @mpidr: register containing MPIDR value
+ * @mask: register containing MPIDR mask
+ *
+ * Pseudo C-code:
+ *
+ *u32 dst;
+ *
+ *compute_mpidr_hash(u32 rs0, u32 rs1, u32 rs2, u32 mpidr, u32 mask) {
+ *     u32 aff0, aff1, aff2;
+ *     u32 mpidr_masked = mpidr & mask;
+ *     aff0 = mpidr_masked & 0xff;
+ *     aff1 = mpidr_masked & 0xff00;
+ *     aff2 = mpidr_masked & 0xff0000;
+ *     dst = (aff0 >> rs0 | aff1 >> rs1 | aff2 >> rs2);
+ *}
+ * Input registers: rs0, rs1, rs2, mpidr, mask
+ * Output register: dst
+ * Note: input and output registers must be disjoint register sets
+         (eg: a macro instance with mpidr = r1 and dst = r1 is invalid)
+ */
+       .macro compute_mpidr_hash dst, rs0, rs1, rs2, mpidr, mask
+       and     \mpidr, \mpidr, \mask                   @ mask out MPIDR bits
+       and     \dst, \mpidr, #0xff                     @ mask=aff0
+ ARM(  mov     \dst, \dst, lsr \rs0            )       @ dst=aff0>>rs0
+ THUMB(        lsr     \dst, \dst, \rs0                )
+       and     \mask, \mpidr, #0xff00                  @ mask = aff1
+ ARM(  orr     \dst, \dst, \mask, lsr \rs1     )       @ dst|=(aff1>>rs1)
+ THUMB(        lsr     \mask, \mask, \rs1              )
+ THUMB(        orr     \dst, \dst, \mask               )
+       and     \mask, \mpidr, #0xff0000                @ mask = aff2
+ ARM(  orr     \dst, \dst, \mask, lsr \rs2     )       @ dst|=(aff2>>rs2)
+ THUMB(        lsr     \mask, \mask, \rs2              )
+ THUMB(        orr     \dst, \dst, \mask               )
+       .endm
+
 /*
  * Save CPU state for a suspend.  This saves the CPU general purpose
  * registers, and allocates space on the kernel stack to save the CPU
@@ -29,12 +72,18 @@ ENTRY(__cpu_suspend)
        mov     r1, r4                  @ size of save block
        mov     r2, r5                  @ virtual SP
        ldr     r3, =sleep_save_sp
-#ifdef CONFIG_SMP
-       ALT_SMP(mrc p15, 0, lr, c0, c0, 5)
-       ALT_UP(mov lr, #0)
-       and     lr, lr, #15
+       ldr     r3, [r3, #SLEEP_SAVE_SP_VIRT]
+       ALT_SMP(mrc p15, 0, r9, c0, c0, 5)
+        ALT_UP_B(1f)
+       ldr     r8, =mpidr_hash
+       /*
+        * This ldmia relies on the memory layout of the mpidr_hash
+        * struct mpidr_hash.
+        */
+       ldmia   r8, {r4-r7}     @ r4 = mpidr mask (r5,r6,r7) = l[0,1,2] shifts
+       compute_mpidr_hash      lr, r5, r6, r7, r9, r4
        add     r3, r3, lr, lsl #2
-#endif
+1:
        bl      __cpu_suspend_save
        adr     lr, BSYM(cpu_suspend_abort)
        ldmfd   sp!, {r0, pc}           @ call suspend fn
@@ -81,15 +130,23 @@ ENDPROC(cpu_resume_after_mmu)
        .data
        .align
 ENTRY(cpu_resume)
-#ifdef CONFIG_SMP
-       adr     r0, sleep_save_sp
-       ALT_SMP(mrc p15, 0, r1, c0, c0, 5)
-       ALT_UP(mov r1, #0)
-       and     r1, r1, #15
-       ldr     r0, [r0, r1, lsl #2]    @ stack phys addr
-#else
-       ldr     r0, sleep_save_sp       @ stack phys addr
-#endif
+       mov     r1, #0
+       ALT_SMP(mrc p15, 0, r0, c0, c0, 5)
+       ALT_UP_B(1f)
+       adr     r2, mpidr_hash_ptr
+       ldr     r3, [r2]
+       add     r2, r2, r3              @ r2 = struct mpidr_hash phys address
+       /*
+        * This ldmia relies on the memory layout of the mpidr_hash
+        * struct mpidr_hash.
+        */
+       ldmia   r2, { r3-r6 }   @ r3 = mpidr mask (r4,r5,r6) = l[0,1,2] shifts
+       compute_mpidr_hash      r1, r4, r5, r6, r0, r3
+1:
+       adr     r0, _sleep_save_sp
+       ldr     r0, [r0, #SLEEP_SAVE_SP_PHYS]
+       ldr     r0, [r0, r1, lsl #2]
+
        setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1  @ set SVC, irqs off
        @ load phys pgd, stack, resume fn
   ARM( ldmia   r0!, {r1, sp, pc}       )
@@ -98,7 +155,11 @@ THUMB(      mov     sp, r2                  )
 THUMB( bx      r3                      )
 ENDPROC(cpu_resume)
 
-sleep_save_sp:
-       .rept   CONFIG_NR_CPUS
-       .long   0                               @ preserve stack phys ptr here
-       .endr
+       .align 2
+mpidr_hash_ptr:
+       .long   mpidr_hash - .                  @ mpidr_hash struct offset
+
+       .type   sleep_save_sp, #object
+ENTRY(sleep_save_sp)
+_sleep_save_sp:
+       .space  SLEEP_SAVE_SP_SZ                @ struct sleep_save_sp
index 5919eb451bb9840590091c3d26a922bd65b1d005..c5fb5469054bddea98b9ba9647f7ed75929481aa 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/smp_plat.h>
 #include <asm/virt.h>
 #include <asm/mach/arch.h>
+#include <asm/mpu.h>
 
 /*
  * as from 2.5, kernels no longer have an init_tasks structure
@@ -78,6 +79,13 @@ void __init smp_set_ops(struct smp_operations *ops)
                smp_ops = *ops;
 };
 
+static unsigned long get_arch_pgd(pgd_t *pgd)
+{
+       phys_addr_t pgdir = virt_to_phys(pgd);
+       BUG_ON(pgdir & ARCH_PGD_MASK);
+       return pgdir >> ARCH_PGD_SHIFT;
+}
+
 int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
 {
        int ret;
@@ -87,8 +95,14 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
         * its stack and the page tables.
         */
        secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
-       secondary_data.pgdir = virt_to_phys(idmap_pgd);
-       secondary_data.swapper_pg_dir = virt_to_phys(swapper_pg_dir);
+#ifdef CONFIG_ARM_MPU
+       secondary_data.mpu_rgn_szr = mpu_rgn_info.rgns[MPU_RAM_REGION].drsr;
+#endif
+
+#ifdef CONFIG_MMU
+       secondary_data.pgdir = get_arch_pgd(idmap_pgd);
+       secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
+#endif
        __cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data));
        outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1));
 
@@ -112,9 +126,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
                pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
        }
 
-       secondary_data.stack = NULL;
-       secondary_data.pgdir = 0;
 
+       memset(&secondary_data, 0, sizeof(secondary_data));
        return ret;
 }
 
index 9a52a07aa40ee3c017c55b5b5cce3b92ae7c599c..a98b62dca2faf9bbce7fbcb786d4c325513f7231 100644 (file)
@@ -103,7 +103,7 @@ static void broadcast_tlb_a15_erratum(void)
 
 static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)
 {
-       int cpu, this_cpu;
+       int this_cpu;
        cpumask_t mask = { CPU_BITS_NONE };
 
        if (!erratum_a15_798181())
@@ -111,21 +111,7 @@ static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)
 
        dummy_flush_tlb_a15_erratum();
        this_cpu = get_cpu();
-       for_each_online_cpu(cpu) {
-               if (cpu == this_cpu)
-                       continue;
-               /*
-                * We only need to send an IPI if the other CPUs are running
-                * the same ASID as the one being invalidated. There is no
-                * need for locking around the active_asids check since the
-                * switch_mm() function has at least one dmb() (as required by
-                * this workaround) in case a context switch happens on
-                * another CPU after the condition below.
-                */
-               if (atomic64_read(&mm->context.id) ==
-                   atomic64_read(&per_cpu(active_asids, cpu)))
-                       cpumask_set_cpu(cpu, &mask);
-       }
+       a15_erratum_get_cpumask(this_cpu, mm, &mask);
        smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1);
        put_cpu();
 }
index c59c97ea8268b461b45b8d46066b2f4208f9afe5..41cf3cbf756de473be3bb1ebb268445aeacadc5d 100644 (file)
@@ -1,15 +1,54 @@
 #include <linux/init.h>
+#include <linux/slab.h>
 
+#include <asm/cacheflush.h>
 #include <asm/idmap.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/memory.h>
+#include <asm/smp_plat.h>
 #include <asm/suspend.h>
 #include <asm/tlbflush.h>
 
 extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
 extern void cpu_resume_mmu(void);
 
+#ifdef CONFIG_MMU
+/*
+ * Hide the first two arguments to __cpu_suspend - these are an implementation
+ * detail which platform code shouldn't have to know about.
+ */
+int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
+{
+       struct mm_struct *mm = current->active_mm;
+       int ret;
+
+       if (!idmap_pgd)
+               return -EINVAL;
+
+       /*
+        * Provide a temporary page table with an identity mapping for
+        * the MMU-enable code, required for resuming.  On successful
+        * resume (indicated by a zero return code), we need to switch
+        * back to the correct page tables.
+        */
+       ret = __cpu_suspend(arg, fn);
+       if (ret == 0) {
+               cpu_switch_mm(mm->pgd, mm);
+               local_flush_bp_all();
+               local_flush_tlb_all();
+       }
+
+       return ret;
+}
+#else
+int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
+{
+       return __cpu_suspend(arg, fn);
+}
+#define        idmap_pgd       NULL
+#endif
+
 /*
  * This is called by __cpu_suspend() to save the state, and do whatever
  * flushing is required to ensure that when the CPU goes to sleep we have
@@ -47,30 +86,19 @@ void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
                          virt_to_phys(save_ptr) + sizeof(*save_ptr));
 }
 
-/*
- * Hide the first two arguments to __cpu_suspend - these are an implementation
- * detail which platform code shouldn't have to know about.
- */
-int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
-{
-       struct mm_struct *mm = current->active_mm;
-       int ret;
-
-       if (!idmap_pgd)
-               return -EINVAL;
+extern struct sleep_save_sp sleep_save_sp;
 
-       /*
-        * Provide a temporary page table with an identity mapping for
-        * the MMU-enable code, required for resuming.  On successful
-        * resume (indicated by a zero return code), we need to switch
-        * back to the correct page tables.
-        */
-       ret = __cpu_suspend(arg, fn);
-       if (ret == 0) {
-               cpu_switch_mm(mm->pgd, mm);
-               local_flush_bp_all();
-               local_flush_tlb_all();
-       }
+static int cpu_suspend_alloc_sp(void)
+{
+       void *ctx_ptr;
+       /* ctx_ptr is an array of physical addresses */
+       ctx_ptr = kcalloc(mpidr_hash_size(), sizeof(u32), GFP_KERNEL);
 
-       return ret;
+       if (WARN_ON(!ctx_ptr))
+               return -ENOMEM;
+       sleep_save_sp.save_ptr_stash = ctx_ptr;
+       sleep_save_sp.save_ptr_stash_phys = virt_to_phys(ctx_ptr);
+       sync_cache_w(&sleep_save_sp);
+       return 0;
 }
+early_initcall(cpu_suspend_alloc_sp);
index 486e12a0f26a1bc2a7a7339e3a507a9708f64dc1..cab094c234ee85d646b9534d2044010c10c727ee 100644 (file)
@@ -581,7 +581,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
                return regs->ARM_r0;
 
        case NR(set_tls):
-               thread->tp_value = regs->ARM_r0;
+               thread->tp_value[0] = regs->ARM_r0;
                if (tls_emu)
                        return 0;
                if (has_tls_reg) {
@@ -699,7 +699,7 @@ static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
        int reg = (instr >> 12) & 15;
        if (reg == 15)
                return 1;
-       regs->uregs[reg] = current_thread_info()->tp_value;
+       regs->uregs[reg] = current_thread_info()->tp_value[0];
        regs->ARM_pc += 4;
        return 0;
 }
index 370e1a8af6ac0663974b2fdc186dd05c7f3b996a..ebf5015508b525c052ddfed5c4ea2ea0a0ed969e 100644 (file)
@@ -41,9 +41,9 @@ config KVM_ARM_HOST
          Provides host support for ARM processors.
 
 config KVM_ARM_MAX_VCPUS
-       int "Number maximum supported virtual CPUs per VM" if KVM_ARM_HOST
-       default 4 if KVM_ARM_HOST
-       default 0
+       int "Number maximum supported virtual CPUs per VM"
+       depends on KVM_ARM_HOST
+       default 4
        help
          Static number of max supported virtual CPUs per VM.
 
@@ -67,6 +67,4 @@ config KVM_ARM_TIMER
        ---help---
          Adds support for the Architected Timers in virtual machines
 
-source drivers/virtio/Kconfig
-
 endif # VIRTUALIZATION
index 53c5ed83d16fc47455073d96355e3ac787ee5190..d99bee4950e50a6c26e428acc710448fba1a726f 100644 (file)
@@ -14,10 +14,11 @@ CFLAGS_mmu.o := -I.
 AFLAGS_init.o := -Wa,-march=armv7-a$(plus_virt)
 AFLAGS_interrupts.o := -Wa,-march=armv7-a$(plus_virt)
 
-kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
+KVM := ../../../virt/kvm
+kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o
 
 obj-y += kvm-arm.o init.o interrupts.o
 obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
 obj-y += coproc.o coproc_a15.o mmio.o psci.o perf.o
-obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o
-obj-$(CONFIG_KVM_ARM_TIMER) += arch_timer.o
+obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
+obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
index ef1703b9587b0264c5b7ea8ebb246376dfe76326..741f66a2edbd77bf3ddce5a53c6cb760e491c7fe 100644 (file)
@@ -800,8 +800,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
 
 static void cpu_init_hyp_mode(void *dummy)
 {
-       unsigned long long boot_pgd_ptr;
-       unsigned long long pgd_ptr;
+       phys_addr_t boot_pgd_ptr;
+       phys_addr_t pgd_ptr;
        unsigned long hyp_stack_ptr;
        unsigned long stack_page;
        unsigned long vector_ptr;
@@ -809,8 +809,8 @@ static void cpu_init_hyp_mode(void *dummy)
        /* Switch from the HYP stub to our own HYP init vector */
        __hyp_set_vectors(kvm_get_idmap_vector());
 
-       boot_pgd_ptr = (unsigned long long)kvm_mmu_get_boot_httbr();
-       pgd_ptr = (unsigned long long)kvm_mmu_get_httbr();
+       boot_pgd_ptr = kvm_mmu_get_boot_httbr();
+       pgd_ptr = kvm_mmu_get_httbr();
        stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
        hyp_stack_ptr = stack_page + PAGE_SIZE;
        vector_ptr = (unsigned long)__kvm_hyp_vector;
index 8eea97be1ed52e8ea42d463f166fdc3e69261682..4a5199070430672728c91dfe610047e83b78a964 100644 (file)
@@ -180,6 +180,10 @@ static const struct coproc_reg cp15_regs[] = {
                        NULL, reset_unknown, c6_DFAR },
        { CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32,
                        NULL, reset_unknown, c6_IFAR },
+
+       /* PAR swapped by interrupt.S */
+       { CRn( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
+
        /*
         * DC{C,I,CI}SW operations:
         */
index 3d74a0be47dbfd81bf3950ba4bad75ed1b1b0f76..df4c82d47ad7101cf2f87028d39471cd6d63d7df 100644 (file)
@@ -52,9 +52,6 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-       if (kvm_psci_call(vcpu))
-               return 1;
-
        kvm_inject_undefined(vcpu);
        return 1;
 }
index f7793df62f5834ab60abb19528d2e31f9a756a11..16cd4ba5d7fd6d0ff0781da759712167cbc17508 100644 (file)
@@ -49,6 +49,7 @@ __kvm_hyp_code_start:
 ENTRY(__kvm_tlb_flush_vmid_ipa)
        push    {r2, r3}
 
+       dsb     ishst
        add     r0, r0, #KVM_VTTBR
        ldrd    r2, r3, [r0]
        mcrr    p15, 6, r2, r3, c2      @ Write VTTBR
@@ -291,6 +292,7 @@ THUMB(      orr     r2, r2, #PSR_T_BIT      )
        ldr     r2, =BSYM(panic)
        msr     ELR_hyp, r2
        ldr     r0, =\panic_str
+       clrex                           @ Clear exclusive monitor
        eret
 .endm
 
@@ -414,6 +416,10 @@ guest_trap:
        mrcne   p15, 4, r2, c6, c0, 4   @ HPFAR
        bne     3f
 
+       /* Preserve PAR */
+       mrrc    p15, 0, r0, r1, c7      @ PAR
+       push    {r0, r1}
+
        /* Resolve IPA using the xFAR */
        mcr     p15, 0, r2, c7, c8, 0   @ ATS1CPR
        isb
@@ -424,13 +430,20 @@ guest_trap:
        lsl     r2, r2, #4
        orr     r2, r2, r1, lsl #24
 
+       /* Restore PAR */
+       pop     {r0, r1}
+       mcrr    p15, 0, r0, r1, c7      @ PAR
+
 3:     load_vcpu                       @ Load VCPU pointer to r0
        str     r2, [r0, #VCPU_HPFAR]
 
 1:     mov     r1, #ARM_EXCEPTION_HVC
        b       __kvm_vcpu_return
 
-4:     pop     {r0, r1, r2}            @ Failed translation, return to guest
+4:     pop     {r0, r1}                @ Failed translation, return to guest
+       mcrr    p15, 0, r0, r1, c7      @ PAR
+       clrex
+       pop     {r0, r1, r2}
        eret
 
 /*
@@ -456,6 +469,7 @@ switch_to_guest_vfp:
 
        pop     {r3-r7}
        pop     {r0-r2}
+       clrex
        eret
 #endif
 
index 3c8f2f0b4c5e105c765b281241415066ce1470d2..6f18695a09cb5b50d8d849c9f2b486e8a01529c9 100644 (file)
@@ -302,11 +302,14 @@ vcpu      .req    r0              @ vcpu pointer always in r0
        .endif
 
        mrc     p15, 0, r2, c14, c1, 0  @ CNTKCTL
+       mrrc    p15, 0, r4, r5, c7      @ PAR
 
        .if \store_to_vcpu == 0
-       push    {r2}
+       push    {r2,r4-r5}
        .else
        str     r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
+       add     r12, vcpu, #CP15_OFFSET(c7_PAR)
+       strd    r4, r5, [r12]
        .endif
 .endm
 
@@ -319,12 +322,15 @@ vcpu      .req    r0              @ vcpu pointer always in r0
  */
 .macro write_cp15_state read_from_vcpu
        .if \read_from_vcpu == 0
-       pop     {r2}
+       pop     {r2,r4-r5}
        .else
        ldr     r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
+       add     r12, vcpu, #CP15_OFFSET(c7_PAR)
+       ldrd    r4, r5, [r12]
        .endif
 
        mcr     p15, 0, r2, c14, c1, 0  @ CNTKCTL
+       mcrr    p15, 0, r4, r5, c7      @ PAR
 
        .if \read_from_vcpu == 0
        pop     {r2-r12}
@@ -497,6 +503,10 @@ vcpu       .req    r0              @ vcpu pointer always in r0
        add     r5, vcpu, r4
        strd    r2, r3, [r5]
 
+       @ Ensure host CNTVCT == CNTPCT
+       mov     r2, #0
+       mcrr    p15, 4, r2, r2, c14     @ CNTVOFF
+
 1:
 #endif
        @ Allow physical timer/counter access for the host
index 72a12f2171b26bba2937e3c288f4bd51f1b5540b..b8e06b7a28331ede0a01ce6aefcb60d7be343f6e 100644 (file)
@@ -86,12 +86,6 @@ static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
        sign_extend = kvm_vcpu_dabt_issext(vcpu);
        rt = kvm_vcpu_dabt_get_rd(vcpu);
 
-       if (kvm_vcpu_reg_is_pc(vcpu, rt)) {
-               /* IO memory trying to read/write pc */
-               kvm_inject_pabt(vcpu, kvm_vcpu_get_hfar(vcpu));
-               return 1;
-       }
-
        mmio->is_write = is_write;
        mmio->phys_addr = fault_ipa;
        mmio->len = len;
index 84ba67b982c0d32546dae5092ec84ac1d620756b..ca6bea4859b48c35e9c34d970fb02580840e23b4 100644 (file)
@@ -382,9 +382,6 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
        if (!pgd)
                return -ENOMEM;
 
-       /* stage-2 pgd must be aligned to its size */
-       VM_BUG_ON((unsigned long)pgd & (S2_PGD_SIZE - 1));
-
        memset(pgd, 0, PTRS_PER_S2_PGD * sizeof(pgd_t));
        kvm_clean_pgd(pgd);
        kvm->arch.pgd = pgd;
index 7ee5bb7a3667d8227a2d87b3e62239a4854cd933..86a693a02ba3a78e4288b94c63f3b1fba77a6b38 100644 (file)
@@ -75,7 +75,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
  * kvm_psci_call - handle PSCI call if r0 value is in range
  * @vcpu: Pointer to the VCPU struct
  *
- * Handle PSCI calls from guests through traps from HVC or SMC instructions.
+ * Handle PSCI calls from guests through traps from HVC instructions.
  * The calling convention is similar to SMC calls to the secure world where
  * the function number is placed in r0 and this function returns true if the
  * function number specified in r0 is withing the PSCI range, and false
index b80256b554cd428d1c4f8e83e453fd33b6a1edcc..b7840e7aa4529ac73e34c29e26c0002ef033306d 100644 (file)
@@ -27,6 +27,8 @@
 #include <asm/kvm_arm.h>
 #include <asm/kvm_coproc.h>
 
+#include <kvm/arm_arch_timer.h>
+
 /******************************************************************************
  * Cortex-A15 Reset Values
  */
@@ -37,6 +39,11 @@ static struct kvm_regs a15_regs_reset = {
        .usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT,
 };
 
+static const struct kvm_irq_level a15_vtimer_irq = {
+       .irq = 27,
+       .level = 1,
+};
+
 
 /*******************************************************************************
  * Exported reset function
@@ -52,6 +59,7 @@ static struct kvm_regs a15_regs_reset = {
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 {
        struct kvm_regs *cpu_reset;
+       const struct kvm_irq_level *cpu_vtimer_irq;
 
        switch (vcpu->arch.target) {
        case KVM_ARM_TARGET_CORTEX_A15:
@@ -59,6 +67,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
                        return -EINVAL;
                cpu_reset = &a15_regs_reset;
                vcpu->arch.midr = read_cpuid_id();
+               cpu_vtimer_irq = &a15_vtimer_irq;
                break;
        default:
                return -ENODEV;
@@ -70,5 +79,8 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
        /* Reset CP15 registers */
        kvm_reset_coprocs(vcpu);
 
+       /* Reset arch_timer context */
+       kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
+
        return 0;
 }
index a075b3e0c5c7a5229aa87163e732d9c6b49a7a50..e026b19b23eaf1d8546f4996a387c13e1b8ed670 100644 (file)
@@ -40,6 +40,7 @@ config ARCH_DAVINCI_DA850
        bool "DA850/OMAP-L138/AM18x based system"
        select ARCH_DAVINCI_DA8XX
        select ARCH_HAS_CPUFREQ
+       select CPU_FREQ_TABLE
        select CP_INTC
 
 config ARCH_DAVINCI_DA8XX
index 4d6933848abfaeaab005ed972916fb0cfb69b5da..a0d4f6038b608f187eedc4a0cf89b0b97ce6a49c 100644 (file)
@@ -1004,7 +1004,7 @@ static const struct da850_opp da850_opp_96 = {
 
 #define OPP(freq)              \
        {                               \
-               .index = (unsigned int) &da850_opp_##freq,      \
+               .driver_data = (unsigned int) &da850_opp_##freq,        \
                .frequency = freq * 1000, \
        }
 
@@ -1016,7 +1016,7 @@ static struct cpufreq_frequency_table da850_freq_table[] = {
        OPP(200),
        OPP(96),
        {
-               .index          = 0,
+               .driver_data            = 0,
                .frequency      = CPUFREQ_TABLE_END,
        },
 };
@@ -1044,7 +1044,7 @@ static int da850_set_voltage(unsigned int index)
        if (!cvdd)
                return -ENODEV;
 
-       opp = (struct da850_opp *) cpufreq_info.freq_table[index].index;
+       opp = (struct da850_opp *) cpufreq_info.freq_table[index].driver_data;
 
        return regulator_set_voltage(cvdd, opp->cvdd_min, opp->cvdd_max);
 }
@@ -1125,7 +1125,7 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index)
        struct pll_data *pll = clk->pll_data;
        int ret;
 
-       opp = (struct da850_opp *) cpufreq_info.freq_table[index].index;
+       opp = (struct da850_opp *) cpufreq_info.freq_table[index].driver_data;
        prediv = opp->prediv;
        mult = opp->mult;
        postdiv = opp->postdiv;
index b13cc74114db5543ab59dfcd77fb11f64c7c8fd7..8a53f346cdb3f72dbb8314255ab2b2450b7ce177 100644 (file)
@@ -116,7 +116,7 @@ static void __init ebsa110_map_io(void)
        iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc));
 }
 
-static void __iomem *ebsa110_ioremap_caller(unsigned long cookie, size_t size,
+static void __iomem *ebsa110_ioremap_caller(phys_addr_t cookie, size_t size,
                                            unsigned int flags, void *caller)
 {
        return (void __iomem *)cookie;
index ba70a846d1c6dcaceeccf1b5cef2861f1a1fabad..855d4a7b462d12fd0fc67b4abd3a55b0b0522530 100644 (file)
@@ -93,7 +93,7 @@ config SOC_EXYNOS5440
        default y
        depends on ARCH_EXYNOS5
        select ARCH_HAS_OPP
-       select ARM_ARCH_TIMER
+       select HAVE_ARM_ARCH_TIMER
        select AUTO_ZRELADDR
        select MIGHT_HAVE_PCI
        select PCI_DOMAINS if PCI
index dae4cd7be0400eda33f01d62574951d5d90989c4..6f424eced1816914bf59e39e48608b50bb338fe5 100644 (file)
@@ -268,10 +268,11 @@ static struct mc13xxx_led_platform_data moboard_led[] = {
 static struct mc13xxx_leds_platform_data moboard_leds = {
        .num_leds = ARRAY_SIZE(moboard_led),
        .led = moboard_led,
-       .flags = MC13783_LED_SLEWLIMTC,
-       .abmode = MC13783_LED_AB_DISABLED,
-       .tc1_period = MC13783_LED_PERIOD_10MS,
-       .tc2_period = MC13783_LED_PERIOD_10MS,
+       .led_control[0] = MC13783_LED_C0_ENABLE | MC13783_LED_C0_ABMODE(0),
+       .led_control[1] = MC13783_LED_C1_SLEWLIM,
+       .led_control[2] = MC13783_LED_C2_SLEWLIM,
+       .led_control[3] = MC13783_LED_C3_PERIOD(0),
+       .led_control[4] = MC13783_LED_C3_PERIOD(0),
 };
 
 static struct mc13xxx_buttons_platform_data moboard_buttons = {
index 8f0f60697f557eb511a22ecf926dbd8487c738ba..0884ca90d15a309eab1a33af6cfc68c95db82b75 100644 (file)
@@ -65,7 +65,7 @@ static void imx3_idle(void)
                : "=r" (reg));
 }
 
-static void __iomem *imx3_ioremap_caller(unsigned long phys_addr, size_t size,
+static void __iomem *imx3_ioremap_caller(phys_addr_t phys_addr, size_t size,
                                         unsigned int mtype, void *caller)
 {
        if (mtype == MT_DEVICE) {
index 183dc8b5511bac36d83a78a3159ca1223192a7ea..faaf7d4482c5d93d58fb72cbcd1a086825117186 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "pci.h"
 
-static void __iomem *__iop13xx_ioremap_caller(unsigned long cookie,
+static void __iomem *__iop13xx_ioremap_caller(phys_addr_t cookie,
        size_t size, unsigned int mtype, void *caller)
 {
        void __iomem * retval;
index 3181f61ea63e5e9bc5297624f85a3bce8c38ff73..1c5bd7637b054008381adbc2109840c3c25d0d78 100644 (file)
@@ -469,7 +469,6 @@ void __init iop13xx_platform_init(void)
                        dma_cap_set(DMA_MEMCPY, plat_data->cap_mask);
                        dma_cap_set(DMA_XOR, plat_data->cap_mask);
                        dma_cap_set(DMA_XOR_VAL, plat_data->cap_mask);
-                       dma_cap_set(DMA_MEMSET, plat_data->cap_mask);
                        dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask);
                        break;
                case IOP13XX_INIT_ADMA_1:
@@ -479,7 +478,6 @@ void __init iop13xx_platform_init(void)
                        dma_cap_set(DMA_MEMCPY, plat_data->cap_mask);
                        dma_cap_set(DMA_XOR, plat_data->cap_mask);
                        dma_cap_set(DMA_XOR_VAL, plat_data->cap_mask);
-                       dma_cap_set(DMA_MEMSET, plat_data->cap_mask);
                        dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask);
                        break;
                case IOP13XX_INIT_ADMA_2:
@@ -489,7 +487,6 @@ void __init iop13xx_platform_init(void)
                        dma_cap_set(DMA_MEMCPY, plat_data->cap_mask);
                        dma_cap_set(DMA_XOR, plat_data->cap_mask);
                        dma_cap_set(DMA_XOR_VAL, plat_data->cap_mask);
-                       dma_cap_set(DMA_MEMSET, plat_data->cap_mask);
                        dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask);
                        dma_cap_set(DMA_PQ, plat_data->cap_mask);
                        dma_cap_set(DMA_PQ_VAL, plat_data->cap_mask);
index 6600cff6bd922b88984e549fce3d2c406c4939a2..d7223b3b81f3c9d3575c1d72d59cad7851dfed20 100644 (file)
@@ -559,7 +559,7 @@ void ixp4xx_restart(char mode, const char *cmd)
  * fallback to the default.
  */
 
-static void __iomem *ixp4xx_ioremap_caller(unsigned long addr, size_t size,
+static void __iomem *ixp4xx_ioremap_caller(phys_addr_t addr, size_t size,
                                           unsigned int mtype, void *caller)
 {
        if (!is_pci_memory(addr))
index ce8215a269e50a10d8fb81090edc34cee16dd492..421cf7751a803162a6d6a1c37dda3bb95ccbd681 100644 (file)
@@ -23,7 +23,7 @@ extern void msm_map_msm8x60_io(void);
 extern void msm_map_msm8960_io(void);
 extern void msm_map_qsd8x50_io(void);
 
-extern void __iomem *__msm_ioremap_caller(unsigned long phys_addr, size_t size,
+extern void __iomem *__msm_ioremap_caller(phys_addr_t phys_addr, size_t size,
                                          unsigned int mtype, void *caller);
 
 extern struct smp_operations msm_smp_ops;
index efa113e4de86ff47b05739cb09b138dd5fec1ff9..3dc04ccaf59f15973f5719e491fd3b4a4aa96539 100644 (file)
@@ -168,7 +168,7 @@ void __init msm_map_msm7x30_io(void)
 }
 #endif /* CONFIG_ARCH_MSM7X30 */
 
-void __iomem *__msm_ioremap_caller(unsigned long phys_addr, size_t size,
+void __iomem *__msm_ioremap_caller(phys_addr_t phys_addr, size_t size,
                                   unsigned int mtype, void *caller)
 {
        if (mtype == MT_DEVICE) {
index 58152b15ecaa59acd526e41a5a8185d425813279..627fa7e41fbabbeccf38c1703dc26ed2a98d66db 100644 (file)
@@ -62,6 +62,7 @@ config SOC_OMAP5
        select HAVE_SMP
        select COMMON_CLK
        select HAVE_ARM_ARCH_TIMER
+       select ARM_ERRATA_798181
 
 config SOC_AM33XX
        bool "AM33XX support"
index ea5a27ff994106244c0d121bfde68bbb16f37ca6..d4f671547c3756cb5d134aada03d0d2471ffa23b 100644 (file)
@@ -95,10 +95,6 @@ obj-$(CONFIG_POWER_AVS_OMAP_CLASS3)    += smartreflex-class3.o
 AFLAGS_sleep24xx.o                     :=-Wa,-march=armv6
 AFLAGS_sleep34xx.o                     :=-Wa,-march=armv7-a$(plus_sec)
 
-ifeq ($(CONFIG_PM_VERBOSE),y)
-CFLAGS_pm_bus.o                                += -DDEBUG
-endif
-
 endif
 
 ifeq ($(CONFIG_CPU_IDLE),y)
index b54562d1235e5bd0a5f89659e724e50387ae8dfb..87e65dde8e133a47baaebf7313767810c786a4d6 100644 (file)
@@ -553,6 +553,37 @@ static struct usbhs_omap_platform_data igep3_usbhs_bdata __initdata = {
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+       /* Display Sub System */
+       OMAP3_MUX(DSS_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_HSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_VSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_ACBIAS, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA8, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA9, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA10, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA11, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA12, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA13, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA14, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA15, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA16, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA17, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA18, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA19, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA20, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA21, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA22, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       OMAP3_MUX(DSS_DATA23, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+       /* TFP410 PanelBus DVI Transmitte (GPIO_170) */
+       OMAP3_MUX(HDQ_SIO, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
        /* SMSC9221 LAN Controller ETH IRQ (GPIO_176) */
        OMAP3_MUX(MCSPI1_CS2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
        { .reg_offset = OMAP_MUX_TERMINATOR },
index bd74f9f6063b243f523dc288d9aa3d8c1e71362f..bdd1e3a179e1cb32fe3d5aba17a09d37d2704d91 100644 (file)
@@ -61,7 +61,7 @@ static struct omap_dss_board_info rx51_dss_board_info = {
 
 static int __init rx51_video_init(void)
 {
-       if (!machine_is_nokia_rx51())
+       if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
                return 0;
 
        if (omap_mux_init_gpio(RX51_LCD_RESET_GPIO, OMAP_PIN_OUTPUT)) {
index aef96e45cb2049c2cebba2ad50e1e8a0a8036225..3c1279f27d1fe4436595e94fb4977707a5f5fadb 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/pinctrl/machine.h>
@@ -66,7 +65,7 @@ static int __init omap3_l3_init(void)
 
        WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
 
-       return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
+       return PTR_RET(pdev);
 }
 omap_postcore_initcall(omap3_l3_init);
 
@@ -100,7 +99,7 @@ static int __init omap4_l3_init(void)
 
        WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
 
-       return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
+       return PTR_RET(pdev);
 }
 omap_postcore_initcall(omap4_l3_init);
 
index 190ae493c6efe97bf2465b93245df54106cdd02b..2ca33cc0c484055a7c4f6543b9c2a1e35adeef87 100644 (file)
@@ -83,10 +83,7 @@ static int __init omap_init_vrfb(void)
        pdev = platform_device_register_resndata(NULL, "omapvrfb", -1,
                        res, num_res, NULL, 0);
 
-       if (IS_ERR(pdev))
-               return PTR_ERR(pdev);
-       else
-               return 0;
+       return PTR_RET(pdev);
 }
 
 omap_arch_initcall(omap_init_vrfb);
index 1c7969e965d75685ca8cd0bba8c06feba47b51ab..f3fdd6afa2137c8bb85e088d40e1e6217bf6334d 100644 (file)
@@ -1734,7 +1734,7 @@ static int __init omap_gpmc_init(void)
        pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0);
        WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
 
-       return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
+       return PTR_RET(pdev);
 }
 omap_postcore_initcall(omap_gpmc_init);
 
index 68be532f8688c30e857cc4463c414ab4ffc18c9c..5cc92874be7e6f22d81767c0f75e141376ab83d6 100644 (file)
@@ -588,11 +588,6 @@ static int _od_runtime_suspend(struct device *dev)
        return ret;
 }
 
-static int _od_runtime_idle(struct device *dev)
-{
-       return pm_generic_runtime_idle(dev);
-}
-
 static int _od_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -648,7 +643,7 @@ static int _od_resume_noirq(struct device *dev)
 struct dev_pm_domain omap_device_pm_domain = {
        .ops = {
                SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
-                                  _od_runtime_idle)
+                                  NULL)
                USE_PLATFORM_PM_SLEEP_OPS
                .suspend_noirq = _od_suspend_noirq,
                .resume_noirq = _od_resume_noirq,
index 9ace8eae7ee8b1444aa9b0634764d2ad93871ecb..33c8846b419358693c634cca1c6b860f99c8fa6f 100644 (file)
@@ -54,10 +54,7 @@ static int __init omap2_init_pmu(unsigned oh_num, char *oh_names[])
        WARN(IS_ERR(omap_pmu_dev), "Can't build omap_device for %s.\n",
             dev_name);
 
-       if (IS_ERR(omap_pmu_dev))
-               return PTR_ERR(omap_pmu_dev);
-
-       return 0;
+       return PTR_RET(omap_pmu_dev);
 }
 
 static int __init omap_init_pmu(void)
index 88ff83a0942eb742382ae6c1eec4e4d49951ff11..9086ce03ae12a00fa500553b80f68902c0fc852a 100644 (file)
@@ -34,6 +34,8 @@ ppa_zero_params:
 ppa_por_params:
        .word           1, 0
 
+#ifdef CONFIG_ARCH_OMAP4
+
 /*
  * =============================
  * == CPU suspend finisher ==
@@ -326,7 +328,9 @@ skip_l2en:
 
        b       cpu_resume                      @ Jump to generic resume
 ENDPROC(omap4_cpu_resume)
-#endif
+#endif /* CONFIG_ARCH_OMAP4 */
+
+#endif /* defined(CONFIG_SMP) && defined(CONFIG_PM) */
 
 #ifndef CONFIG_OMAP4_ERRATA_I688
 ENTRY(omap_bus_sync)
index aee3c8940a30ca19f6d7819b2cc654481bbd1fd5..7a42e1960c3b5fe4aed135fa17d7717e735e044d 100644 (file)
@@ -26,14 +26,14 @@ static int sr_class3_enable(struct omap_sr *sr)
        }
 
        omap_vp_enable(sr->voltdm);
-       return sr_enable(sr->voltdm, volt);
+       return sr_enable(sr, volt);
 }
 
 static int sr_class3_disable(struct omap_sr *sr, int is_volt_reset)
 {
-       sr_disable_errgen(sr->voltdm);
+       sr_disable_errgen(sr);
        omap_vp_disable(sr->voltdm);
-       sr_disable(sr->voltdm);
+       sr_disable(sr);
        if (is_volt_reset)
                voltdm_reset(sr->voltdm);
 
@@ -42,7 +42,7 @@ static int sr_class3_disable(struct omap_sr *sr, int is_volt_reset)
 
 static int sr_class3_configure(struct omap_sr *sr)
 {
-       return sr_configure_errgen(sr->voltdm);
+       return sr_configure_errgen(sr);
 }
 
 /* SR class3 structure */
index 3bdb0fb020285d8a2b603a4771c7eea60d69baa9..5f148e721790ccc41b9fc939fafc1bbcae8ca367 100644 (file)
@@ -220,7 +220,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
                                         int posted)
 {
        char name[10]; /* 10 = sizeof("gptXX_Xck0") */
-       const char *oh_name;
+       const char *oh_name = NULL;
        struct device_node *np;
        struct omap_hwmod *oh;
        struct resource irq, mem;
index 96100dbf5a2e8353e9fad34ded41ec5e83dda7ad..a8427115ee07b9a986d62dceac6006f8c9cecafd 100644 (file)
@@ -615,12 +615,14 @@ endmenu
 config PXA25x
        bool
        select CPU_XSCALE
+       select CPU_FREQ_TABLE if CPU_FREQ
        help
          Select code specific to PXA21x/25x/26x variants
 
 config PXA27x
        bool
        select CPU_XSCALE
+       select CPU_FREQ_TABLE if CPU_FREQ
        help
          Select code specific to PXA27x variants
 
@@ -633,6 +635,7 @@ config CPU_PXA26x
 config PXA3xx
        bool
        select CPU_XSC3
+       select CPU_FREQ_TABLE if CPU_FREQ
        help
          Select code specific to PXA3xx variants
 
index ddd8280e3875792abd0899048201e9ead6010567..2a0aa5684e725fbd13973e407c1722571f1a4357 100644 (file)
@@ -60,5 +60,5 @@ void s3c2410_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg)
  */
 void s3c2410_set_fvco(struct s3c_cpufreq_config *cfg)
 {
-       __raw_writel(cfg->pll.index, S3C2410_MPLLCON);
+       __raw_writel(cfg->pll.driver_data, S3C2410_MPLLCON);
 }
index dcf3420a3271b2a9a6e9f750c69c685c8811cf68..5e37d368594b6ac0e5a459cf80c5bd0f7ac4d77b 100644 (file)
 #include <plat/cpu-freq-core.h>
 
 static struct cpufreq_frequency_table pll_vals_12MHz[] = {
-    { .frequency = 34000000,  .index = PLLVAL(82, 2, 3),   },
-    { .frequency = 45000000,  .index = PLLVAL(82, 1, 3),   },
-    { .frequency = 51000000,  .index = PLLVAL(161, 3, 3),  },
-    { .frequency = 48000000,  .index = PLLVAL(120, 2, 3),  },
-    { .frequency = 56000000,  .index = PLLVAL(142, 2, 3),  },
-    { .frequency = 68000000,  .index = PLLVAL(82, 2, 2),   },
-    { .frequency = 79000000,  .index = PLLVAL(71, 1, 2),   },
-    { .frequency = 85000000,  .index = PLLVAL(105, 2, 2),  },
-    { .frequency = 90000000,  .index = PLLVAL(112, 2, 2),  },
-    { .frequency = 101000000, .index = PLLVAL(127, 2, 2),  },
-    { .frequency = 113000000, .index = PLLVAL(105, 1, 2),  },
-    { .frequency = 118000000, .index = PLLVAL(150, 2, 2),  },
-    { .frequency = 124000000, .index = PLLVAL(116, 1, 2),  },
-    { .frequency = 135000000, .index = PLLVAL(82, 2, 1),   },
-    { .frequency = 147000000, .index = PLLVAL(90, 2, 1),   },
-    { .frequency = 152000000, .index = PLLVAL(68, 1, 1),   },
-    { .frequency = 158000000, .index = PLLVAL(71, 1, 1),   },
-    { .frequency = 170000000, .index = PLLVAL(77, 1, 1),   },
-    { .frequency = 180000000, .index = PLLVAL(82, 1, 1),   },
-    { .frequency = 186000000, .index = PLLVAL(85, 1, 1),   },
-    { .frequency = 192000000, .index = PLLVAL(88, 1, 1),   },
-    { .frequency = 203000000, .index = PLLVAL(161, 3, 1),  },
+    { .frequency = 34000000,  .driver_data = PLLVAL(82, 2, 3),   },
+    { .frequency = 45000000,  .driver_data = PLLVAL(82, 1, 3),   },
+    { .frequency = 51000000,  .driver_data = PLLVAL(161, 3, 3),  },
+    { .frequency = 48000000,  .driver_data = PLLVAL(120, 2, 3),  },
+    { .frequency = 56000000,  .driver_data = PLLVAL(142, 2, 3),  },
+    { .frequency = 68000000,  .driver_data = PLLVAL(82, 2, 2),   },
+    { .frequency = 79000000,  .driver_data = PLLVAL(71, 1, 2),   },
+    { .frequency = 85000000,  .driver_data = PLLVAL(105, 2, 2),  },
+    { .frequency = 90000000,  .driver_data = PLLVAL(112, 2, 2),  },
+    { .frequency = 101000000, .driver_data = PLLVAL(127, 2, 2),  },
+    { .frequency = 113000000, .driver_data = PLLVAL(105, 1, 2),  },
+    { .frequency = 118000000, .driver_data = PLLVAL(150, 2, 2),  },
+    { .frequency = 124000000, .driver_data = PLLVAL(116, 1, 2),  },
+    { .frequency = 135000000, .driver_data = PLLVAL(82, 2, 1),   },
+    { .frequency = 147000000, .driver_data = PLLVAL(90, 2, 1),   },
+    { .frequency = 152000000, .driver_data = PLLVAL(68, 1, 1),   },
+    { .frequency = 158000000, .driver_data = PLLVAL(71, 1, 1),   },
+    { .frequency = 170000000, .driver_data = PLLVAL(77, 1, 1),   },
+    { .frequency = 180000000, .driver_data = PLLVAL(82, 1, 1),   },
+    { .frequency = 186000000, .driver_data = PLLVAL(85, 1, 1),   },
+    { .frequency = 192000000, .driver_data = PLLVAL(88, 1, 1),   },
+    { .frequency = 203000000, .driver_data = PLLVAL(161, 3, 1),  },
 
     /* 2410A extras */
 
-    { .frequency = 210000000, .index = PLLVAL(132, 2, 1),  },
-    { .frequency = 226000000, .index = PLLVAL(105, 1, 1),  },
-    { .frequency = 266000000, .index = PLLVAL(125, 1, 1),  },
-    { .frequency = 268000000, .index = PLLVAL(126, 1, 1),  },
-    { .frequency = 270000000, .index = PLLVAL(127, 1, 1),  },
+    { .frequency = 210000000, .driver_data = PLLVAL(132, 2, 1),  },
+    { .frequency = 226000000, .driver_data = PLLVAL(105, 1, 1),  },
+    { .frequency = 266000000, .driver_data = PLLVAL(125, 1, 1),  },
+    { .frequency = 268000000, .driver_data = PLLVAL(126, 1, 1),  },
+    { .frequency = 270000000, .driver_data = PLLVAL(127, 1, 1),  },
 };
 
 static int s3c2410_plls_add(struct device *dev, struct subsys_interface *sif)
index 67378175831943ad4f8a45053674a79c40d75968..a19460e6e7b0ec9317e8db98ed9aea2cf6290421 100644 (file)
 #include <plat/cpu-freq-core.h>
 
 static struct cpufreq_frequency_table s3c2440_plls_12[] __initdata = {
-       { .frequency = 75000000,        .index = PLLVAL(0x75, 3, 3),  },        /* FVco 600.000000 */
-       { .frequency = 80000000,        .index = PLLVAL(0x98, 4, 3),  },        /* FVco 640.000000 */
-       { .frequency = 90000000,        .index = PLLVAL(0x70, 2, 3),  },        /* FVco 720.000000 */
-       { .frequency = 100000000,       .index = PLLVAL(0x5c, 1, 3),  },        /* FVco 800.000000 */
-       { .frequency = 110000000,       .index = PLLVAL(0x66, 1, 3),  },        /* FVco 880.000000 */
-       { .frequency = 120000000,       .index = PLLVAL(0x70, 1, 3),  },        /* FVco 960.000000 */
-       { .frequency = 150000000,       .index = PLLVAL(0x75, 3, 2),  },        /* FVco 600.000000 */
-       { .frequency = 160000000,       .index = PLLVAL(0x98, 4, 2),  },        /* FVco 640.000000 */
-       { .frequency = 170000000,       .index = PLLVAL(0x4d, 1, 2),  },        /* FVco 680.000000 */
-       { .frequency = 180000000,       .index = PLLVAL(0x70, 2, 2),  },        /* FVco 720.000000 */
-       { .frequency = 190000000,       .index = PLLVAL(0x57, 1, 2),  },        /* FVco 760.000000 */
-       { .frequency = 200000000,       .index = PLLVAL(0x5c, 1, 2),  },        /* FVco 800.000000 */
-       { .frequency = 210000000,       .index = PLLVAL(0x84, 2, 2),  },        /* FVco 840.000000 */
-       { .frequency = 220000000,       .index = PLLVAL(0x66, 1, 2),  },        /* FVco 880.000000 */
-       { .frequency = 230000000,       .index = PLLVAL(0x6b, 1, 2),  },        /* FVco 920.000000 */
-       { .frequency = 240000000,       .index = PLLVAL(0x70, 1, 2),  },        /* FVco 960.000000 */
-       { .frequency = 300000000,       .index = PLLVAL(0x75, 3, 1),  },        /* FVco 600.000000 */
-       { .frequency = 310000000,       .index = PLLVAL(0x93, 4, 1),  },        /* FVco 620.000000 */
-       { .frequency = 320000000,       .index = PLLVAL(0x98, 4, 1),  },        /* FVco 640.000000 */
-       { .frequency = 330000000,       .index = PLLVAL(0x66, 2, 1),  },        /* FVco 660.000000 */
-       { .frequency = 340000000,       .index = PLLVAL(0x4d, 1, 1),  },        /* FVco 680.000000 */
-       { .frequency = 350000000,       .index = PLLVAL(0xa7, 4, 1),  },        /* FVco 700.000000 */
-       { .frequency = 360000000,       .index = PLLVAL(0x70, 2, 1),  },        /* FVco 720.000000 */
-       { .frequency = 370000000,       .index = PLLVAL(0xb1, 4, 1),  },        /* FVco 740.000000 */
-       { .frequency = 380000000,       .index = PLLVAL(0x57, 1, 1),  },        /* FVco 760.000000 */
-       { .frequency = 390000000,       .index = PLLVAL(0x7a, 2, 1),  },        /* FVco 780.000000 */
-       { .frequency = 400000000,       .index = PLLVAL(0x5c, 1, 1),  },        /* FVco 800.000000 */
+       { .frequency = 75000000,        .driver_data = PLLVAL(0x75, 3, 3),  },  /* FVco 600.000000 */
+       { .frequency = 80000000,        .driver_data = PLLVAL(0x98, 4, 3),  },  /* FVco 640.000000 */
+       { .frequency = 90000000,        .driver_data = PLLVAL(0x70, 2, 3),  },  /* FVco 720.000000 */
+       { .frequency = 100000000,       .driver_data = PLLVAL(0x5c, 1, 3),  },  /* FVco 800.000000 */
+       { .frequency = 110000000,       .driver_data = PLLVAL(0x66, 1, 3),  },  /* FVco 880.000000 */
+       { .frequency = 120000000,       .driver_data = PLLVAL(0x70, 1, 3),  },  /* FVco 960.000000 */
+       { .frequency = 150000000,       .driver_data = PLLVAL(0x75, 3, 2),  },  /* FVco 600.000000 */
+       { .frequency = 160000000,       .driver_data = PLLVAL(0x98, 4, 2),  },  /* FVco 640.000000 */
+       { .frequency = 170000000,       .driver_data = PLLVAL(0x4d, 1, 2),  },  /* FVco 680.000000 */
+       { .frequency = 180000000,       .driver_data = PLLVAL(0x70, 2, 2),  },  /* FVco 720.000000 */
+       { .frequency = 190000000,       .driver_data = PLLVAL(0x57, 1, 2),  },  /* FVco 760.000000 */
+       { .frequency = 200000000,       .driver_data = PLLVAL(0x5c, 1, 2),  },  /* FVco 800.000000 */
+       { .frequency = 210000000,       .driver_data = PLLVAL(0x84, 2, 2),  },  /* FVco 840.000000 */
+       { .frequency = 220000000,       .driver_data = PLLVAL(0x66, 1, 2),  },  /* FVco 880.000000 */
+       { .frequency = 230000000,       .driver_data = PLLVAL(0x6b, 1, 2),  },  /* FVco 920.000000 */
+       { .frequency = 240000000,       .driver_data = PLLVAL(0x70, 1, 2),  },  /* FVco 960.000000 */
+       { .frequency = 300000000,       .driver_data = PLLVAL(0x75, 3, 1),  },  /* FVco 600.000000 */
+       { .frequency = 310000000,       .driver_data = PLLVAL(0x93, 4, 1),  },  /* FVco 620.000000 */
+       { .frequency = 320000000,       .driver_data = PLLVAL(0x98, 4, 1),  },  /* FVco 640.000000 */
+       { .frequency = 330000000,       .driver_data = PLLVAL(0x66, 2, 1),  },  /* FVco 660.000000 */
+       { .frequency = 340000000,       .driver_data = PLLVAL(0x4d, 1, 1),  },  /* FVco 680.000000 */
+       { .frequency = 350000000,       .driver_data = PLLVAL(0xa7, 4, 1),  },  /* FVco 700.000000 */
+       { .frequency = 360000000,       .driver_data = PLLVAL(0x70, 2, 1),  },  /* FVco 720.000000 */
+       { .frequency = 370000000,       .driver_data = PLLVAL(0xb1, 4, 1),  },  /* FVco 740.000000 */
+       { .frequency = 380000000,       .driver_data = PLLVAL(0x57, 1, 1),  },  /* FVco 760.000000 */
+       { .frequency = 390000000,       .driver_data = PLLVAL(0x7a, 2, 1),  },  /* FVco 780.000000 */
+       { .frequency = 400000000,       .driver_data = PLLVAL(0x5c, 1, 1),  },  /* FVco 800.000000 */
 };
 
 static int s3c2440_plls12_add(struct device *dev, struct subsys_interface *sif)
index debfa106289bb1f1df3a9e44db8929202f9258c5..1191b29056252e49eee5cc041e0757247dab1bdf 100644 (file)
 #include <plat/cpu-freq-core.h>
 
 static struct cpufreq_frequency_table s3c2440_plls_169344[] __initdata = {
-       { .frequency = 78019200,        .index = PLLVAL(121, 5, 3),     },      /* FVco 624.153600 */
-       { .frequency = 84067200,        .index = PLLVAL(131, 5, 3),     },      /* FVco 672.537600 */
-       { .frequency = 90115200,        .index = PLLVAL(141, 5, 3),     },      /* FVco 720.921600 */
-       { .frequency = 96163200,        .index = PLLVAL(151, 5, 3),     },      /* FVco 769.305600 */
-       { .frequency = 102135600,       .index = PLLVAL(185, 6, 3),     },      /* FVco 817.084800 */
-       { .frequency = 108259200,       .index = PLLVAL(171, 5, 3),     },      /* FVco 866.073600 */
-       { .frequency = 114307200,       .index = PLLVAL(127, 3, 3),     },      /* FVco 914.457600 */
-       { .frequency = 120234240,       .index = PLLVAL(134, 3, 3),     },      /* FVco 961.873920 */
-       { .frequency = 126161280,       .index = PLLVAL(141, 3, 3),     },      /* FVco 1009.290240 */
-       { .frequency = 132088320,       .index = PLLVAL(148, 3, 3),     },      /* FVco 1056.706560 */
-       { .frequency = 138015360,       .index = PLLVAL(155, 3, 3),     },      /* FVco 1104.122880 */
-       { .frequency = 144789120,       .index = PLLVAL(163, 3, 3),     },      /* FVco 1158.312960 */
-       { .frequency = 150100363,       .index = PLLVAL(187, 9, 2),     },      /* FVco 600.401454 */
-       { .frequency = 156038400,       .index = PLLVAL(121, 5, 2),     },      /* FVco 624.153600 */
-       { .frequency = 162086400,       .index = PLLVAL(126, 5, 2),     },      /* FVco 648.345600 */
-       { .frequency = 168134400,       .index = PLLVAL(131, 5, 2),     },      /* FVco 672.537600 */
-       { .frequency = 174048000,       .index = PLLVAL(177, 7, 2),     },      /* FVco 696.192000 */
-       { .frequency = 180230400,       .index = PLLVAL(141, 5, 2),     },      /* FVco 720.921600 */
-       { .frequency = 186278400,       .index = PLLVAL(124, 4, 2),     },      /* FVco 745.113600 */
-       { .frequency = 192326400,       .index = PLLVAL(151, 5, 2),     },      /* FVco 769.305600 */
-       { .frequency = 198132480,       .index = PLLVAL(109, 3, 2),     },      /* FVco 792.529920 */
-       { .frequency = 204271200,       .index = PLLVAL(185, 6, 2),     },      /* FVco 817.084800 */
-       { .frequency = 210268800,       .index = PLLVAL(141, 4, 2),     },      /* FVco 841.075200 */
-       { .frequency = 216518400,       .index = PLLVAL(171, 5, 2),     },      /* FVco 866.073600 */
-       { .frequency = 222264000,       .index = PLLVAL(97, 2, 2),      },      /* FVco 889.056000 */
-       { .frequency = 228614400,       .index = PLLVAL(127, 3, 2),     },      /* FVco 914.457600 */
-       { .frequency = 234259200,       .index = PLLVAL(158, 4, 2),     },      /* FVco 937.036800 */
-       { .frequency = 240468480,       .index = PLLVAL(134, 3, 2),     },      /* FVco 961.873920 */
-       { .frequency = 246960000,       .index = PLLVAL(167, 4, 2),     },      /* FVco 987.840000 */
-       { .frequency = 252322560,       .index = PLLVAL(141, 3, 2),     },      /* FVco 1009.290240 */
-       { .frequency = 258249600,       .index = PLLVAL(114, 2, 2),     },      /* FVco 1032.998400 */
-       { .frequency = 264176640,       .index = PLLVAL(148, 3, 2),     },      /* FVco 1056.706560 */
-       { .frequency = 270950400,       .index = PLLVAL(120, 2, 2),     },      /* FVco 1083.801600 */
-       { .frequency = 276030720,       .index = PLLVAL(155, 3, 2),     },      /* FVco 1104.122880 */
-       { .frequency = 282240000,       .index = PLLVAL(92, 1, 2),      },      /* FVco 1128.960000 */
-       { .frequency = 289578240,       .index = PLLVAL(163, 3, 2),     },      /* FVco 1158.312960 */
-       { .frequency = 294235200,       .index = PLLVAL(131, 2, 2),     },      /* FVco 1176.940800 */
-       { .frequency = 300200727,       .index = PLLVAL(187, 9, 1),     },      /* FVco 600.401454 */
-       { .frequency = 306358690,       .index = PLLVAL(191, 9, 1),     },      /* FVco 612.717380 */
-       { .frequency = 312076800,       .index = PLLVAL(121, 5, 1),     },      /* FVco 624.153600 */
-       { .frequency = 318366720,       .index = PLLVAL(86, 3, 1),      },      /* FVco 636.733440 */
-       { .frequency = 324172800,       .index = PLLVAL(126, 5, 1),     },      /* FVco 648.345600 */
-       { .frequency = 330220800,       .index = PLLVAL(109, 4, 1),     },      /* FVco 660.441600 */
-       { .frequency = 336268800,       .index = PLLVAL(131, 5, 1),     },      /* FVco 672.537600 */
-       { .frequency = 342074880,       .index = PLLVAL(93, 3, 1),      },      /* FVco 684.149760 */
-       { .frequency = 348096000,       .index = PLLVAL(177, 7, 1),     },      /* FVco 696.192000 */
-       { .frequency = 355622400,       .index = PLLVAL(118, 4, 1),     },      /* FVco 711.244800 */
-       { .frequency = 360460800,       .index = PLLVAL(141, 5, 1),     },      /* FVco 720.921600 */
-       { .frequency = 366206400,       .index = PLLVAL(165, 6, 1),     },      /* FVco 732.412800 */
-       { .frequency = 372556800,       .index = PLLVAL(124, 4, 1),     },      /* FVco 745.113600 */
-       { .frequency = 378201600,       .index = PLLVAL(126, 4, 1),     },      /* FVco 756.403200 */
-       { .frequency = 384652800,       .index = PLLVAL(151, 5, 1),     },      /* FVco 769.305600 */
-       { .frequency = 391608000,       .index = PLLVAL(177, 6, 1),     },      /* FVco 783.216000 */
-       { .frequency = 396264960,       .index = PLLVAL(109, 3, 1),     },      /* FVco 792.529920 */
-       { .frequency = 402192000,       .index = PLLVAL(87, 2, 1),      },      /* FVco 804.384000 */
+       { .frequency = 78019200,        .driver_data = PLLVAL(121, 5, 3),       },      /* FVco 624.153600 */
+       { .frequency = 84067200,        .driver_data = PLLVAL(131, 5, 3),       },      /* FVco 672.537600 */
+       { .frequency = 90115200,        .driver_data = PLLVAL(141, 5, 3),       },      /* FVco 720.921600 */
+       { .frequency = 96163200,        .driver_data = PLLVAL(151, 5, 3),       },      /* FVco 769.305600 */
+       { .frequency = 102135600,       .driver_data = PLLVAL(185, 6, 3),       },      /* FVco 817.084800 */
+       { .frequency = 108259200,       .driver_data = PLLVAL(171, 5, 3),       },      /* FVco 866.073600 */
+       { .frequency = 114307200,       .driver_data = PLLVAL(127, 3, 3),       },      /* FVco 914.457600 */
+       { .frequency = 120234240,       .driver_data = PLLVAL(134, 3, 3),       },      /* FVco 961.873920 */
+       { .frequency = 126161280,       .driver_data = PLLVAL(141, 3, 3),       },      /* FVco 1009.290240 */
+       { .frequency = 132088320,       .driver_data = PLLVAL(148, 3, 3),       },      /* FVco 1056.706560 */
+       { .frequency = 138015360,       .driver_data = PLLVAL(155, 3, 3),       },      /* FVco 1104.122880 */
+       { .frequency = 144789120,       .driver_data = PLLVAL(163, 3, 3),       },      /* FVco 1158.312960 */
+       { .frequency = 150100363,       .driver_data = PLLVAL(187, 9, 2),       },      /* FVco 600.401454 */
+       { .frequency = 156038400,       .driver_data = PLLVAL(121, 5, 2),       },      /* FVco 624.153600 */
+       { .frequency = 162086400,       .driver_data = PLLVAL(126, 5, 2),       },      /* FVco 648.345600 */
+       { .frequency = 168134400,       .driver_data = PLLVAL(131, 5, 2),       },      /* FVco 672.537600 */
+       { .frequency = 174048000,       .driver_data = PLLVAL(177, 7, 2),       },      /* FVco 696.192000 */
+       { .frequency = 180230400,       .driver_data = PLLVAL(141, 5, 2),       },      /* FVco 720.921600 */
+       { .frequency = 186278400,       .driver_data = PLLVAL(124, 4, 2),       },      /* FVco 745.113600 */
+       { .frequency = 192326400,       .driver_data = PLLVAL(151, 5, 2),       },      /* FVco 769.305600 */
+       { .frequency = 198132480,       .driver_data = PLLVAL(109, 3, 2),       },      /* FVco 792.529920 */
+       { .frequency = 204271200,       .driver_data = PLLVAL(185, 6, 2),       },      /* FVco 817.084800 */
+       { .frequency = 210268800,       .driver_data = PLLVAL(141, 4, 2),       },      /* FVco 841.075200 */
+       { .frequency = 216518400,       .driver_data = PLLVAL(171, 5, 2),       },      /* FVco 866.073600 */
+       { .frequency = 222264000,       .driver_data = PLLVAL(97, 2, 2),        },      /* FVco 889.056000 */
+       { .frequency = 228614400,       .driver_data = PLLVAL(127, 3, 2),       },      /* FVco 914.457600 */
+       { .frequency = 234259200,       .driver_data = PLLVAL(158, 4, 2),       },      /* FVco 937.036800 */
+       { .frequency = 240468480,       .driver_data = PLLVAL(134, 3, 2),       },      /* FVco 961.873920 */
+       { .frequency = 246960000,       .driver_data = PLLVAL(167, 4, 2),       },      /* FVco 987.840000 */
+       { .frequency = 252322560,       .driver_data = PLLVAL(141, 3, 2),       },      /* FVco 1009.290240 */
+       { .frequency = 258249600,       .driver_data = PLLVAL(114, 2, 2),       },      /* FVco 1032.998400 */
+       { .frequency = 264176640,       .driver_data = PLLVAL(148, 3, 2),       },      /* FVco 1056.706560 */
+       { .frequency = 270950400,       .driver_data = PLLVAL(120, 2, 2),       },      /* FVco 1083.801600 */
+       { .frequency = 276030720,       .driver_data = PLLVAL(155, 3, 2),       },      /* FVco 1104.122880 */
+       { .frequency = 282240000,       .driver_data = PLLVAL(92, 1, 2),        },      /* FVco 1128.960000 */
+       { .frequency = 289578240,       .driver_data = PLLVAL(163, 3, 2),       },      /* FVco 1158.312960 */
+       { .frequency = 294235200,       .driver_data = PLLVAL(131, 2, 2),       },      /* FVco 1176.940800 */
+       { .frequency = 300200727,       .driver_data = PLLVAL(187, 9, 1),       },      /* FVco 600.401454 */
+       { .frequency = 306358690,       .driver_data = PLLVAL(191, 9, 1),       },      /* FVco 612.717380 */
+       { .frequency = 312076800,       .driver_data = PLLVAL(121, 5, 1),       },      /* FVco 624.153600 */
+       { .frequency = 318366720,       .driver_data = PLLVAL(86, 3, 1),        },      /* FVco 636.733440 */
+       { .frequency = 324172800,       .driver_data = PLLVAL(126, 5, 1),       },      /* FVco 648.345600 */
+       { .frequency = 330220800,       .driver_data = PLLVAL(109, 4, 1),       },      /* FVco 660.441600 */
+       { .frequency = 336268800,       .driver_data = PLLVAL(131, 5, 1),       },      /* FVco 672.537600 */
+       { .frequency = 342074880,       .driver_data = PLLVAL(93, 3, 1),        },      /* FVco 684.149760 */
+       { .frequency = 348096000,       .driver_data = PLLVAL(177, 7, 1),       },      /* FVco 696.192000 */
+       { .frequency = 355622400,       .driver_data = PLLVAL(118, 4, 1),       },      /* FVco 711.244800 */
+       { .frequency = 360460800,       .driver_data = PLLVAL(141, 5, 1),       },      /* FVco 720.921600 */
+       { .frequency = 366206400,       .driver_data = PLLVAL(165, 6, 1),       },      /* FVco 732.412800 */
+       { .frequency = 372556800,       .driver_data = PLLVAL(124, 4, 1),       },      /* FVco 745.113600 */
+       { .frequency = 378201600,       .driver_data = PLLVAL(126, 4, 1),       },      /* FVco 756.403200 */
+       { .frequency = 384652800,       .driver_data = PLLVAL(151, 5, 1),       },      /* FVco 769.305600 */
+       { .frequency = 391608000,       .driver_data = PLLVAL(177, 6, 1),       },      /* FVco 783.216000 */
+       { .frequency = 396264960,       .driver_data = PLLVAL(109, 3, 1),       },      /* FVco 792.529920 */
+       { .frequency = 402192000,       .driver_data = PLLVAL(87, 2, 1),        },      /* FVco 804.384000 */
 };
 
 static int s3c2440_plls169344_add(struct device *dev,
index db27e8eef19247bfabaebb147c90f7c7e7a6182a..3912ce91fee42574346c85635ef9089076bceec0 100644 (file)
@@ -23,7 +23,7 @@ config ARCH_R8A73A4
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARM_GIC
        select CPU_V7
-       select ARM_ARCH_TIMER
+       select HAVE_ARM_ARCH_TIMER
        select SH_CLK_CPG
        select RENESAS_IRQC
 
@@ -59,7 +59,7 @@ config ARCH_R8A7790
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARM_GIC
        select CPU_V7
-       select ARM_ARCH_TIMER
+       select HAVE_ARM_ARCH_TIMER
        select SH_CLK_CPG
        select RENESAS_IRQC
 
index 7e105932c09d709f53a734f8633dcfde2b6a6efe..5390c6bbbc02dd389852ba519118ddaab2222a37 100644 (file)
@@ -142,15 +142,15 @@ static void pllc2_table_rebuild(struct clk *clk)
        /* Initialise PLLC2 frequency table */
        for (i = 0; i < ARRAY_SIZE(pllc2_freq_table) - 2; i++) {
                pllc2_freq_table[i].frequency = clk->parent->rate * (i + 20) * 2;
-               pllc2_freq_table[i].index = i;
+               pllc2_freq_table[i].driver_data = i;
        }
 
        /* This is a special entry - switching PLL off makes it a repeater */
        pllc2_freq_table[i].frequency = clk->parent->rate;
-       pllc2_freq_table[i].index = i;
+       pllc2_freq_table[i].driver_data = i;
 
        pllc2_freq_table[++i].frequency = CPUFREQ_TABLE_END;
-       pllc2_freq_table[i].index = i;
+       pllc2_freq_table[i].driver_data = i;
 }
 
 static unsigned long pllc2_recalc(struct clk *clk)
index 84d72fc36dfea1434431cb0b98a388f4b178e667..ef3a8da49b2d223616514c364e554f14add271d1 100644 (file)
@@ -28,7 +28,6 @@ config ARCH_TEGRA_2x_SOC
        select ARM_ERRATA_754327 if SMP
        select ARM_ERRATA_764369 if SMP
        select ARM_GIC
-       select CPU_FREQ_TABLE if CPU_FREQ
        select CPU_V7
        select PINCTRL
        select PINCTRL_TEGRA20
@@ -46,7 +45,6 @@ config ARCH_TEGRA_3x_SOC
        select ARM_ERRATA_754322
        select ARM_ERRATA_764369 if SMP
        select ARM_GIC
-       select CPU_FREQ_TABLE if CPU_FREQ
        select CPU_V7
        select PINCTRL
        select PINCTRL_TEGRA30
@@ -60,10 +58,9 @@ config ARCH_TEGRA_3x_SOC
 
 config ARCH_TEGRA_114_SOC
        bool "Enable support for Tegra114 family"
-       select ARM_ARCH_TIMER
+       select HAVE_ARM_ARCH_TIMER
        select ARM_GIC
        select ARM_L1_CACHE_SHIFT_6
-       select CPU_FREQ_TABLE if CPU_FREQ
        select CPU_V7
        select PINCTRL
        select PINCTRL_TEGRA114
index ec5836b1e7133d75118f082710337505bc800dcc..b25153e2ebaa4945c3d8d86eaaaa1d41597a8711 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/irqchip.h>
-#include <linux/clk/tegra.h>
+#include <linux/clk-provider.h>
 
 #include <asm/hardware/cache-l2x0.h>
 
@@ -60,7 +60,7 @@ u32 tegra_uart_config[4] = {
 #ifdef CONFIG_OF
 void __init tegra_dt_init_irq(void)
 {
-       tegra_clocks_init();
+       of_clk_init(NULL);
        tegra_pmc_init();
        tegra_init_irq();
        irqchip_init();
index b6145ea5164105dd80a2abafffb569acbd746410..e6fb0239151bdcf5953ac74cc37a0c3b80287c42 100644 (file)
@@ -76,13 +76,15 @@ void __init ux500_init_irq(void)
        } else if (cpu_is_u9540()) {
                prcmu_early_init(U8500_PRCMU_BASE, SZ_8K - 1);
                ux500_pm_init(U8500_PRCMU_BASE, SZ_8K - 1);
-               u8500_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
+               u9540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
                               U8500_CLKRST3_BASE, U8500_CLKRST5_BASE,
                               U8500_CLKRST6_BASE);
        } else if (cpu_is_u8540()) {
                prcmu_early_init(U8500_PRCMU_BASE, SZ_8K + SZ_4K - 1);
                ux500_pm_init(U8500_PRCMU_BASE, SZ_8K + SZ_4K - 1);
-               u8540_clk_init();
+               u8540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
+                              U8500_CLKRST3_BASE, U8500_CLKRST5_BASE,
+                              U8500_CLKRST6_BASE);
        }
 }
 
index 8958f0d896bc983cda9fcf9ffff12a4318ab4001..081d46929436b528517876da5cc92a2fd7a018be 100644 (file)
@@ -2,7 +2,7 @@ config ARCH_VIRT
        bool "Dummy Virtual Machine" if ARCH_MULTI_V7
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARM_GIC
-       select ARM_ARCH_TIMER
+       select HAVE_ARM_ARCH_TIMER
        select ARM_PSCI
        select HAVE_SMP
        select CPU_V7
index 9e8101ecd63e6a2b158849b74e14921a2b273177..6cacdc8dd654dd11ecbfb45f7576f1ead0a1062e 100644 (file)
@@ -392,7 +392,8 @@ config CPU_V7
        select CPU_CACHE_V7
        select CPU_CACHE_VIPT
        select CPU_COPY_V6 if MMU
-       select CPU_CP15_MMU
+       select CPU_CP15_MMU if MMU
+       select CPU_CP15_MPU if !MMU
        select CPU_HAS_ASID if MMU
        select CPU_PABRT_V7
        select CPU_TLB_V7 if MMU
index ee558a01f390925ca016f901697091660be48af4..ecfe6e53f6e03ffe7a12bf0776b784106f7efe19 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_MODULES)         += proc-syms.o
 
 obj-$(CONFIG_ALIGNMENT_TRAP)   += alignment.o
 obj-$(CONFIG_HIGHMEM)          += highmem.o
+obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
 
 obj-$(CONFIG_CPU_ABRT_NOMMU)   += abort-nommu.o
 obj-$(CONFIG_CPU_ABRT_EV4)     += abort-ev4.o
index c465faca51b06b05ed50c27962b8b169198ea909..d70e0aba0c9d9b4a0d10a78c627e159b1bf90d9b 100644 (file)
@@ -523,6 +523,147 @@ static void aurora_flush_range(unsigned long start, unsigned long end)
        }
 }
 
+/*
+ * For certain Broadcom SoCs, depending on the address range, different offsets
+ * need to be added to the address before passing it to L2 for
+ * invalidation/clean/flush
+ *
+ * Section Address Range              Offset        EMI
+ *   1     0x00000000 - 0x3FFFFFFF    0x80000000    VC
+ *   2     0x40000000 - 0xBFFFFFFF    0x40000000    SYS
+ *   3     0xC0000000 - 0xFFFFFFFF    0x80000000    VC
+ *
+ * When the start and end addresses have crossed two different sections, we
+ * need to break the L2 operation into two, each within its own section.
+ * For example, if we need to invalidate addresses starts at 0xBFFF0000 and
+ * ends at 0xC0001000, we need do invalidate 1) 0xBFFF0000 - 0xBFFFFFFF and 2)
+ * 0xC0000000 - 0xC0001000
+ *
+ * Note 1:
+ * By breaking a single L2 operation into two, we may potentially suffer some
+ * performance hit, but keep in mind the cross section case is very rare
+ *
+ * Note 2:
+ * We do not need to handle the case when the start address is in
+ * Section 1 and the end address is in Section 3, since it is not a valid use
+ * case
+ *
+ * Note 3:
+ * Section 1 in practical terms can no longer be used on rev A2. Because of
+ * that the code does not need to handle section 1 at all.
+ *
+ */
+#define BCM_SYS_EMI_START_ADDR        0x40000000UL
+#define BCM_VC_EMI_SEC3_START_ADDR    0xC0000000UL
+
+#define BCM_SYS_EMI_OFFSET            0x40000000UL
+#define BCM_VC_EMI_OFFSET             0x80000000UL
+
+static inline int bcm_addr_is_sys_emi(unsigned long addr)
+{
+       return (addr >= BCM_SYS_EMI_START_ADDR) &&
+               (addr < BCM_VC_EMI_SEC3_START_ADDR);
+}
+
+static inline unsigned long bcm_l2_phys_addr(unsigned long addr)
+{
+       if (bcm_addr_is_sys_emi(addr))
+               return addr + BCM_SYS_EMI_OFFSET;
+       else
+               return addr + BCM_VC_EMI_OFFSET;
+}
+
+static void bcm_inv_range(unsigned long start, unsigned long end)
+{
+       unsigned long new_start, new_end;
+
+       BUG_ON(start < BCM_SYS_EMI_START_ADDR);
+
+       if (unlikely(end <= start))
+               return;
+
+       new_start = bcm_l2_phys_addr(start);
+       new_end = bcm_l2_phys_addr(end);
+
+       /* normal case, no cross section between start and end */
+       if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
+               l2x0_inv_range(new_start, new_end);
+               return;
+       }
+
+       /* They cross sections, so it can only be a cross from section
+        * 2 to section 3
+        */
+       l2x0_inv_range(new_start,
+               bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
+       l2x0_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+               new_end);
+}
+
+static void bcm_clean_range(unsigned long start, unsigned long end)
+{
+       unsigned long new_start, new_end;
+
+       BUG_ON(start < BCM_SYS_EMI_START_ADDR);
+
+       if (unlikely(end <= start))
+               return;
+
+       if ((end - start) >= l2x0_size) {
+               l2x0_clean_all();
+               return;
+       }
+
+       new_start = bcm_l2_phys_addr(start);
+       new_end = bcm_l2_phys_addr(end);
+
+       /* normal case, no cross section between start and end */
+       if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
+               l2x0_clean_range(new_start, new_end);
+               return;
+       }
+
+       /* They cross sections, so it can only be a cross from section
+        * 2 to section 3
+        */
+       l2x0_clean_range(new_start,
+               bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
+       l2x0_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+               new_end);
+}
+
+static void bcm_flush_range(unsigned long start, unsigned long end)
+{
+       unsigned long new_start, new_end;
+
+       BUG_ON(start < BCM_SYS_EMI_START_ADDR);
+
+       if (unlikely(end <= start))
+               return;
+
+       if ((end - start) >= l2x0_size) {
+               l2x0_flush_all();
+               return;
+       }
+
+       new_start = bcm_l2_phys_addr(start);
+       new_end = bcm_l2_phys_addr(end);
+
+       /* normal case, no cross section between start and end */
+       if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
+               l2x0_flush_range(new_start, new_end);
+               return;
+       }
+
+       /* They cross sections, so it can only be a cross from section
+        * 2 to section 3
+        */
+       l2x0_flush_range(new_start,
+               bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
+       l2x0_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+               new_end);
+}
+
 static void __init l2x0_of_setup(const struct device_node *np,
                                 u32 *aux_val, u32 *aux_mask)
 {
@@ -765,6 +906,21 @@ static const struct l2x0_of_data aurora_no_outer_data = {
        },
 };
 
+static const struct l2x0_of_data bcm_l2x0_data = {
+       .setup = pl310_of_setup,
+       .save  = pl310_save,
+       .outer_cache = {
+               .resume      = pl310_resume,
+               .inv_range   = bcm_inv_range,
+               .clean_range = bcm_clean_range,
+               .flush_range = bcm_flush_range,
+               .sync        = l2x0_cache_sync,
+               .flush_all   = l2x0_flush_all,
+               .inv_all     = l2x0_inv_all,
+               .disable     = l2x0_disable,
+       },
+};
+
 static const struct of_device_id l2x0_ids[] __initconst = {
        { .compatible = "arm,pl310-cache", .data = (void *)&pl310_data },
        { .compatible = "arm,l220-cache", .data = (void *)&l2x0_data },
@@ -773,6 +929,8 @@ static const struct of_device_id l2x0_ids[] __initconst = {
          .data = (void *)&aurora_no_outer_data},
        { .compatible = "marvell,aurora-outer-cache",
          .data = (void *)&aurora_with_outer_data},
+       { .compatible = "bcm,bcm11351-a2-pl310-cache",
+         .data = (void *)&bcm_l2x0_data},
        {}
 };
 
index 2ac37372ef52f4ba4db642d39bef349798f1785a..b55b1015724b56931c57ad7b2920d760b80529e8 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/smp_plat.h>
 #include <asm/thread_notify.h>
 #include <asm/tlbflush.h>
+#include <asm/proc-fns.h>
 
 /*
  * On ARMv6, we have the following structure in the Context ID:
  * non 64-bit operations.
  */
 #define ASID_FIRST_VERSION     (1ULL << ASID_BITS)
-#define NUM_USER_ASIDS         (ASID_FIRST_VERSION - 1)
-
-#define ASID_TO_IDX(asid)      ((asid & ~ASID_MASK) - 1)
-#define IDX_TO_ASID(idx)       ((idx + 1) & ~ASID_MASK)
+#define NUM_USER_ASIDS         ASID_FIRST_VERSION
 
 static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
 static atomic64_t asid_generation = ATOMIC64_INIT(ASID_FIRST_VERSION);
 static DECLARE_BITMAP(asid_map, NUM_USER_ASIDS);
 
-DEFINE_PER_CPU(atomic64_t, active_asids);
+static DEFINE_PER_CPU(atomic64_t, active_asids);
 static DEFINE_PER_CPU(u64, reserved_asids);
 static cpumask_t tlb_flush_pending;
 
+#ifdef CONFIG_ARM_ERRATA_798181
+void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
+                            cpumask_t *mask)
+{
+       int cpu;
+       unsigned long flags;
+       u64 context_id, asid;
+
+       raw_spin_lock_irqsave(&cpu_asid_lock, flags);
+       context_id = mm->context.id.counter;
+       for_each_online_cpu(cpu) {
+               if (cpu == this_cpu)
+                       continue;
+               /*
+                * We only need to send an IPI if the other CPUs are
+                * running the same ASID as the one being invalidated.
+                */
+               asid = per_cpu(active_asids, cpu).counter;
+               if (asid == 0)
+                       asid = per_cpu(reserved_asids, cpu);
+               if (context_id == asid)
+                       cpumask_set_cpu(cpu, mask);
+       }
+       raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
+}
+#endif
+
 #ifdef CONFIG_ARM_LPAE
 static void cpu_set_reserved_ttbr0(void)
 {
-       unsigned long ttbl = __pa(swapper_pg_dir);
-       unsigned long ttbh = 0;
-
        /*
         * Set TTBR0 to swapper_pg_dir which contains only global entries. The
         * ASID is set to 0.
         */
-       asm volatile(
-       "       mcrr    p15, 0, %0, %1, c2              @ set TTBR0\n"
-       :
-       : "r" (ttbl), "r" (ttbh));
+       cpu_set_ttbr(0, __pa(swapper_pg_dir));
        isb();
 }
 #else
@@ -128,7 +147,16 @@ static void flush_context(unsigned int cpu)
                        asid = 0;
                } else {
                        asid = atomic64_xchg(&per_cpu(active_asids, i), 0);
-                       __set_bit(ASID_TO_IDX(asid), asid_map);
+                       /*
+                        * If this CPU has already been through a
+                        * rollover, but hasn't run another task in
+                        * the meantime, we must preserve its reserved
+                        * ASID, as this is the only trace we have of
+                        * the process it is still running.
+                        */
+                       if (asid == 0)
+                               asid = per_cpu(reserved_asids, i);
+                       __set_bit(asid & ~ASID_MASK, asid_map);
                }
                per_cpu(reserved_asids, i) = asid;
        }
@@ -167,17 +195,19 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
                /*
                 * Allocate a free ASID. If we can't find one, take a
                 * note of the currently active ASIDs and mark the TLBs
-                * as requiring flushes.
+                * as requiring flushes. We always count from ASID #1,
+                * as we reserve ASID #0 to switch via TTBR0 and indicate
+                * rollover events.
                 */
-               asid = find_first_zero_bit(asid_map, NUM_USER_ASIDS);
+               asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, 1);
                if (asid == NUM_USER_ASIDS) {
                        generation = atomic64_add_return(ASID_FIRST_VERSION,
                                                         &asid_generation);
                        flush_context(cpu);
-                       asid = find_first_zero_bit(asid_map, NUM_USER_ASIDS);
+                       asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, 1);
                }
                __set_bit(asid, asid_map);
-               asid = generation | IDX_TO_ASID(asid);
+               asid |= generation;
                cpumask_clear(mm_cpumask(mm));
        }
 
index ef3e0f3aac96261d1c8e73671a00419c977902bc..7ec02961dfa0d8fe161d61071020fead4f89b7fc 100644 (file)
@@ -250,7 +250,7 @@ static void __dma_free_buffer(struct page *page, size_t size)
 
 #ifdef CONFIG_MMU
 #ifdef CONFIG_HUGETLB_PAGE
-#error ARM Coherent DMA allocator does not (yet) support huge TLB
+#warning ARM Coherent DMA allocator does not (yet) support huge TLB
 #endif
 
 static void *__alloc_from_contiguous(struct device *dev, size_t size,
@@ -880,10 +880,24 @@ static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
        dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
 
        /*
-        * Mark the D-cache clean for this page to avoid extra flushing.
+        * Mark the D-cache clean for these pages to avoid extra flushing.
         */
-       if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
-               set_bit(PG_dcache_clean, &page->flags);
+       if (dir != DMA_TO_DEVICE && size >= PAGE_SIZE) {
+               unsigned long pfn;
+               size_t left = size;
+
+               pfn = page_to_pfn(page) + off / PAGE_SIZE;
+               off %= PAGE_SIZE;
+               if (off) {
+                       pfn++;
+                       left -= PAGE_SIZE - off;
+               }
+               while (left >= PAGE_SIZE) {
+                       page = pfn_to_page(pfn++);
+                       set_bit(PG_dcache_clean, &page->flags);
+                       left -= PAGE_SIZE;
+               }
+       }
 }
 
 /**
index 5dbf13f954f6f493aaae525d4f3b93282ac88f75..c97f7940cb9553d52ba3b6c711f2dab430aea110 100644 (file)
@@ -491,12 +491,14 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
  * Some section permission faults need to be handled gracefully.
  * They can happen due to a __{get,put}_user during an oops.
  */
+#ifndef CONFIG_ARM_LPAE
 static int
 do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
        do_bad_area(addr, fsr, regs);
        return 0;
 }
+#endif /* CONFIG_ARM_LPAE */
 
 /*
  * This abort handler always returns "fault".
index 32aa5861119f2bdd353468114462dd8a680a60cb..6d5ba9afb16a4409d50dbdbc03d08c83642df9b4 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/highmem.h>
 #include <asm/smp_plat.h>
 #include <asm/tlbflush.h>
+#include <linux/hugetlb.h>
 
 #include "mm.h"
 
@@ -168,19 +169,23 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
         * coherent with the kernels mapping.
         */
        if (!PageHighMem(page)) {
-               __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
+               size_t page_size = PAGE_SIZE << compound_order(page);
+               __cpuc_flush_dcache_area(page_address(page), page_size);
        } else {
-               void *addr;
-
+               unsigned long i;
                if (cache_is_vipt_nonaliasing()) {
-                       addr = kmap_atomic(page);
-                       __cpuc_flush_dcache_area(addr, PAGE_SIZE);
-                       kunmap_atomic(addr);
-               } else {
-                       addr = kmap_high_get(page);
-                       if (addr) {
+                       for (i = 0; i < (1 << compound_order(page)); i++) {
+                               void *addr = kmap_atomic(page);
                                __cpuc_flush_dcache_area(addr, PAGE_SIZE);
-                               kunmap_high(page);
+                               kunmap_atomic(addr);
+                       }
+               } else {
+                       for (i = 0; i < (1 << compound_order(page)); i++) {
+                               void *addr = kmap_high_get(page);
+                               if (addr) {
+                                       __cpuc_flush_dcache_area(addr, PAGE_SIZE);
+                                       kunmap_high(page);
+                               }
                        }
                }
        }
@@ -287,7 +292,7 @@ void flush_dcache_page(struct page *page)
        mapping = page_mapping(page);
 
        if (!cache_ops_need_broadcast() &&
-           mapping && !mapping_mapped(mapping))
+           mapping && !page_mapped(page))
                clear_bit(PG_dcache_clean, &page->flags);
        else {
                __flush_dcache_page(mapping, page);
index 05a4e943183650ddba75efd5727d2196a01aeb94..ab4409a2307e07a602f1fcba08519cbbf2201d00 100644 (file)
@@ -9,11 +9,11 @@ static struct fsr_info fsr_info[] = {
        { do_page_fault,        SIGSEGV, SEGV_MAPERR,   "level 3 translation fault"     },
        { do_bad,               SIGBUS,  0,             "reserved access flag fault"    },
        { do_bad,               SIGSEGV, SEGV_ACCERR,   "level 1 access flag fault"     },
-       { do_bad,               SIGSEGV, SEGV_ACCERR,   "level 2 access flag fault"     },
+       { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 access flag fault"     },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 access flag fault"     },
        { do_bad,               SIGBUS,  0,             "reserved permission fault"     },
        { do_bad,               SIGSEGV, SEGV_ACCERR,   "level 1 permission fault"      },
-       { do_sect_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 permission fault"      },
+       { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 permission fault"      },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 permission fault"      },
        { do_bad,               SIGBUS,  0,             "synchronous external abort"    },
        { do_bad,               SIGBUS,  0,             "asynchronous external abort"   },
diff --git a/arch/arm/mm/hugetlbpage.c b/arch/arm/mm/hugetlbpage.c
new file mode 100644 (file)
index 0000000..3d1e4a2
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * arch/arm/mm/hugetlbpage.c
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * Based on arch/x86/include/asm/hugetlb.h and Bill Carson's patches
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+#include <linux/sysctl.h>
+#include <asm/mman.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
+
+/*
+ * On ARM, huge pages are backed by pmd's rather than pte's, so we do a lot
+ * of type casting from pmd_t * to pte_t *.
+ */
+
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd = NULL;
+
+       pgd = pgd_offset(mm, addr);
+       if (pgd_present(*pgd)) {
+               pud = pud_offset(pgd, addr);
+               if (pud_present(*pud))
+                       pmd = pmd_offset(pud, addr);
+       }
+
+       return (pte_t *)pmd;
+}
+
+struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
+                             int write)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+int pud_huge(pud_t pud)
+{
+       return 0;
+}
+
+int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
+{
+       return 0;
+}
+
+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;
+
+       pgd = pgd_offset(mm, addr);
+       pud = pud_alloc(mm, pgd, addr);
+       if (pud)
+               pte = (pte_t *)pmd_alloc(mm, pud, addr);
+
+       return pte;
+}
+
+struct page *
+follow_huge_pmd(struct mm_struct *mm, unsigned long address,
+               pmd_t *pmd, int write)
+{
+       struct page *page;
+
+       page = pte_page(*(pte_t *)pmd);
+       if (page)
+               page += ((address & ~PMD_MASK) >> PAGE_SHIFT);
+       return page;
+}
+
+int pmd_huge(pmd_t pmd)
+{
+       return pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
+}
index 9a5cdc01fcdfef7315ec97687c35ae28adcb7688..6833cbead6cc33b91863083c10e1ab8c5bd3ac4f 100644 (file)
 
 #include "mm.h"
 
-static unsigned long phys_initrd_start __initdata = 0;
+static phys_addr_t phys_initrd_start __initdata = 0;
 static unsigned long phys_initrd_size __initdata = 0;
 
 static int __init early_initrd(char *p)
 {
-       unsigned long start, size;
+       phys_addr_t start;
+       unsigned long size;
        char *endp;
 
        start = memparse(p, &endp);
@@ -350,14 +351,14 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
 #ifdef CONFIG_BLK_DEV_INITRD
        if (phys_initrd_size &&
            !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
-               pr_err("INITRD: 0x%08lx+0x%08lx is not a memory region - disabling initrd\n",
-                      phys_initrd_start, phys_initrd_size);
+               pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n",
+                      (u64)phys_initrd_start, phys_initrd_size);
                phys_initrd_start = phys_initrd_size = 0;
        }
        if (phys_initrd_size &&
            memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
-               pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n",
-                      phys_initrd_start, phys_initrd_size);
+               pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region - disabling initrd\n",
+                      (u64)phys_initrd_start, phys_initrd_size);
                phys_initrd_start = phys_initrd_size = 0;
        }
        if (phys_initrd_size) {
@@ -442,7 +443,7 @@ static inline void
 free_memmap(unsigned long start_pfn, unsigned long end_pfn)
 {
        struct page *start_pg, *end_pg;
-       unsigned long pg, pgend;
+       phys_addr_t pg, pgend;
 
        /*
         * Convert start_pfn/end_pfn to a struct page pointer.
@@ -454,8 +455,8 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
         * Convert to physical addresses, and
         * round start upwards and end downwards.
         */
-       pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
-       pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
+       pg = PAGE_ALIGN(__pa(start_pg));
+       pgend = __pa(end_pg) & PAGE_MASK;
 
        /*
         * If there are free pages between these,
@@ -582,9 +583,6 @@ static void __init free_highpages(void)
  */
 void __init mem_init(void)
 {
-       unsigned long reserved_pages, free_pages;
-       struct memblock_region *reg;
-       int i;
 #ifdef CONFIG_HAVE_TCM
        /* These pointers are filled in on TCM detection */
        extern u32 dtcm_end;
@@ -595,57 +593,16 @@ void __init mem_init(void)
 
        /* this will put all unused low memory onto the freelists */
        free_unused_memmap(&meminfo);
-
-       totalram_pages += free_all_bootmem();
+       free_all_bootmem();
 
 #ifdef CONFIG_SA1111
        /* now that our DMA memory is actually so designated, we can free it */
-       free_reserved_area(__va(PHYS_PFN_OFFSET), swapper_pg_dir, 0, NULL);
+       free_reserved_area(__va(PHYS_PFN_OFFSET), swapper_pg_dir, -1, NULL);
 #endif
 
        free_highpages();
 
-       reserved_pages = free_pages = 0;
-
-       for_each_bank(i, &meminfo) {
-               struct membank *bank = &meminfo.bank[i];
-               unsigned int pfn1, pfn2;
-               struct page *page, *end;
-
-               pfn1 = bank_pfn_start(bank);
-               pfn2 = bank_pfn_end(bank);
-
-               page = pfn_to_page(pfn1);
-               end  = pfn_to_page(pfn2 - 1) + 1;
-
-               do {
-                       if (PageReserved(page))
-                               reserved_pages++;
-                       else if (!page_count(page))
-                               free_pages++;
-                       page++;
-               } while (page < end);
-       }
-
-       /*
-        * Since our memory may not be contiguous, calculate the
-        * real number of pages we have in this system
-        */
-       printk(KERN_INFO "Memory:");
-       num_physpages = 0;
-       for_each_memblock(memory, reg) {
-               unsigned long pages = memblock_region_memory_end_pfn(reg) -
-                       memblock_region_memory_base_pfn(reg);
-               num_physpages += pages;
-               printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
-       }
-       printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
-
-       printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
-               nr_free_pages() << (PAGE_SHIFT-10),
-               free_pages << (PAGE_SHIFT-10),
-               reserved_pages << (PAGE_SHIFT-10),
-               totalhigh_pages << (PAGE_SHIFT-10));
+       mem_init_print_info(NULL);
 
 #define MLK(b, t) b, t, ((t) - (b)) >> 10
 #define MLM(b, t) b, t, ((t) - (b)) >> 20
@@ -711,7 +668,7 @@ void __init mem_init(void)
        BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE      > PAGE_OFFSET);
 #endif
 
-       if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
+       if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
                extern int sysctl_overcommit_memory;
                /*
                 * On a machine this small we won't get
@@ -728,12 +685,12 @@ void free_initmem(void)
        extern char __tcm_start, __tcm_end;
 
        poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start);
-       free_reserved_area(&__tcm_start, &__tcm_end, 0, "TCM link");
+       free_reserved_area(&__tcm_start, &__tcm_end, -1, "TCM link");
 #endif
 
        poison_init_mem(__init_begin, __init_end - __init_begin);
        if (!machine_is_integrator() && !machine_is_cintegrator())
-               free_initmem_default(0);
+               free_initmem_default(-1);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -744,7 +701,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 {
        if (!keep_initrd) {
                poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
-               free_reserved_area(start, end, 0, "initrd");
+               free_reserved_area((void *)start, (void *)end, -1, "initrd");
        }
 }
 
index 04d9006eab1fd1120d8dd823bfb91d232a25ccc3..f123d6eb074b056586dd840ba2465d3fba2b36a2 100644 (file)
@@ -331,10 +331,10 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
        return (void __iomem *) (offset + addr);
 }
 
-void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
+void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
        unsigned int mtype, void *caller)
 {
-       unsigned long last_addr;
+       phys_addr_t last_addr;
        unsigned long offset = phys_addr & ~PAGE_MASK;
        unsigned long pfn = __phys_to_pfn(phys_addr);
 
@@ -367,12 +367,12 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
 }
 EXPORT_SYMBOL(__arm_ioremap_pfn);
 
-void __iomem * (*arch_ioremap_caller)(unsigned long, size_t,
+void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
                                      unsigned int, void *) =
        __arm_ioremap_caller;
 
 void __iomem *
-__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+__arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
 {
        return arch_ioremap_caller(phys_addr, size, mtype,
                __builtin_return_address(0));
@@ -387,7 +387,7 @@ EXPORT_SYMBOL(__arm_ioremap);
  * CONFIG_GENERIC_ALLOCATOR for allocating external memory.
  */
 void __iomem *
-__arm_ioremap_exec(unsigned long phys_addr, size_t size, bool cached)
+__arm_ioremap_exec(phys_addr_t phys_addr, size_t size, bool cached)
 {
        unsigned int mtype;
 
index d1d1cefa1f93b47a895f748528ab580632a468b8..d7229d28c7f8ea9cef25d2e84db8f3a82d5b9a75 100644 (file)
@@ -675,7 +675,8 @@ 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, unsigned long phys, const struct mem_type *type)
+                                 unsigned long end, phys_addr_t phys,
+                                 const struct mem_type *type)
 {
        pud_t *pud = pud_offset(pgd, addr);
        unsigned long next;
@@ -989,27 +990,28 @@ phys_addr_t arm_lowmem_limit __initdata = 0;
 void __init sanity_check_meminfo(void)
 {
        int i, j, highmem = 0;
+       phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
 
        for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
                struct membank *bank = &meminfo.bank[j];
-               *bank = meminfo.bank[i];
+               phys_addr_t size_limit;
 
-               if (bank->start > ULONG_MAX)
-                       highmem = 1;
+               *bank = meminfo.bank[i];
+               size_limit = bank->size;
 
-#ifdef CONFIG_HIGHMEM
-               if (__va(bank->start) >= vmalloc_min ||
-                   __va(bank->start) < (void *)PAGE_OFFSET)
+               if (bank->start >= vmalloc_limit)
                        highmem = 1;
+               else
+                       size_limit = vmalloc_limit - bank->start;
 
                bank->highmem = highmem;
 
+#ifdef CONFIG_HIGHMEM
                /*
                 * Split those memory banks which are partially overlapping
                 * the vmalloc area greatly simplifying things later.
                 */
-               if (!highmem && __va(bank->start) < vmalloc_min &&
-                   bank->size > vmalloc_min - __va(bank->start)) {
+               if (!highmem && bank->size > size_limit) {
                        if (meminfo.nr_banks >= NR_BANKS) {
                                printk(KERN_CRIT "NR_BANKS too low, "
                                                 "ignoring high memory\n");
@@ -1018,16 +1020,14 @@ void __init sanity_check_meminfo(void)
                                        (meminfo.nr_banks - i) * sizeof(*bank));
                                meminfo.nr_banks++;
                                i++;
-                               bank[1].size -= vmalloc_min - __va(bank->start);
-                               bank[1].start = __pa(vmalloc_min - 1) + 1;
+                               bank[1].size -= size_limit;
+                               bank[1].start = vmalloc_limit;
                                bank[1].highmem = highmem = 1;
                                j++;
                        }
-                       bank->size = vmalloc_min - __va(bank->start);
+                       bank->size = size_limit;
                }
 #else
-               bank->highmem = highmem;
-
                /*
                 * Highmem banks not allowed with !CONFIG_HIGHMEM.
                 */
@@ -1039,32 +1039,17 @@ void __init sanity_check_meminfo(void)
                        continue;
                }
 
-               /*
-                * Check whether this memory bank would entirely overlap
-                * the vmalloc area.
-                */
-               if (__va(bank->start) >= vmalloc_min ||
-                   __va(bank->start) < (void *)PAGE_OFFSET) {
-                       printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
-                              "(vmalloc region overlap).\n",
-                              (unsigned long long)bank->start,
-                              (unsigned long long)bank->start + bank->size - 1);
-                       continue;
-               }
-
                /*
                 * Check whether this memory bank would partially overlap
                 * the vmalloc area.
                 */
-               if (__va(bank->start + bank->size - 1) >= vmalloc_min ||
-                   __va(bank->start + bank->size - 1) <= __va(bank->start)) {
-                       unsigned long newsize = vmalloc_min - __va(bank->start);
+               if (bank->size > size_limit) {
                        printk(KERN_NOTICE "Truncating RAM at %.8llx-%.8llx "
                               "to -%.8llx (vmalloc region overlap).\n",
                               (unsigned long long)bank->start,
                               (unsigned long long)bank->start + bank->size - 1,
-                              (unsigned long long)bank->start + newsize - 1);
-                       bank->size = newsize;
+                              (unsigned long long)bank->start + size_limit - 1);
+                       bank->size = size_limit;
                }
 #endif
                if (!bank->highmem && bank->start + bank->size > arm_lowmem_limit)
index 5a3aba614a405b8290c02a4aedaa2d81e00ee40e..1fa50100ab6af1f57067af8ff06c4a05d1fcb3ff 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/pagemap.h>
 #include <linux/io.h>
 #include <linux/memblock.h>
+#include <linux/kernel.h>
 
 #include <asm/cacheflush.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/traps.h>
 #include <asm/mach/arch.h>
+#include <asm/cputype.h>
+#include <asm/mpu.h>
 
 #include "mm.h"
 
+#ifdef CONFIG_ARM_MPU
+struct mpu_rgn_info mpu_rgn_info;
+
+/* Region number */
+static void rgnr_write(u32 v)
+{
+       asm("mcr        p15, 0, %0, c6, c2, 0" : : "r" (v));
+}
+
+/* Data-side / unified region attributes */
+
+/* Region access control register */
+static void dracr_write(u32 v)
+{
+       asm("mcr        p15, 0, %0, c6, c1, 4" : : "r" (v));
+}
+
+/* Region size register */
+static void drsr_write(u32 v)
+{
+       asm("mcr        p15, 0, %0, c6, c1, 2" : : "r" (v));
+}
+
+/* Region base address register */
+static void drbar_write(u32 v)
+{
+       asm("mcr        p15, 0, %0, c6, c1, 0" : : "r" (v));
+}
+
+static u32 drbar_read(void)
+{
+       u32 v;
+       asm("mrc        p15, 0, %0, c6, c1, 0" : "=r" (v));
+       return v;
+}
+/* Optional instruction-side region attributes */
+
+/* I-side Region access control register */
+static void iracr_write(u32 v)
+{
+       asm("mcr        p15, 0, %0, c6, c1, 5" : : "r" (v));
+}
+
+/* I-side Region size register */
+static void irsr_write(u32 v)
+{
+       asm("mcr        p15, 0, %0, c6, c1, 3" : : "r" (v));
+}
+
+/* I-side Region base address register */
+static void irbar_write(u32 v)
+{
+       asm("mcr        p15, 0, %0, c6, c1, 1" : : "r" (v));
+}
+
+static unsigned long irbar_read(void)
+{
+       unsigned long v;
+       asm("mrc        p15, 0, %0, c6, c1, 1" : "=r" (v));
+       return v;
+}
+
+/* MPU initialisation functions */
+void __init sanity_check_meminfo_mpu(void)
+{
+       int i;
+       struct membank *bank = meminfo.bank;
+       phys_addr_t phys_offset = PHYS_OFFSET;
+       phys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size;
+
+       /* Initially only use memory continuous from PHYS_OFFSET */
+       if (bank_phys_start(&bank[0]) != phys_offset)
+               panic("First memory bank must be contiguous from PHYS_OFFSET");
+
+       /* Banks have already been sorted by start address */
+       for (i = 1; i < meminfo.nr_banks; i++) {
+               if (bank[i].start <= bank_phys_end(&bank[0]) &&
+                   bank_phys_end(&bank[i]) > bank_phys_end(&bank[0])) {
+                       bank[0].size = bank_phys_end(&bank[i]) - bank[0].start;
+               } else {
+                       pr_notice("Ignoring RAM after 0x%.8lx. "
+                       "First non-contiguous (ignored) bank start: 0x%.8lx\n",
+                               (unsigned long)bank_phys_end(&bank[0]),
+                               (unsigned long)bank_phys_start(&bank[i]));
+                       break;
+               }
+       }
+       /* All contiguous banks are now merged in to the first bank */
+       meminfo.nr_banks = 1;
+       specified_mem_size = bank[0].size;
+
+       /*
+        * MPU has curious alignment requirements: Size must be power of 2, and
+        * region start must be aligned to the region size
+        */
+       if (phys_offset != 0)
+               pr_info("PHYS_OFFSET != 0 => MPU Region size constrained by alignment requirements\n");
+
+       /*
+        * Maximum aligned region might overflow phys_addr_t if phys_offset is
+        * 0. Hence we keep everything below 4G until we take the smaller of
+        * the aligned_region_size and rounded_mem_size, one of which is
+        * guaranteed to be smaller than the maximum physical address.
+        */
+       aligned_region_size = (phys_offset - 1) ^ (phys_offset);
+       /* Find the max power-of-two sized region that fits inside our bank */
+       rounded_mem_size = (1 <<  __fls(bank[0].size)) - 1;
+
+       /* The actual region size is the smaller of the two */
+       aligned_region_size = aligned_region_size < rounded_mem_size
+                               ? aligned_region_size + 1
+                               : rounded_mem_size + 1;
+
+       if (aligned_region_size != specified_mem_size)
+               pr_warn("Truncating memory from 0x%.8lx to 0x%.8lx (MPU region constraints)",
+                               (unsigned long)specified_mem_size,
+                               (unsigned long)aligned_region_size);
+
+       meminfo.bank[0].size = aligned_region_size;
+       pr_debug("MPU Region from 0x%.8lx size 0x%.8lx (end 0x%.8lx))\n",
+               (unsigned long)phys_offset,
+               (unsigned long)aligned_region_size,
+               (unsigned long)bank_phys_end(&bank[0]));
+
+}
+
+static int mpu_present(void)
+{
+       return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7);
+}
+
+static int mpu_max_regions(void)
+{
+       /*
+        * We don't support a different number of I/D side regions so if we
+        * have separate instruction and data memory maps then return
+        * whichever side has a smaller number of supported regions.
+        */
+       u32 dregions, iregions, mpuir;
+       mpuir = read_cpuid(CPUID_MPUIR);
+
+       dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;
+
+       /* Check for separate d-side and i-side memory maps */
+       if (mpuir & MPUIR_nU)
+               iregions = (mpuir & MPUIR_IREGION_SZMASK) >> MPUIR_IREGION;
+
+       /* Use the smallest of the two maxima */
+       return min(dregions, iregions);
+}
+
+static int mpu_iside_independent(void)
+{
+       /* MPUIR.nU specifies whether there is *not* a unified memory map */
+       return read_cpuid(CPUID_MPUIR) & MPUIR_nU;
+}
+
+static int mpu_min_region_order(void)
+{
+       u32 drbar_result, irbar_result;
+       /* We've kept a region free for this probing */
+       rgnr_write(MPU_PROBE_REGION);
+       isb();
+       /*
+        * As per ARM ARM, write 0xFFFFFFFC to DRBAR to find the minimum
+        * region order
+       */
+       drbar_write(0xFFFFFFFC);
+       drbar_result = irbar_result = drbar_read();
+       drbar_write(0x0);
+       /* If the MPU is non-unified, we use the larger of the two minima*/
+       if (mpu_iside_independent()) {
+               irbar_write(0xFFFFFFFC);
+               irbar_result = irbar_read();
+               irbar_write(0x0);
+       }
+       isb(); /* Ensure that MPU region operations have completed */
+       /* Return whichever result is larger */
+       return __ffs(max(drbar_result, irbar_result));
+}
+
+static int mpu_setup_region(unsigned int number, phys_addr_t start,
+                       unsigned int size_order, unsigned int properties)
+{
+       u32 size_data;
+
+       /* We kept a region free for probing resolution of MPU regions*/
+       if (number > mpu_max_regions() || number == MPU_PROBE_REGION)
+               return -ENOENT;
+
+       if (size_order > 32)
+               return -ENOMEM;
+
+       if (size_order < mpu_min_region_order())
+               return -ENOMEM;
+
+       /* Writing N to bits 5:1 (RSR_SZ)  specifies region size 2^N+1 */
+       size_data = ((size_order - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN;
+
+       dsb(); /* Ensure all previous data accesses occur with old mappings */
+       rgnr_write(number);
+       isb();
+       drbar_write(start);
+       dracr_write(properties);
+       isb(); /* Propagate properties before enabling region */
+       drsr_write(size_data);
+
+       /* Check for independent I-side registers */
+       if (mpu_iside_independent()) {
+               irbar_write(start);
+               iracr_write(properties);
+               isb();
+               irsr_write(size_data);
+       }
+       isb();
+
+       /* Store region info (we treat i/d side the same, so only store d) */
+       mpu_rgn_info.rgns[number].dracr = properties;
+       mpu_rgn_info.rgns[number].drbar = start;
+       mpu_rgn_info.rgns[number].drsr = size_data;
+       return 0;
+}
+
+/*
+* Set up default MPU regions, doing nothing if there is no MPU
+*/
+void __init mpu_setup(void)
+{
+       int region_err;
+       if (!mpu_present())
+               return;
+
+       region_err = mpu_setup_region(MPU_RAM_REGION, PHYS_OFFSET,
+                                       ilog2(meminfo.bank[0].size),
+                                       MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);
+       if (region_err) {
+               panic("MPU region initialization failure! %d", region_err);
+       } else {
+               pr_info("Using ARMv7 PMSA Compliant MPU. "
+                        "Region independence: %s, Max regions: %d\n",
+                       mpu_iside_independent() ? "Yes" : "No",
+                       mpu_max_regions());
+       }
+}
+#else
+static void sanity_check_meminfo_mpu(void) {}
+static void __init mpu_setup(void) {}
+#endif /* CONFIG_ARM_MPU */
+
 void __init arm_mm_memblock_reserve(void)
 {
 #ifndef CONFIG_CPU_V7M
@@ -37,7 +289,9 @@ void __init arm_mm_memblock_reserve(void)
 
 void __init sanity_check_meminfo(void)
 {
-       phys_addr_t end = bank_phys_end(&meminfo.bank[meminfo.nr_banks - 1]);
+       phys_addr_t end;
+       sanity_check_meminfo_mpu();
+       end = bank_phys_end(&meminfo.bank[meminfo.nr_banks - 1]);
        high_memory = __va(end - 1) + 1;
 }
 
@@ -48,6 +302,7 @@ void __init sanity_check_meminfo(void)
 void __init paging_init(struct machine_desc *mdesc)
 {
        early_trap_init((void *)CONFIG_VECTORS_BASE);
+       mpu_setup();
        bootmem_init();
 }
 
@@ -94,16 +349,16 @@ void __iomem *__arm_ioremap_pfn_caller(unsigned long pfn, unsigned long offset,
        return __arm_ioremap_pfn(pfn, offset, size, mtype);
 }
 
-void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size,
+void __iomem *__arm_ioremap(phys_addr_t phys_addr, size_t size,
                            unsigned int mtype)
 {
        return (void __iomem *)phys_addr;
 }
 EXPORT_SYMBOL(__arm_ioremap);
 
-void __iomem * (*arch_ioremap_caller)(unsigned long, size_t, unsigned int, void *);
+void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t, unsigned int, void *);
 
-void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
+void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
                                   unsigned int mtype, void *caller)
 {
        return __arm_ioremap(phys_addr, size, mtype);
index 919405e20b80e73272a519a7c3b377b9eccc2dd0..2d1ef87328a1783d309296a25889d8a37d2a9ae6 100644 (file)
@@ -140,8 +140,10 @@ ENTRY(cpu_v6_set_pte_ext)
 ENTRY(cpu_v6_do_suspend)
        stmfd   sp!, {r4 - r9, lr}
        mrc     p15, 0, r4, c13, c0, 0  @ FCSE/PID
+#ifdef CONFIG_MMU
        mrc     p15, 0, r5, c3, c0, 0   @ Domain ID
        mrc     p15, 0, r6, c2, c0, 1   @ Translation table base 1
+#endif
        mrc     p15, 0, r7, c1, c0, 1   @ auxiliary control register
        mrc     p15, 0, r8, c1, c0, 2   @ co-processor access control
        mrc     p15, 0, r9, c1, c0, 0   @ control register
@@ -158,14 +160,16 @@ ENTRY(cpu_v6_do_resume)
        mcr     p15, 0, ip, c13, c0, 1  @ set reserved context ID
        ldmia   r0, {r4 - r9}
        mcr     p15, 0, r4, c13, c0, 0  @ FCSE/PID
+#ifdef CONFIG_MMU
        mcr     p15, 0, r5, c3, c0, 0   @ Domain ID
        ALT_SMP(orr     r1, r1, #TTB_FLAGS_SMP)
        ALT_UP(orr      r1, r1, #TTB_FLAGS_UP)
        mcr     p15, 0, r1, c2, c0, 0   @ Translation table base 0
        mcr     p15, 0, r6, c2, c0, 1   @ Translation table base 1
+       mcr     p15, 0, ip, c2, c0, 2   @ TTB control register
+#endif
        mcr     p15, 0, r7, c1, c0, 1   @ auxiliary control register
        mcr     p15, 0, r8, c1, c0, 2   @ co-processor access control
-       mcr     p15, 0, ip, c2, c0, 2   @ TTB control register
        mcr     p15, 0, ip, c7, c5, 4   @ ISB
        mov     r0, r9                  @ control register
        b       cpu_resume_mmu
index 363027e811d6f5c803d7616c318d4aeab7bfb3e9..5ffe1956c6d95c5ba227986347caddec5d0dacda 100644 (file)
 #define TTB_FLAGS_SMP  (TTB_IRGN_WBWA|TTB_S|TTB_RGN_OC_WBWA)
 #define PMD_FLAGS_SMP  (PMD_SECT_WBWA|PMD_SECT_S)
 
+#ifndef __ARMEB__
+#  define rpgdl        r0
+#  define rpgdh        r1
+#else
+#  define rpgdl        r1
+#  define rpgdh        r0
+#endif
+
 /*
  * cpu_v7_switch_mm(pgd_phys, tsk)
  *
  */
 ENTRY(cpu_v7_switch_mm)
 #ifdef CONFIG_MMU
-       mmid    r1, r1                          @ get mm->context.id
-       asid    r3, r1
-       mov     r3, r3, lsl #(48 - 32)          @ ASID
-       mcrr    p15, 0, r0, r3, c2              @ set TTB 0
+       mmid    r2, r2
+       asid    r2, r2
+       orr     rpgdh, rpgdh, r2, lsl #(48 - 32)        @ upper 32-bits of pgd
+       mcrr    p15, 0, rpgdl, rpgdh, c2                @ set TTB 0
        isb
 #endif
        mov     pc, lr
@@ -106,7 +114,8 @@ ENDPROC(cpu_v7_set_pte_ext)
         */
        .macro  v7_ttb_setup, zero, ttbr0, ttbr1, tmp
        ldr     \tmp, =swapper_pg_dir           @ swapper_pg_dir virtual address
-       cmp     \ttbr1, \tmp                    @ PHYS_OFFSET > PAGE_OFFSET? (branch below)
+       mov     \tmp, \tmp, lsr #ARCH_PGD_SHIFT
+       cmp     \ttbr1, \tmp                    @ PHYS_OFFSET > PAGE_OFFSET?
        mrc     p15, 0, \tmp, c2, c0, 2         @ TTB control register
        orr     \tmp, \tmp, #TTB_EAE
        ALT_SMP(orr     \tmp, \tmp, #TTB_FLAGS_SMP)
@@ -114,27 +123,21 @@ ENDPROC(cpu_v7_set_pte_ext)
        ALT_SMP(orr     \tmp, \tmp, #TTB_FLAGS_SMP << 16)
        ALT_UP(orr      \tmp, \tmp, #TTB_FLAGS_UP << 16)
        /*
-        * TTBR0/TTBR1 split (PAGE_OFFSET):
-        *   0x40000000: T0SZ = 2, T1SZ = 0 (not used)
-        *   0x80000000: T0SZ = 0, T1SZ = 1
-        *   0xc0000000: T0SZ = 0, T1SZ = 2
-        *
-        * Only use this feature if PHYS_OFFSET <= PAGE_OFFSET, otherwise
-        * booting secondary CPUs would end up using TTBR1 for the identity
-        * mapping set up in TTBR0.
+        * Only use split TTBRs if PHYS_OFFSET <= PAGE_OFFSET (cmp above),
+        * otherwise booting secondary CPUs would end up using TTBR1 for the
+        * identity mapping set up in TTBR0.
         */
-       bhi     9001f                           @ PHYS_OFFSET > PAGE_OFFSET?
-       orr     \tmp, \tmp, #(((PAGE_OFFSET >> 30) - 1) << 16) @ TTBCR.T1SZ
-#if defined CONFIG_VMSPLIT_2G
-       /* PAGE_OFFSET == 0x80000000, T1SZ == 1 */
-       add     \ttbr1, \ttbr1, #1 << 4         @ skip two L1 entries
-#elif defined CONFIG_VMSPLIT_3G
-       /* PAGE_OFFSET == 0xc0000000, T1SZ == 2 */
-       add     \ttbr1, \ttbr1, #4096 * (1 + 3) @ only L2 used, skip pgd+3*pmd
-#endif
-       /* CONFIG_VMSPLIT_1G does not need TTBR1 adjustment */
-9001:  mcr     p15, 0, \tmp, c2, c0, 2         @ TTB control register
-       mcrr    p15, 1, \ttbr1, \zero, c2       @ load TTBR1
+       orrls   \tmp, \tmp, #TTBR1_SIZE                         @ TTBCR.T1SZ
+       mcr     p15, 0, \tmp, c2, c0, 2                         @ TTBCR
+       mov     \tmp, \ttbr1, lsr #(32 - ARCH_PGD_SHIFT)        @ upper bits
+       mov     \ttbr1, \ttbr1, lsl #ARCH_PGD_SHIFT             @ lower bits
+       addls   \ttbr1, \ttbr1, #TTBR1_OFFSET
+       mcrr    p15, 1, \ttbr1, \zero, c2                       @ load TTBR1
+       mov     \tmp, \ttbr0, lsr #(32 - ARCH_PGD_SHIFT)        @ upper bits
+       mov     \ttbr0, \ttbr0, lsl #ARCH_PGD_SHIFT             @ lower bits
+       mcrr    p15, 0, \ttbr0, \zero, c2                       @ load TTBR0
+       mcrr    p15, 1, \ttbr1, \zero, c2                       @ load TTBR1
+       mcrr    p15, 0, \ttbr0, \zero, c2                       @ load TTBR0
        .endm
 
        __CPUINIT
index e35fec34453ea13d57e2f1902a07bc99e21ba731..7ef3ad05df398656d2f63302139288154fa1abfd 100644 (file)
@@ -98,9 +98,11 @@ ENTRY(cpu_v7_do_suspend)
        mrc     p15, 0, r4, c13, c0, 0  @ FCSE/PID
        mrc     p15, 0, r5, c13, c0, 3  @ User r/o thread ID
        stmia   r0!, {r4 - r5}
+#ifdef CONFIG_MMU
        mrc     p15, 0, r6, c3, c0, 0   @ Domain ID
        mrc     p15, 0, r7, c2, c0, 1   @ TTB 1
        mrc     p15, 0, r11, c2, c0, 2  @ TTB control register
+#endif
        mrc     p15, 0, r8, c1, c0, 0   @ Control register
        mrc     p15, 0, r9, c1, c0, 1   @ Auxiliary control register
        mrc     p15, 0, r10, c1, c0, 2  @ Co-processor access control
@@ -110,13 +112,14 @@ ENDPROC(cpu_v7_do_suspend)
 
 ENTRY(cpu_v7_do_resume)
        mov     ip, #0
-       mcr     p15, 0, ip, c8, c7, 0   @ invalidate TLBs
        mcr     p15, 0, ip, c7, c5, 0   @ invalidate I cache
        mcr     p15, 0, ip, c13, c0, 1  @ set reserved context ID
        ldmia   r0!, {r4 - r5}
        mcr     p15, 0, r4, c13, c0, 0  @ FCSE/PID
        mcr     p15, 0, r5, c13, c0, 3  @ User r/o thread ID
        ldmia   r0, {r6 - r11}
+#ifdef CONFIG_MMU
+       mcr     p15, 0, ip, c8, c7, 0   @ invalidate TLBs
        mcr     p15, 0, r6, c3, c0, 0   @ Domain ID
 #ifndef CONFIG_ARM_LPAE
        ALT_SMP(orr     r1, r1, #TTB_FLAGS_SMP)
@@ -125,14 +128,15 @@ ENTRY(cpu_v7_do_resume)
        mcr     p15, 0, r1, c2, c0, 0   @ TTB 0
        mcr     p15, 0, r7, c2, c0, 1   @ TTB 1
        mcr     p15, 0, r11, c2, c0, 2  @ TTB control register
-       mrc     p15, 0, r4, c1, c0, 1   @ Read Auxiliary control register
-       teq     r4, r9                  @ Is it already set?
-       mcrne   p15, 0, r9, c1, c0, 1   @ No, so write it
-       mcr     p15, 0, r10, c1, c0, 2  @ Co-processor access control
        ldr     r4, =PRRR               @ PRRR
        ldr     r5, =NMRR               @ NMRR
        mcr     p15, 0, r4, c10, c2, 0  @ write PRRR
        mcr     p15, 0, r5, c10, c2, 1  @ write NMRR
+#endif /* CONFIG_MMU */
+       mrc     p15, 0, r4, c1, c0, 1   @ Read Auxiliary control register
+       teq     r4, r9                  @ Is it already set?
+       mcrne   p15, 0, r9, c1, c0, 1   @ No, so write it
+       mcr     p15, 0, r10, c1, c0, 2  @ Co-processor access control
        isb
        dsb
        mov     r0, r8                  @ control register
@@ -178,7 +182,8 @@ ENDPROC(cpu_pj4b_do_idle)
  */
 __v7_ca5mp_setup:
 __v7_ca9mp_setup:
-       mov     r10, #(1 << 0)                  @ TLB ops broadcasting
+__v7_cr7mp_setup:
+       mov     r10, #(1 << 0)                  @ Cache/TLB ops broadcasting
        b       1f
 __v7_ca7mp_setup:
 __v7_ca15mp_setup:
@@ -442,6 +447,16 @@ __v7_pj4b_proc_info:
        .size   __v7_pj4b_proc_info, . - __v7_pj4b_proc_info
 #endif
 
+       /*
+        * ARM Ltd. Cortex R7 processor.
+        */
+       .type   __v7_cr7mp_proc_info, #object
+__v7_cr7mp_proc_info:
+       .long   0x410fc170
+       .long   0xff0ffff0
+       __v7_proc __v7_cr7mp_setup
+       .size   __v7_cr7mp_proc_info, . - __v7_cr7mp_proc_info
+
        /*
         * ARM Ltd. Cortex A7 processor.
         */
index 1ff6a37e893c423da523a945e0cf7c5d8f837152..a4d1f8de3b5b23453ee4738723164a5ba8405424 100644 (file)
@@ -192,12 +192,10 @@ static int __init iop3xx_adma_cap_init(void)
 
        #ifdef CONFIG_ARCH_IOP32X /* the 32x AAU does not perform zero sum */
        dma_cap_set(DMA_XOR, iop3xx_aau_data.cap_mask);
-       dma_cap_set(DMA_MEMSET, iop3xx_aau_data.cap_mask);
        dma_cap_set(DMA_INTERRUPT, iop3xx_aau_data.cap_mask);
        #else
        dma_cap_set(DMA_XOR, iop3xx_aau_data.cap_mask);
        dma_cap_set(DMA_XOR_VAL, iop3xx_aau_data.cap_mask);
-       dma_cap_set(DMA_MEMSET, iop3xx_aau_data.cap_mask);
        dma_cap_set(DMA_INTERRUPT, iop3xx_aau_data.cap_mask);
        #endif
 
index c019b7aaf776b7d622aa5c97146070aee57ef523..c66d163d7a2a25084179e71e6a2d57f8e04263ff 100644 (file)
@@ -666,14 +666,9 @@ void __init orion_xor0_init(unsigned long mapbase_low,
        orion_xor0_shared_resources[3].start = irq_1;
        orion_xor0_shared_resources[3].end = irq_1;
 
-       /*
-        * two engines can't do memset simultaneously, this limitation
-        * satisfied by removing memset support from one of the engines.
-        */
        dma_cap_set(DMA_MEMCPY, orion_xor0_channels_data[0].cap_mask);
        dma_cap_set(DMA_XOR, orion_xor0_channels_data[0].cap_mask);
 
-       dma_cap_set(DMA_MEMSET, orion_xor0_channels_data[1].cap_mask);
        dma_cap_set(DMA_MEMCPY, orion_xor0_channels_data[1].cap_mask);
        dma_cap_set(DMA_XOR, orion_xor0_channels_data[1].cap_mask);
 
@@ -732,14 +727,9 @@ void __init orion_xor1_init(unsigned long mapbase_low,
        orion_xor1_shared_resources[3].start = irq_1;
        orion_xor1_shared_resources[3].end = irq_1;
 
-       /*
-        * two engines can't do memset simultaneously, this limitation
-        * satisfied by removing memset support from one of the engines.
-        */
        dma_cap_set(DMA_MEMCPY, orion_xor1_channels_data[0].cap_mask);
        dma_cap_set(DMA_XOR, orion_xor1_channels_data[0].cap_mask);
 
-       dma_cap_set(DMA_MEMSET, orion_xor1_channels_data[1].cap_mask);
        dma_cap_set(DMA_MEMCPY, orion_xor1_channels_data[1].cap_mask);
        dma_cap_set(DMA_XOR, orion_xor1_channels_data[1].cap_mask);
 
index 249fe6333e180b8240b1734c7066957fdf4c9e41..6816192a7561b41941b403964008f46da0803da5 100644 (file)
@@ -426,7 +426,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
                if (!(cause & (1 << i)))
                        continue;
 
-               type = irqd_get_trigger_type(irq_get_irq_data(irq));
+               type = irq_get_trigger_type(irq);
                if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
                        /* Swap polarity (race with GPIO line) */
                        u32 polarity;
index d7e17150028a678f1a9042a921a77f48b9d7681e..7231c8e4975e5ed2a15d9124531b1f8240fa91dd 100644 (file)
@@ -285,7 +285,7 @@ static inline int s3c_cpufreq_addfreq(struct cpufreq_frequency_table *table,
                s3c_freq_dbg("%s: { %d = %u kHz }\n",
                             __func__, index, freq);
 
-               table[index].index = index;
+               table[index].driver_data = index;
                table[index].frequency = freq;
        }
 
index b178d44e9eaa897c8f8a3a4bb017198cb7014cae..2677bc3762d7ce418b4c116b709dadf0f8e53697 100644 (file)
@@ -11,8 +11,6 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 
-       __INIT
-
 /*
  * Realview/Versatile Express specific entry point for secondary CPUs.
  * This provides a "holding pen" into which all secondary cores are held
index 56b3f6d447ae10b8d53f9cfb767826fe90a97c11..4143d9b0d87af3e511a5324c6528a3150f2046a2 100644 (file)
@@ -7,6 +7,7 @@ config ARM64
        select ARM_AMBA
        select ARM_ARCH_TIMER
        select ARM_GIC
+       select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS
        select COMMON_CLK
        select GENERIC_CLOCKEVENTS
@@ -111,6 +112,11 @@ config ARCH_VEXPRESS
          This enables support for the ARMv8 software model (Versatile
          Express).
 
+config ARCH_XGENE
+       bool "AppliedMicro X-Gene SOC Family"
+       help
+         This enables support for AppliedMicro X-Gene SOC Family
+
 endmenu
 
 menu "Bus support"
@@ -148,6 +154,8 @@ config NR_CPUS
        int "Maximum number of CPUs (2-32)"
        range 2 32
        depends on SMP
+       # These have to remain sorted largest to smallest
+       default "8" if ARCH_XGENE
        default "4"
 
 source kernel/Kconfig.preempt
@@ -180,8 +188,35 @@ config HW_PERF_EVENTS
          Enable hardware performance counter support for perf events. If
          disabled, perf events will use software events only.
 
+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_64K_PAGES
+
+config HAVE_ARCH_TRANSPARENT_HUGEPAGE
+       def_bool y
+
 source "mm/Kconfig"
 
+config XEN_DOM0
+       def_bool y
+       depends on XEN
+
+config XEN
+       bool "Xen guest support on ARM64 (EXPERIMENTAL)"
+       depends on ARM64 && OF
+       help
+         Say Y if you want to run Linux in a Virtual Machine on Xen on ARM64.
+
+config FORCE_MAX_ZONEORDER
+       int
+       default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE)
+       default "11"
+
 endmenu
 
 menu "Boot options"
index c95c5cb212fd65b49f3fe801466fae90ea2f6739..d90cf79f233a952cf8a164ce78deffea7b65cace 100644 (file)
@@ -37,6 +37,8 @@ TEXT_OFFSET := 0x00080000
 export TEXT_OFFSET GZFLAGS
 
 core-y         += arch/arm64/kernel/ arch/arm64/mm/
+core-$(CONFIG_KVM) += arch/arm64/kvm/
+core-$(CONFIG_XEN) += arch/arm64/xen/
 libs-y         := arch/arm64/lib/ $(libs-y)
 libs-y         += $(LIBGCC)
 
@@ -60,6 +62,10 @@ zinstall install: vmlinux
 dtbs: scripts
        $(Q)$(MAKE) $(build)=$(boot)/dts dtbs
 
+PHONY += vdso_install
+vdso_install:
+       $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@
+
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
index 68457e9e0975bc37b57818a8b18cbe7268191e5c..c52bdb051f664b64568d4a9bfddca2c43b8aa7f0 100644 (file)
@@ -1,4 +1,5 @@
 dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb
+dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb
 
 targets += dtbs
 targets += $(dtb-y)
diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts
new file mode 100644 (file)
index 0000000..1247ca1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * dts file for AppliedMicro (APM) Mustang Board
+ *
+ * Copyright (C) 2013, Applied Micro Circuits Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+/dts-v1/;
+
+/include/ "apm-storm.dtsi"
+
+/ {
+       model = "APM X-Gene Mustang board";
+       compatible = "apm,mustang", "apm,xgene-storm";
+
+       chosen { };
+
+       memory {
+               device_type = "memory";
+               reg = < 0x1 0x00000000 0x0 0x80000000 >; /* Updated by bootloader */
+       };
+};
diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
new file mode 100644 (file)
index 0000000..bfdc578
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * dts file for AppliedMicro (APM) X-Gene Storm SOC
+ *
+ * Copyright (C) 2013, Applied Micro Circuits Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+/ {
+       compatible = "apm,xgene-storm";
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cpus {
+               #address-cells = <2>;
+               #size-cells = <0>;
+
+               cpu@000 {
+                       device_type = "cpu";
+                       compatible = "apm,potenza", "arm,armv8";
+                       reg = <0x0 0x000>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x1 0x0000fff8>;
+               };
+               cpu@001 {
+                       device_type = "cpu";
+                       compatible = "apm,potenza", "arm,armv8";
+                       reg = <0x0 0x001>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x1 0x0000fff8>;
+               };
+               cpu@100 {
+                       device_type = "cpu";
+                       compatible = "apm,potenza", "arm,armv8";
+                       reg = <0x0 0x100>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x1 0x0000fff8>;
+               };
+               cpu@101 {
+                       device_type = "cpu";
+                       compatible = "apm,potenza", "arm,armv8";
+                       reg = <0x0 0x101>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x1 0x0000fff8>;
+               };
+               cpu@200 {
+                       device_type = "cpu";
+                       compatible = "apm,potenza", "arm,armv8";
+                       reg = <0x0 0x200>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x1 0x0000fff8>;
+               };
+               cpu@201 {
+                       device_type = "cpu";
+                       compatible = "apm,potenza", "arm,armv8";
+                       reg = <0x0 0x201>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x1 0x0000fff8>;
+               };
+               cpu@300 {
+                       device_type = "cpu";
+                       compatible = "apm,potenza", "arm,armv8";
+                       reg = <0x0 0x300>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x1 0x0000fff8>;
+               };
+               cpu@301 {
+                       device_type = "cpu";
+                       compatible = "apm,potenza", "arm,armv8";
+                       reg = <0x0 0x301>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x1 0x0000fff8>;
+               };
+       };
+
+       gic: interrupt-controller@78010000 {
+               compatible = "arm,cortex-a15-gic";
+               #interrupt-cells = <3>;
+               interrupt-controller;
+               reg = <0x0 0x78010000 0x0 0x1000>,      /* GIC Dist */
+                     <0x0 0x78020000 0x0 0x1000>,      /* GIC CPU */
+                     <0x0 0x78040000 0x0 0x2000>,      /* GIC VCPU Control */
+                     <0x0 0x78060000 0x0 0x2000>;      /* GIC VCPU */
+               interrupts = <1 9 0xf04>;       /* GIC Maintenence IRQ */
+       };
+
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <1 0 0xff01>,      /* Secure Phys IRQ */
+                            <1 13 0xff01>,     /* Non-secure Phys IRQ */
+                            <1 14 0xff01>,     /* Virt IRQ */
+                            <1 15 0xff01>;     /* Hyp IRQ */
+               clock-frequency = <50000000>;
+       };
+
+       soc {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               serial0: serial@1c020000 {
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0 0x1c020000 0x0 0x1000>;
+                       reg-shift = <2>;
+                       clock-frequency = <10000000>; /* Updated by bootloader */
+                       interrupt-parent = <&gic>;
+                       interrupts = <0x0 0x4c 0x4>;
+               };
+       };
+};
index 8d9696adb44031626733c6c0f8435dea3c4a024e..5b3e83217b03b1e255c23347fcc4d06859cba9c1 100644 (file)
@@ -24,6 +24,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
 CONFIG_ARCH_VEXPRESS=y
+CONFIG_ARCH_XGENE=y
 CONFIG_SMP=y
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_CMDLINE="console=ttyAMA0"
@@ -54,6 +55,9 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_SERIO_I8042 is not set
 # CONFIG_SERIO_SERPORT is not set
 CONFIG_LEGACY_PTY_COUNT=16
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
index bf6ab242f04725e56e8cf93d3ab6e930668651f0..d56ed11ba9a387be20f835d5f7675f9e95eb4574 100644 (file)
@@ -110,16 +110,6 @@ static inline void __cpuinit arch_counter_set_user_access(void)
        asm volatile("msr       cntkctl_el1, %0" : : "r" (cntkctl));
 }
 
-static inline u64 arch_counter_get_cntpct(void)
-{
-       u64 cval;
-
-       isb();
-       asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
-
-       return cval;
-}
-
 static inline u64 arch_counter_get_cntvct(void)
 {
        u64 cval;
index 3300cbd18a89b504939c7b2530040f8bdd159ebf..fea9ee32720678b348685ef4803bb2c622c3eb8e 100644 (file)
@@ -123,9 +123,6 @@ static inline void __flush_icache_all(void)
 #define flush_dcache_mmap_unlock(mapping) \
        spin_unlock_irq(&(mapping)->tree_lock)
 
-#define flush_icache_user_range(vma,page,addr,len) \
-       flush_dcache_page(page)
-
 /*
  * We don't appear to need to do anything here.  In fact, if we did, we'd
  * duplicate cache flushing elsewhere performed by flush_dcache_page().
index cf2749488cd4a40545a31792689fbca63d7756c3..5fe138e0b828f130e55bd93b56e9d9e8492f1060 100644 (file)
 })
 
 #define ARM_CPU_IMP_ARM                0x41
+#define ARM_CPU_IMP_APM                0x50
 
 #define ARM_CPU_PART_AEM_V8    0xD0F0
 #define ARM_CPU_PART_FOUNDATION        0xD000
 #define ARM_CPU_PART_CORTEX_A57        0xD070
 
+#define APM_CPU_PART_POTENZA   0x0000
+
 #ifndef __ASSEMBLY__
 
 /*
index 7eaa0b302493491b781b0a8c432b66bdac57fd43..ef8235c68c092674ed0c628733bbc7a6b02404b5 100644 (file)
@@ -83,6 +83,15 @@ static inline int reinstall_suspended_bps(struct pt_regs *regs)
 }
 #endif
 
+#ifdef CONFIG_COMPAT
+int aarch32_break_handler(struct pt_regs *regs);
+#else
+static int aarch32_break_handler(struct pt_regs *regs)
+{
+       return -EFAULT;
+}
+#endif
+
 #endif /* __ASSEMBLY */
 #endif /* __KERNEL__ */
 #endif /* __ASM_DEBUG_MONITORS_H */
index 0d8453c755a8acb57593beb5c8afcda29e197f95..cf98b362094b22f232f042817f6a72ed2bac5dfb 100644 (file)
@@ -18,6 +18,9 @@
 
 struct dev_archdata {
        struct dma_map_ops *dma_ops;
+#ifdef CONFIG_IOMMU_API
+       void *iommu;                    /* private IOMMU data */
+#endif
 };
 
 struct pdev_archdata {
index 99477689419849822602f0b152650d88dd18f241..8d1810001aeffc0be57b9edc5919941f8a49e91a 100644 (file)
@@ -81,8 +81,12 @@ static inline void dma_mark_clean(void *addr, size_t size)
 {
 }
 
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-                                      dma_addr_t *dma_handle, gfp_t flags)
+#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL)
+#define dma_free_coherent(d, s, h, f)  dma_free_attrs(d, s, h, f, NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+                                   dma_addr_t *dma_handle, gfp_t flags,
+                                   struct dma_attrs *attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
        void *vaddr;
@@ -90,13 +94,14 @@ static inline void *dma_alloc_coherent(struct device *dev, size_t size,
        if (dma_alloc_from_coherent(dev, size, dma_handle, &vaddr))
                return vaddr;
 
-       vaddr = ops->alloc(dev, size, dma_handle, flags, NULL);
+       vaddr = ops->alloc(dev, size, dma_handle, flags, attrs);
        debug_dma_alloc_coherent(dev, size, *dma_handle, vaddr);
        return vaddr;
 }
 
-static inline void dma_free_coherent(struct device *dev, size_t size,
-                                    void *vaddr, dma_addr_t dev_addr)
+static inline void dma_free_attrs(struct device *dev, size_t size,
+                                 void *vaddr, dma_addr_t dev_addr,
+                                 struct dma_attrs *attrs)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
 
@@ -104,7 +109,7 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
                return;
 
        debug_dma_free_coherent(dev, size, vaddr, dev_addr);
-       ops->free(dev, size, vaddr, dev_addr, NULL);
+       ops->free(dev, size, vaddr, dev_addr, attrs);
 }
 
 /*
diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h
new file mode 100644 (file)
index 0000000..5b7ca8a
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * arch/arm64/include/asm/hugetlb.h
+ *
+ * Copyright (C) 2013 Linaro Ltd.
+ *
+ * Based on arch/x86/include/asm/hugetlb.h
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_HUGETLB_H
+#define __ASM_HUGETLB_H
+
+#include <asm-generic/hugetlb.h>
+#include <asm/page.h>
+
+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,
+                                         unsigned long floor,
+                                         unsigned long ceiling)
+{
+       free_pgd_range(tlb, addr, end, floor, ceiling);
+}
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+                                        unsigned long addr, unsigned long len)
+{
+       return 0;
+}
+
+static inline int prepare_hugepage_range(struct file *file,
+                                        unsigned long addr, unsigned long len)
+{
+       struct hstate *h = hstate_file(file);
+       if (len & ~huge_page_mask(h))
+               return -EINVAL;
+       if (addr & ~huge_page_mask(h))
+               return -EINVAL;
+       return 0;
+}
+
+static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
+{
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+       return pte_none(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+       return pte_wrprotect(pte);
+}
+
+static inline int arch_prepare_hugepage(struct page *page)
+{
+       return 0;
+}
+
+static inline void arch_release_hugepage(struct page *page)
+{
+}
+
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+       clear_bit(PG_dcache_clean, &page->flags);
+}
+
+#endif /* __ASM_HUGETLB_H */
diff --git a/arch/arm64/include/asm/hypervisor.h b/arch/arm64/include/asm/hypervisor.h
new file mode 100644 (file)
index 0000000..d2c7904
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ASM_ARM64_HYPERVISOR_H
+#define _ASM_ARM64_HYPERVISOR_H
+
+#include <asm/xen/hypervisor.h>
+
+#endif
index 2e12258aa7e47c110729c25265cfa6cae50e99c9..1d12f89140ba0a24bf1975b5425490b7dffb1fc9 100644 (file)
@@ -228,10 +228,12 @@ extern void __iounmap(volatile void __iomem *addr);
 #define PROT_DEFAULT           (PTE_TYPE_PAGE | PTE_AF | PTE_DIRTY)
 #define PROT_DEVICE_nGnRE      (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE))
 #define PROT_NORMAL_NC         (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL_NC))
+#define PROT_NORMAL            (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
 
 #define ioremap(addr, size)            __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
 #define ioremap_nocache(addr, size)    __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
 #define ioremap_wc(addr, size)         __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
+#define ioremap_cached(addr, size)     __ioremap((addr), (size), __pgprot(PROT_NORMAL))
 #define iounmap                                __iounmap
 
 #define PROT_SECT_DEFAULT      (PMD_TYPE_SECT | PMD_SECT_AF)
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
new file mode 100644 (file)
index 0000000..a5f28e2
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * 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/>.
+ */
+
+#ifndef __ARM64_KVM_ARM_H__
+#define __ARM64_KVM_ARM_H__
+
+#include <asm/types.h>
+
+/* Hyp Configuration Register (HCR) bits */
+#define HCR_ID         (UL(1) << 33)
+#define HCR_CD         (UL(1) << 32)
+#define HCR_RW_SHIFT   31
+#define HCR_RW         (UL(1) << HCR_RW_SHIFT)
+#define HCR_TRVM       (UL(1) << 30)
+#define HCR_HCD                (UL(1) << 29)
+#define HCR_TDZ                (UL(1) << 28)
+#define HCR_TGE                (UL(1) << 27)
+#define HCR_TVM                (UL(1) << 26)
+#define HCR_TTLB       (UL(1) << 25)
+#define HCR_TPU                (UL(1) << 24)
+#define HCR_TPC                (UL(1) << 23)
+#define HCR_TSW                (UL(1) << 22)
+#define HCR_TAC                (UL(1) << 21)
+#define HCR_TIDCP      (UL(1) << 20)
+#define HCR_TSC                (UL(1) << 19)
+#define HCR_TID3       (UL(1) << 18)
+#define HCR_TID2       (UL(1) << 17)
+#define HCR_TID1       (UL(1) << 16)
+#define HCR_TID0       (UL(1) << 15)
+#define HCR_TWE                (UL(1) << 14)
+#define HCR_TWI                (UL(1) << 13)
+#define HCR_DC         (UL(1) << 12)
+#define HCR_BSU                (3 << 10)
+#define HCR_BSU_IS     (UL(1) << 10)
+#define HCR_FB         (UL(1) << 9)
+#define HCR_VA         (UL(1) << 8)
+#define HCR_VI         (UL(1) << 7)
+#define HCR_VF         (UL(1) << 6)
+#define HCR_AMO                (UL(1) << 5)
+#define HCR_IMO                (UL(1) << 4)
+#define HCR_FMO                (UL(1) << 3)
+#define HCR_PTW                (UL(1) << 2)
+#define HCR_SWIO       (UL(1) << 1)
+#define HCR_VM         (UL(1) << 0)
+
+/*
+ * The bits we set in HCR:
+ * RW:         64bit by default, can be overriden for 32bit VMs
+ * TAC:                Trap ACTLR
+ * TSC:                Trap SMC
+ * TSW:                Trap cache operations by set/way
+ * TWI:                Trap WFI
+ * TIDCP:      Trap L2CTLR/L2ECTLR
+ * BSU_IS:     Upgrade barriers to the inner shareable domain
+ * FB:         Force broadcast of all maintainance operations
+ * AMO:                Override CPSR.A and enable signaling with VA
+ * IMO:                Override CPSR.I and enable signaling with VI
+ * FMO:                Override CPSR.F and enable signaling with VF
+ * SWIO:       Turn set/way invalidates into set/way clean+invalidate
+ */
+#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
+                        HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
+                        HCR_SWIO | HCR_TIDCP | HCR_RW)
+#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
+
+/* Hyp System Control Register (SCTLR_EL2) bits */
+#define SCTLR_EL2_EE   (1 << 25)
+#define SCTLR_EL2_WXN  (1 << 19)
+#define SCTLR_EL2_I    (1 << 12)
+#define SCTLR_EL2_SA   (1 << 3)
+#define SCTLR_EL2_C    (1 << 2)
+#define SCTLR_EL2_A    (1 << 1)
+#define SCTLR_EL2_M    1
+#define SCTLR_EL2_FLAGS        (SCTLR_EL2_M | SCTLR_EL2_A | SCTLR_EL2_C |      \
+                        SCTLR_EL2_SA | SCTLR_EL2_I)
+
+/* TCR_EL2 Registers bits */
+#define TCR_EL2_TBI    (1 << 20)
+#define TCR_EL2_PS     (7 << 16)
+#define TCR_EL2_PS_40B (2 << 16)
+#define TCR_EL2_TG0    (1 << 14)
+#define TCR_EL2_SH0    (3 << 12)
+#define TCR_EL2_ORGN0  (3 << 10)
+#define TCR_EL2_IRGN0  (3 << 8)
+#define TCR_EL2_T0SZ   0x3f
+#define TCR_EL2_MASK   (TCR_EL2_TG0 | TCR_EL2_SH0 | \
+                        TCR_EL2_ORGN0 | TCR_EL2_IRGN0 | TCR_EL2_T0SZ)
+
+#define TCR_EL2_FLAGS  (TCR_EL2_PS_40B)
+
+/* VTCR_EL2 Registers bits */
+#define VTCR_EL2_PS_MASK       (7 << 16)
+#define VTCR_EL2_PS_40B                (2 << 16)
+#define VTCR_EL2_TG0_MASK      (1 << 14)
+#define VTCR_EL2_TG0_4K                (0 << 14)
+#define VTCR_EL2_TG0_64K       (1 << 14)
+#define VTCR_EL2_SH0_MASK      (3 << 12)
+#define VTCR_EL2_SH0_INNER     (3 << 12)
+#define VTCR_EL2_ORGN0_MASK    (3 << 10)
+#define VTCR_EL2_ORGN0_WBWA    (1 << 10)
+#define VTCR_EL2_IRGN0_MASK    (3 << 8)
+#define VTCR_EL2_IRGN0_WBWA    (1 << 8)
+#define VTCR_EL2_SL0_MASK      (3 << 6)
+#define VTCR_EL2_SL0_LVL1      (1 << 6)
+#define VTCR_EL2_T0SZ_MASK     0x3f
+#define VTCR_EL2_T0SZ_40B      24
+
+#ifdef CONFIG_ARM64_64K_PAGES
+/*
+ * Stage2 translation configuration:
+ * 40bits output (PS = 2)
+ * 40bits input  (T0SZ = 24)
+ * 64kB pages (TG0 = 1)
+ * 2 level page tables (SL = 1)
+ */
+#define VTCR_EL2_FLAGS         (VTCR_EL2_PS_40B | VTCR_EL2_TG0_64K | \
+                                VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
+                                VTCR_EL2_IRGN0_WBWA | VTCR_EL2_SL0_LVL1 | \
+                                VTCR_EL2_T0SZ_40B)
+#define VTTBR_X                (38 - VTCR_EL2_T0SZ_40B)
+#else
+/*
+ * Stage2 translation configuration:
+ * 40bits output (PS = 2)
+ * 40bits input  (T0SZ = 24)
+ * 4kB pages (TG0 = 0)
+ * 3 level page tables (SL = 1)
+ */
+#define VTCR_EL2_FLAGS         (VTCR_EL2_PS_40B | VTCR_EL2_TG0_4K | \
+                                VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
+                                VTCR_EL2_IRGN0_WBWA | VTCR_EL2_SL0_LVL1 | \
+                                VTCR_EL2_T0SZ_40B)
+#define VTTBR_X                (37 - VTCR_EL2_T0SZ_40B)
+#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)
+
+/* Hyp System Trap Register */
+#define HSTR_EL2_TTEE  (1 << 16)
+#define HSTR_EL2_T(x)  (1 << x)
+
+/* Hyp Coprocessor Trap Register */
+#define CPTR_EL2_TCPAC (1 << 31)
+#define CPTR_EL2_TTA   (1 << 20)
+#define CPTR_EL2_TFP   (1 << 10)
+
+/* Hyp Debug Configuration Register bits */
+#define MDCR_EL2_TDRA          (1 << 11)
+#define MDCR_EL2_TDOSA         (1 << 10)
+#define MDCR_EL2_TDA           (1 << 9)
+#define MDCR_EL2_TDE           (1 << 8)
+#define MDCR_EL2_HPME          (1 << 7)
+#define MDCR_EL2_TPM           (1 << 6)
+#define MDCR_EL2_TPMCR         (1 << 5)
+#define MDCR_EL2_HPMN_MASK     (0x1F)
+
+/* Exception Syndrome Register (ESR) bits */
+#define ESR_EL2_EC_SHIFT       (26)
+#define ESR_EL2_EC             (0x3fU << ESR_EL2_EC_SHIFT)
+#define ESR_EL2_IL             (1U << 25)
+#define ESR_EL2_ISS            (ESR_EL2_IL - 1)
+#define ESR_EL2_ISV_SHIFT      (24)
+#define ESR_EL2_ISV            (1U << ESR_EL2_ISV_SHIFT)
+#define ESR_EL2_SAS_SHIFT      (22)
+#define ESR_EL2_SAS            (3U << ESR_EL2_SAS_SHIFT)
+#define ESR_EL2_SSE            (1 << 21)
+#define ESR_EL2_SRT_SHIFT      (16)
+#define ESR_EL2_SRT_MASK       (0x1f << ESR_EL2_SRT_SHIFT)
+#define ESR_EL2_SF             (1 << 15)
+#define ESR_EL2_AR             (1 << 14)
+#define ESR_EL2_EA             (1 << 9)
+#define ESR_EL2_CM             (1 << 8)
+#define ESR_EL2_S1PTW          (1 << 7)
+#define ESR_EL2_WNR            (1 << 6)
+#define ESR_EL2_FSC            (0x3f)
+#define ESR_EL2_FSC_TYPE       (0x3c)
+
+#define ESR_EL2_CV_SHIFT       (24)
+#define ESR_EL2_CV             (1U << ESR_EL2_CV_SHIFT)
+#define ESR_EL2_COND_SHIFT     (20)
+#define ESR_EL2_COND           (0xfU << ESR_EL2_COND_SHIFT)
+
+
+#define FSC_FAULT      (0x04)
+#define FSC_PERM       (0x0c)
+
+/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
+#define HPFAR_MASK     (~0xFUL)
+
+#define ESR_EL2_EC_UNKNOWN     (0x00)
+#define ESR_EL2_EC_WFI         (0x01)
+#define ESR_EL2_EC_CP15_32     (0x03)
+#define ESR_EL2_EC_CP15_64     (0x04)
+#define ESR_EL2_EC_CP14_MR     (0x05)
+#define ESR_EL2_EC_CP14_LS     (0x06)
+#define ESR_EL2_EC_FP_ASIMD    (0x07)
+#define ESR_EL2_EC_CP10_ID     (0x08)
+#define ESR_EL2_EC_CP14_64     (0x0C)
+#define ESR_EL2_EC_ILL_ISS     (0x0E)
+#define ESR_EL2_EC_SVC32       (0x11)
+#define ESR_EL2_EC_HVC32       (0x12)
+#define ESR_EL2_EC_SMC32       (0x13)
+#define ESR_EL2_EC_SVC64       (0x15)
+#define ESR_EL2_EC_HVC64       (0x16)
+#define ESR_EL2_EC_SMC64       (0x17)
+#define ESR_EL2_EC_SYS64       (0x18)
+#define ESR_EL2_EC_IABT                (0x20)
+#define ESR_EL2_EC_IABT_HYP    (0x21)
+#define ESR_EL2_EC_PC_ALIGN    (0x22)
+#define ESR_EL2_EC_DABT                (0x24)
+#define ESR_EL2_EC_DABT_HYP    (0x25)
+#define ESR_EL2_EC_SP_ALIGN    (0x26)
+#define ESR_EL2_EC_FP_EXC32    (0x28)
+#define ESR_EL2_EC_FP_EXC64    (0x2C)
+#define ESR_EL2_EC_SERRROR     (0x2F)
+#define ESR_EL2_EC_BREAKPT     (0x30)
+#define ESR_EL2_EC_BREAKPT_HYP (0x31)
+#define ESR_EL2_EC_SOFTSTP     (0x32)
+#define ESR_EL2_EC_SOFTSTP_HYP (0x33)
+#define ESR_EL2_EC_WATCHPT     (0x34)
+#define ESR_EL2_EC_WATCHPT_HYP (0x35)
+#define ESR_EL2_EC_BKPT32      (0x38)
+#define ESR_EL2_EC_VECTOR32    (0x3A)
+#define ESR_EL2_EC_BRK64       (0x3C)
+
+#define ESR_EL2_EC_xABT_xFSR_EXTABT    0x10
+
+#endif /* __ARM64_KVM_ARM_H__ */
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
new file mode 100644 (file)
index 0000000..c92de41
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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/>.
+ */
+
+#ifndef __ARM_KVM_ASM_H__
+#define __ARM_KVM_ASM_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       /* Auxilliary 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) */
+/* 32bit specific registers. Keep them at the end of the range */
+#define        DACR32_EL2      21      /* Domain Access Control Register */
+#define        IFSR32_EL2      22      /* Instruction Fault Status Register */
+#define        FPEXC32_EL2     23      /* Floating-Point Exception Control Register */
+#define        DBGVCR32_EL2    24      /* Debug Vector Catch Register */
+#define        TEECR32_EL1     25      /* ThumbEE Configuration Register */
+#define        TEEHBR32_EL1    26      /* ThumbEE Handler Base Register */
+#define        NR_SYS_REGS     27
+
+/* 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 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_AMAIR      (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
+#define c14_CNTKCTL    (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
+#define NR_CP15_REGS   (NR_SYS_REGS * 2)
+
+#define ARM_EXCEPTION_IRQ        0
+#define ARM_EXCEPTION_TRAP       1
+
+#ifndef __ASSEMBLY__
+struct kvm;
+struct kvm_vcpu;
+
+extern char __kvm_hyp_init[];
+extern char __kvm_hyp_init_end[];
+
+extern char __kvm_hyp_vector[];
+
+extern char __kvm_hyp_code_start[];
+extern char __kvm_hyp_code_end[];
+
+extern void __kvm_flush_vm_context(void);
+extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
+
+extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+#endif
+
+#endif /* __ARM_KVM_ASM_H__ */
diff --git a/arch/arm64/include/asm/kvm_coproc.h b/arch/arm64/include/asm/kvm_coproc.h
new file mode 100644 (file)
index 0000000..9a59301
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/include/asm/kvm_coproc.h
+ * Copyright (C) 2012 Rusty Russell IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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_COPROC_H__
+#define __ARM64_KVM_COPROC_H__
+
+#include <linux/kvm_host.h>
+
+void kvm_reset_sys_regs(struct kvm_vcpu *vcpu);
+
+struct kvm_sys_reg_table {
+       const struct sys_reg_desc *table;
+       size_t num;
+};
+
+struct kvm_sys_reg_target_table {
+       struct kvm_sys_reg_table table64;
+       struct kvm_sys_reg_table table32;
+};
+
+void kvm_register_target_sys_reg_table(unsigned int target,
+                                      struct kvm_sys_reg_target_table *table);
+
+int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run);
+
+#define kvm_coproc_table_init kvm_sys_reg_table_init
+void kvm_sys_reg_table_init(void);
+
+struct kvm_one_reg;
+int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
+int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
+int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
+unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu);
+
+#endif /* __ARM64_KVM_COPROC_H__ */
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
new file mode 100644 (file)
index 0000000..eec0738
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/include/kvm_emulate.h
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.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_EMULATE_H__
+#define __ARM64_KVM_EMULATE_H__
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmio.h>
+#include <asm/ptrace.h>
+
+unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
+unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu);
+
+bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
+void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
+
+void kvm_inject_undefined(struct kvm_vcpu *vcpu);
+void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
+void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
+
+static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
+{
+       return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
+}
+
+static inline unsigned long *vcpu_elr_el1(const struct kvm_vcpu *vcpu)
+{
+       return (unsigned long *)&vcpu_gp_regs(vcpu)->elr_el1;
+}
+
+static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
+{
+       return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
+}
+
+static inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
+{
+       return !!(*vcpu_cpsr(vcpu) & PSR_MODE32_BIT);
+}
+
+static inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
+{
+       if (vcpu_mode_is_32bit(vcpu))
+               return kvm_condition_valid32(vcpu);
+
+       return true;
+}
+
+static inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
+{
+       if (vcpu_mode_is_32bit(vcpu))
+               kvm_skip_instr32(vcpu, is_wide_instr);
+       else
+               *vcpu_pc(vcpu) += 4;
+}
+
+static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
+{
+       *vcpu_cpsr(vcpu) |= COMPAT_PSR_T_BIT;
+}
+
+static inline unsigned long *vcpu_reg(const struct kvm_vcpu *vcpu, u8 reg_num)
+{
+       if (vcpu_mode_is_32bit(vcpu))
+               return vcpu_reg32(vcpu, reg_num);
+
+       return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.regs[reg_num];
+}
+
+/* Get vcpu SPSR for current mode */
+static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
+{
+       if (vcpu_mode_is_32bit(vcpu))
+               return vcpu_spsr32(vcpu);
+
+       return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+}
+
+static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
+{
+       u32 mode = *vcpu_cpsr(vcpu) & PSR_MODE_MASK;
+
+       if (vcpu_mode_is_32bit(vcpu))
+               return mode > COMPAT_PSR_MODE_USR;
+
+       return mode != PSR_MODE_EL0t;
+}
+
+static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.fault.esr_el2;
+}
+
+static inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.fault.far_el2;
+}
+
+static inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
+{
+       return ((phys_addr_t)vcpu->arch.fault.hpfar_el2 & HPFAR_MASK) << 8;
+}
+
+static inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
+{
+       return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_ISV);
+}
+
+static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
+{
+       return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_WNR);
+}
+
+static inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu)
+{
+       return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_SSE);
+}
+
+static inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
+{
+       return (kvm_vcpu_get_hsr(vcpu) & ESR_EL2_SRT_MASK) >> ESR_EL2_SRT_SHIFT;
+}
+
+static inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
+{
+       return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_EA);
+}
+
+static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
+{
+       return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_S1PTW);
+}
+
+static inline int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
+{
+       return 1 << ((kvm_vcpu_get_hsr(vcpu) & ESR_EL2_SAS) >> ESR_EL2_SAS_SHIFT);
+}
+
+/* This one is not specific to Data Abort */
+static inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
+{
+       return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_IL);
+}
+
+static inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
+{
+       return kvm_vcpu_get_hsr(vcpu) >> ESR_EL2_EC_SHIFT;
+}
+
+static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
+{
+       return kvm_vcpu_trap_get_class(vcpu) == ESR_EL2_EC_IABT;
+}
+
+static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
+{
+       return kvm_vcpu_get_hsr(vcpu) & ESR_EL2_FSC_TYPE;
+}
+
+#endif /* __ARM64_KVM_EMULATE_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
new file mode 100644 (file)
index 0000000..644d739
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/include/asm/kvm_host.h:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.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_HOST_H__
+#define __ARM64_KVM_HOST_H__
+
+#include <asm/kvm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmio.h>
+
+#define KVM_MAX_VCPUS 4
+#define KVM_USER_MEM_SLOTS 32
+#define KVM_PRIVATE_MEM_SLOTS 4
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+
+#include <kvm/arm_vgic.h>
+#include <kvm/arm_arch_timer.h>
+
+#define KVM_VCPU_MAX_FEATURES 2
+
+/* We don't currently support large pages. */
+#define KVM_HPAGE_GFN_SHIFT(x) 0
+#define KVM_NR_PAGE_SIZES      1
+#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
+
+struct kvm_vcpu;
+int kvm_target_cpu(void);
+int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
+int kvm_arch_dev_ioctl_check_extension(long ext);
+
+struct kvm_arch {
+       /* The VMID generation used for the virt. memory system */
+       u64    vmid_gen;
+       u32    vmid;
+
+       /* 1-level 2nd stage table and lock */
+       spinlock_t pgd_lock;
+       pgd_t *pgd;
+
+       /* VTTBR value associated with above pgd and vmid */
+       u64    vttbr;
+
+       /* Interrupt controller */
+       struct vgic_dist        vgic;
+
+       /* Timer */
+       struct arch_timer_kvm   timer;
+};
+
+#define KVM_NR_MEM_OBJS     40
+
+/*
+ * We don't want allocation failures within the mmu code, so we preallocate
+ * enough memory for a single page fault in a cache.
+ */
+struct kvm_mmu_memory_cache {
+       int nobjs;
+       void *objects[KVM_NR_MEM_OBJS];
+};
+
+struct kvm_vcpu_fault_info {
+       u32 esr_el2;            /* Hyp Syndrom Register */
+       u64 far_el2;            /* Hyp Fault Address Register */
+       u64 hpfar_el2;          /* Hyp IPA Fault Address Register */
+};
+
+struct kvm_cpu_context {
+       struct kvm_regs gp_regs;
+       union {
+               u64 sys_regs[NR_SYS_REGS];
+               u32 cp15[NR_CP15_REGS];
+       };
+};
+
+typedef struct kvm_cpu_context kvm_cpu_context_t;
+
+struct kvm_vcpu_arch {
+       struct kvm_cpu_context ctxt;
+
+       /* HYP configuration */
+       u64 hcr_el2;
+
+       /* Exception Information */
+       struct kvm_vcpu_fault_info fault;
+
+       /* Pointer to host CPU context */
+       kvm_cpu_context_t *host_cpu_context;
+
+       /* VGIC state */
+       struct vgic_cpu vgic_cpu;
+       struct arch_timer_cpu timer_cpu;
+
+       /*
+        * Anything that is not used directly from assembly code goes
+        * here.
+        */
+       /* dcache set/way operation pending */
+       int last_pcpu;
+       cpumask_t require_dcache_flush;
+
+       /* Don't run the guest */
+       bool pause;
+
+       /* IO related fields */
+       struct kvm_decode mmio_decode;
+
+       /* Interrupt related fields */
+       u64 irq_lines;          /* IRQ and FIQ levels */
+
+       /* Cache some mmu pages needed inside spinlock regions */
+       struct kvm_mmu_memory_cache mmu_page_cache;
+
+       /* Target CPU and feature flags */
+       u32 target;
+       DECLARE_BITMAP(features, KVM_VCPU_MAX_FEATURES);
+
+       /* Detect first run of a vcpu */
+       bool has_run_once;
+};
+
+#define vcpu_gp_regs(v)                (&(v)->arch.ctxt.gp_regs)
+#define vcpu_sys_reg(v,r)      ((v)->arch.ctxt.sys_regs[(r)])
+#define vcpu_cp15(v,r)         ((v)->arch.ctxt.cp15[(r)])
+
+struct kvm_vm_stat {
+       u32 remote_tlb_flush;
+};
+
+struct kvm_vcpu_stat {
+       u32 halt_wakeup;
+};
+
+struct kvm_vcpu_init;
+int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
+                       const struct kvm_vcpu_init *init);
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
+int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
+struct kvm_one_reg;
+int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+
+#define KVM_ARCH_WANT_MMU_NOTIFIER
+struct kvm;
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+int kvm_unmap_hva_range(struct kvm *kvm,
+                       unsigned long start, unsigned long end);
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
+
+/* We do not have shadow page tables, hence the empty hooks */
+static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+       return 0;
+}
+
+static inline int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+       return 0;
+}
+
+struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
+struct kvm_vcpu __percpu **kvm_get_running_vcpus(void);
+
+u64 kvm_call_hyp(void *hypfn, ...);
+
+int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
+               int exception_index);
+
+int kvm_perf_init(void);
+int kvm_perf_teardown(void);
+
+static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
+                                      phys_addr_t pgd_ptr,
+                                      unsigned long hyp_stack_ptr,
+                                      unsigned long vector_ptr)
+{
+       /*
+        * Call initialization code, and switch to the full blown
+        * HYP code.
+        */
+       kvm_call_hyp((void *)boot_pgd_ptr, pgd_ptr,
+                    hyp_stack_ptr, vector_ptr);
+}
+
+#endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/include/asm/kvm_mmio.h b/arch/arm64/include/asm/kvm_mmio.h
new file mode 100644 (file)
index 0000000..fc2f689
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.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_MMIO_H__
+#define __ARM64_KVM_MMIO_H__
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+
+/*
+ * This is annoying. The mmio code requires this, even if we don't
+ * need any decoding. To be fixed.
+ */
+struct kvm_decode {
+       unsigned long rt;
+       bool sign_extend;
+};
+
+/*
+ * The in-kernel MMIO emulation code wants to use a copy of run->mmio,
+ * which is an anonymous type. Use our own type instead.
+ */
+struct kvm_exit_mmio {
+       phys_addr_t     phys_addr;
+       u8              data[8];
+       u32             len;
+       bool            is_write;
+};
+
+static inline void kvm_prepare_mmio(struct kvm_run *run,
+                                   struct kvm_exit_mmio *mmio)
+{
+       run->mmio.phys_addr     = mmio->phys_addr;
+       run->mmio.len           = mmio->len;
+       run->mmio.is_write      = mmio->is_write;
+       memcpy(run->mmio.data, mmio->data, mmio->len);
+       run->exit_reason        = KVM_EXIT_MMIO;
+}
+
+int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
+                phys_addr_t fault_ipa);
+
+#endif /* __ARM64_KVM_MMIO_H__ */
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
new file mode 100644 (file)
index 0000000..efe609c
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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/>.
+ */
+
+#ifndef __ARM64_KVM_MMU_H__
+#define __ARM64_KVM_MMU_H__
+
+#include <asm/page.h>
+#include <asm/memory.h>
+
+/*
+ * As we only have the TTBR0_EL2 register, we cannot express
+ * "negative" addresses. This makes it impossible to directly share
+ * mappings with the kernel.
+ *
+ * Instead, give the HYP mode its own VA region at a fixed offset from
+ * the kernel by just masking the top bits (which are all ones for a
+ * kernel address).
+ */
+#define HYP_PAGE_OFFSET_SHIFT  VA_BITS
+#define HYP_PAGE_OFFSET_MASK   ((UL(1) << HYP_PAGE_OFFSET_SHIFT) - 1)
+#define HYP_PAGE_OFFSET                (PAGE_OFFSET & HYP_PAGE_OFFSET_MASK)
+
+/*
+ * Our virtual mapping for the idmap-ed MMU-enable code. Must be
+ * shared across all the page-tables. Conveniently, we use the last
+ * possible page, where no kernel mapping will ever exist.
+ */
+#define TRAMPOLINE_VA          (HYP_PAGE_OFFSET_MASK & PAGE_MASK)
+
+#ifdef __ASSEMBLY__
+
+/*
+ * Convert a kernel VA into a HYP VA.
+ * reg: VA to be converted.
+ */
+.macro kern_hyp_va     reg
+       and     \reg, \reg, #HYP_PAGE_OFFSET_MASK
+.endm
+
+#else
+
+#include <asm/cachetype.h>
+#include <asm/cacheflush.h>
+
+#define KERN_TO_HYP(kva)       ((unsigned long)kva - PAGE_OFFSET + HYP_PAGE_OFFSET)
+
+/*
+ * Align KVM with the kernel's view of physical memory. Should be
+ * 40bit IPA, with PGD being 8kB aligned in the 4KB page configuration.
+ */
+#define KVM_PHYS_SHIFT PHYS_MASK_SHIFT
+#define KVM_PHYS_SIZE  (1UL << KVM_PHYS_SHIFT)
+#define KVM_PHYS_MASK  (KVM_PHYS_SIZE - 1UL)
+
+/* Make sure we get the right size, and thus the right alignment */
+#define PTRS_PER_S2_PGD (1 << (KVM_PHYS_SHIFT - PGDIR_SHIFT))
+#define S2_PGD_ORDER   get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
+
+int create_hyp_mappings(void *from, void *to);
+int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
+void free_boot_hyp_pgd(void);
+void free_hyp_pgds(void);
+
+int kvm_alloc_stage2_pgd(struct kvm *kvm);
+void kvm_free_stage2_pgd(struct kvm *kvm);
+int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
+                         phys_addr_t pa, unsigned long size);
+
+int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
+
+void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
+
+phys_addr_t kvm_mmu_get_httbr(void);
+phys_addr_t kvm_mmu_get_boot_httbr(void);
+phys_addr_t kvm_get_idmap_vector(void);
+int kvm_mmu_init(void);
+void kvm_clear_hyp_idmap(void);
+
+#define        kvm_set_pte(ptep, pte)          set_pte(ptep, pte)
+
+static inline bool kvm_is_write_fault(unsigned long esr)
+{
+       unsigned long esr_ec = esr >> ESR_EL2_EC_SHIFT;
+
+       if (esr_ec == ESR_EL2_EC_IABT)
+               return false;
+
+       if ((esr & ESR_EL2_ISV) && !(esr & ESR_EL2_WNR))
+               return false;
+
+       return true;
+}
+
+static inline void kvm_clean_dcache_area(void *addr, size_t size) {}
+static inline void kvm_clean_pgd(pgd_t *pgd) {}
+static inline void kvm_clean_pmd_entry(pmd_t *pmd) {}
+static inline void kvm_clean_pte(pte_t *pte) {}
+static inline void kvm_clean_pte_entry(pte_t *pte) {}
+
+static inline void kvm_set_s2pte_writable(pte_t *pte)
+{
+       pte_val(*pte) |= PTE_S2_RDWR;
+}
+
+struct kvm;
+
+static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn)
+{
+       if (!icache_is_aliasing()) {            /* PIPT */
+               unsigned long hva = gfn_to_hva(kvm, gfn);
+               flush_icache_range(hva, hva + PAGE_SIZE);
+       } else if (!icache_is_aivivt()) {       /* non ASID-tagged VIVT */
+               /* any kind of VIPT cache */
+               __flush_icache_all();
+       }
+}
+
+#define kvm_flush_dcache_to_poc(a,l)   __flush_dcache_area((a), (l))
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARM64_KVM_MMU_H__ */
diff --git a/arch/arm64/include/asm/kvm_psci.h b/arch/arm64/include/asm/kvm_psci.h
new file mode 100644 (file)
index 0000000..e301a48
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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/>.
+ */
+
+#ifndef __ARM64_KVM_PSCI_H__
+#define __ARM64_KVM_PSCI_H__
+
+bool kvm_psci_call(struct kvm_vcpu *vcpu);
+
+#endif /* __ARM64_KVM_PSCI_H__ */
index 381f556b664ef9fa0f6ad05b39396ebc5b493d6a..20925bcf4e2a10485d724c5017c0ac639093390a 100644 (file)
 #define MT_NORMAL_NC           3
 #define MT_NORMAL              4
 
+/*
+ * Memory types for Stage-2 translation
+ */
+#define MT_S2_NORMAL           0xf
+#define MT_S2_DEVICE_nGnRE     0x1
+
 #ifndef __ASSEMBLY__
 
 extern phys_addr_t             memstart_addr;
index e2bc385adb6b9b3ebb941702be4ea378586413c8..a9eee33dfa62dc031ab8262c275eba79f8609bac 100644 (file)
@@ -151,12 +151,6 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
 {
        unsigned int cpu = smp_processor_id();
 
-#ifdef CONFIG_SMP
-       /* check for possible thread migration */
-       if (!cpumask_empty(mm_cpumask(next)) &&
-           !cpumask_test_cpu(cpu, mm_cpumask(next)))
-               __flush_icache_all();
-#endif
        if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next)
                check_and_switch_context(next, tsk);
 }
index 75fd13d289b93193f261c89fa83fb6973738f6f2..e182a356c979d04e0f6cf811ecfa5b87c915657b 100644 (file)
 /*
  * Hardware page table definitions.
  *
+ * Level 1 descriptor (PUD).
+ */
+
+#define PUD_TABLE_BIT          (_AT(pgdval_t, 1) << 1)
+
+/*
  * Level 2 descriptor (PMD).
  */
 #define PMD_TYPE_MASK          (_AT(pmdval_t, 3) << 0)
 #define PMD_TYPE_FAULT         (_AT(pmdval_t, 0) << 0)
 #define PMD_TYPE_TABLE         (_AT(pmdval_t, 3) << 0)
 #define PMD_TYPE_SECT          (_AT(pmdval_t, 1) << 0)
+#define PMD_TABLE_BIT          (_AT(pmdval_t, 1) << 1)
 
 /*
  * Section
  */
+#define PMD_SECT_VALID         (_AT(pmdval_t, 1) << 0)
+#define PMD_SECT_PROT_NONE     (_AT(pmdval_t, 1) << 2)
+#define PMD_SECT_USER          (_AT(pmdval_t, 1) << 6)         /* AP[1] */
+#define PMD_SECT_RDONLY                (_AT(pmdval_t, 1) << 7)         /* AP[2] */
 #define PMD_SECT_S             (_AT(pmdval_t, 3) << 8)
 #define PMD_SECT_AF            (_AT(pmdval_t, 1) << 10)
 #define PMD_SECT_NG            (_AT(pmdval_t, 1) << 11)
@@ -53,6 +64,7 @@
 #define PTE_TYPE_MASK          (_AT(pteval_t, 3) << 0)
 #define PTE_TYPE_FAULT         (_AT(pteval_t, 0) << 0)
 #define PTE_TYPE_PAGE          (_AT(pteval_t, 3) << 0)
+#define PTE_TABLE_BIT          (_AT(pteval_t, 1) << 1)
 #define PTE_USER               (_AT(pteval_t, 1) << 6)         /* AP[1] */
 #define PTE_RDONLY             (_AT(pteval_t, 1) << 7)         /* AP[2] */
 #define PTE_SHARED             (_AT(pteval_t, 3) << 8)         /* SH[1:0], inner shareable */
 #define PTE_ATTRINDX(t)                (_AT(pteval_t, (t)) << 2)
 #define PTE_ATTRINDX_MASK      (_AT(pteval_t, 7) << 2)
 
+/*
+ * 2nd stage PTE definitions
+ */
+#define PTE_S2_RDONLY          (_AT(pteval_t, 1) << 6)   /* HAP[2:1] */
+#define PTE_S2_RDWR            (_AT(pteval_t, 3) << 6)   /* HAP[2:1] */
+
+/*
+ * Memory Attribute override for Stage-2 (MemAttr[3:0])
+ */
+#define PTE_S2_MEMATTR(t)      (_AT(pteval_t, (t)) << 2)
+#define PTE_S2_MEMATTR_MASK    (_AT(pteval_t, 0xf) << 2)
+
+/*
+ * EL2/HYP PTE/PMD definitions
+ */
+#define PMD_HYP                        PMD_SECT_USER
+#define PTE_HYP                        PTE_USER
+
 /*
  * 40-bit physical address supported.
  */
index 3a768e96cf0ef18bf874d83ffa3ba096eaa9bda0..f0bebc5e22cdb662577ab63828d56d105ae18770 100644 (file)
@@ -25,8 +25,8 @@
  * Software defined PTE bits definition.
  */
 #define PTE_VALID              (_AT(pteval_t, 1) << 0)
-#define PTE_PROT_NONE          (_AT(pteval_t, 1) << 1) /* only when !PTE_VALID */
-#define PTE_FILE               (_AT(pteval_t, 1) << 2) /* only when !pte_present() */
+#define PTE_PROT_NONE          (_AT(pteval_t, 1) << 2) /* only when !PTE_VALID */
+#define PTE_FILE               (_AT(pteval_t, 1) << 3) /* only when !pte_present() */
 #define PTE_DIRTY              (_AT(pteval_t, 1) << 55)
 #define PTE_SPECIAL            (_AT(pteval_t, 1) << 56)
 
@@ -66,7 +66,7 @@ extern pgprot_t pgprot_default;
 
 #define _MOD_PROT(p, b)                __pgprot_modify(p, 0, b)
 
-#define PAGE_NONE              __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE)
+#define PAGE_NONE              __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN)
 #define PAGE_SHARED            _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
 #define PAGE_SHARED_EXEC       _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN)
 #define PAGE_COPY              _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
@@ -76,7 +76,13 @@ extern pgprot_t pgprot_default;
 #define PAGE_KERNEL            _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY)
 #define PAGE_KERNEL_EXEC       _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY)
 
-#define __PAGE_NONE            __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE)
+#define PAGE_HYP               _MOD_PROT(pgprot_default, PTE_HYP)
+#define PAGE_HYP_DEVICE                __pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
+
+#define PAGE_S2                        __pgprot_modify(pgprot_default, PTE_S2_MEMATTR_MASK, PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
+#define PAGE_S2_DEVICE         __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDWR | PTE_UXN)
+
+#define __PAGE_NONE            __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN)
 #define __PAGE_SHARED          __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
 #define __PAGE_SHARED_EXEC     __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
 #define __PAGE_COPY            __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
@@ -119,7 +125,7 @@ extern struct page *empty_zero_page;
 #define pte_none(pte)          (!pte_val(pte))
 #define pte_clear(mm,addr,ptep)        set_pte(ptep, __pte(0))
 #define pte_page(pte)          (pfn_to_page(pte_pfn(pte)))
-#define pte_offset_kernel(dir,addr)    (pmd_page_vaddr(*(dir)) + __pte_index(addr))
+#define pte_offset_kernel(dir,addr)    (pmd_page_vaddr(*(dir)) + pte_index(addr))
 
 #define pte_offset_map(dir,addr)       pte_offset_kernel((dir), (addr))
 #define pte_offset_map_nested(dir,addr)        pte_offset_kernel((dir), (addr))
@@ -173,11 +179,75 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 /*
  * Huge pte definitions.
  */
-#define pte_huge(pte)          ((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE)
-#define pte_mkhuge(pte)                (__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE))
+#define pte_huge(pte)          (!(pte_val(pte) & PTE_TABLE_BIT))
+#define pte_mkhuge(pte)                (__pte(pte_val(pte) & ~PTE_TABLE_BIT))
+
+/*
+ * Hugetlb definitions.
+ */
+#define HUGE_MAX_HSTATE                2
+#define HPAGE_SHIFT            PMD_SHIFT
+#define HPAGE_SIZE             (_AC(1, UL) << HPAGE_SHIFT)
+#define HPAGE_MASK             (~(HPAGE_SIZE - 1))
+#define HUGETLB_PAGE_ORDER     (HPAGE_SHIFT - PAGE_SHIFT)
 
 #define __HAVE_ARCH_PTE_SPECIAL
 
+/*
+ * Software PMD bits for THP
+ */
+
+#define PMD_SECT_DIRTY         (_AT(pmdval_t, 1) << 55)
+#define PMD_SECT_SPLITTING     (_AT(pmdval_t, 1) << 57)
+
+/*
+ * THP definitions.
+ */
+#define pmd_young(pmd)         (pmd_val(pmd) & PMD_SECT_AF)
+
+#define __HAVE_ARCH_PMD_WRITE
+#define pmd_write(pmd)         (!(pmd_val(pmd) & PMD_SECT_RDONLY))
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define pmd_trans_huge(pmd)    (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
+#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
+#endif
+
+#define PMD_BIT_FUNC(fn,op) \
+static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
+
+PMD_BIT_FUNC(wrprotect,        |= PMD_SECT_RDONLY);
+PMD_BIT_FUNC(mkold,    &= ~PMD_SECT_AF);
+PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING);
+PMD_BIT_FUNC(mkwrite,   &= ~PMD_SECT_RDONLY);
+PMD_BIT_FUNC(mkdirty,   |= PMD_SECT_DIRTY);
+PMD_BIT_FUNC(mkyoung,   |= PMD_SECT_AF);
+PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK);
+
+#define pmd_mkhuge(pmd)                (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
+
+#define pmd_pfn(pmd)           (((pmd_val(pmd) & PMD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
+#define pfn_pmd(pfn,prot)      (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+#define mk_pmd(page,prot)      pfn_pmd(page_to_pfn(page),prot)
+
+#define pmd_page(pmd)           pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
+
+static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
+{
+       const pmdval_t mask = PMD_SECT_USER | PMD_SECT_PXN | PMD_SECT_UXN |
+                             PMD_SECT_RDONLY | PMD_SECT_PROT_NONE |
+                             PMD_SECT_VALID;
+       pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask);
+       return pmd;
+}
+
+#define set_pmd_at(mm, addr, pmdp, pmd)        set_pmd(pmdp, pmd)
+
+static inline int has_transparent_hugepage(void)
+{
+       return 1;
+}
+
 /*
  * Mark the prot value as uncacheable and unbufferable.
  */
@@ -197,6 +267,12 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
 
 #define pmd_bad(pmd)           (!(pmd_val(pmd) & 2))
 
+#define pmd_table(pmd)         ((pmd_val(pmd) & PMD_TYPE_MASK) == \
+                                PMD_TYPE_TABLE)
+#define pmd_sect(pmd)          ((pmd_val(pmd) & PMD_TYPE_MASK) == \
+                                PMD_TYPE_SECT)
+
+
 static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
 {
        *pmdp = pmd;
@@ -263,7 +339,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
 #endif
 
 /* Find an entry in the third-level page table.. */
-#define __pte_index(addr)      (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_index(addr)                (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
@@ -281,12 +357,12 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
 
 /*
  * Encode and decode a swap entry:
- *     bits 0-1:       present (must be zero)
- *     bit  2:         PTE_FILE
- *     bits 3-8:       swap type
+ *     bits 0, 2:      present (must both be zero)
+ *     bit  3:         PTE_FILE
+ *     bits 4-8:       swap type
  *     bits 9-63:      swap offset
  */
-#define __SWP_TYPE_SHIFT       3
+#define __SWP_TYPE_SHIFT       4
 #define __SWP_TYPE_BITS                6
 #define __SWP_TYPE_MASK                ((1 << __SWP_TYPE_BITS) - 1)
 #define __SWP_OFFSET_SHIFT     (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
@@ -306,15 +382,15 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
 
 /*
  * Encode and decode a file entry:
- *     bits 0-1:       present (must be zero)
- *     bit  2:         PTE_FILE
- *     bits 3-63:      file offset / PAGE_SIZE
+ *     bits 0, 2:      present (must both be zero)
+ *     bit  3:         PTE_FILE
+ *     bits 4-63:      file offset / PAGE_SIZE
  */
 #define pte_file(pte)          (pte_val(pte) & PTE_FILE)
-#define pte_to_pgoff(x)                (pte_val(x) >> 3)
-#define pgoff_to_pte(x)                __pte(((x) << 3) | PTE_FILE)
+#define pte_to_pgoff(x)                (pte_val(x) >> 4)
+#define pgoff_to_pte(x)                __pte(((x) << 4) | PTE_FILE)
 
-#define PTE_FILE_MAX_BITS      61
+#define PTE_FILE_MAX_BITS      60
 
 extern int kern_addr_valid(unsigned long addr);
 
index 41a71ee4c3df42743eb5aa494f72e6287cff55bb..0dacbbf9458b9297ba1a67720665e8a7448a036e 100644 (file)
@@ -171,7 +171,5 @@ extern unsigned long profile_pc(struct pt_regs *regs);
 #define profile_pc(regs) instruction_pointer(regs)
 #endif
 
-extern int aarch32_break_trap(struct pt_regs *regs);
-
 #endif /* __ASSEMBLY__ */
 #endif
index 7065e920149d3d0ec6e9ed549e71a5040aa0a5d2..0defa0728a9b85f6c82d104f8c3bdb6ea3bf716f 100644 (file)
@@ -59,9 +59,10 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
        unsigned int tmp;
 
        asm volatile(
-       "       ldaxr   %w0, %1\n"
+       "2:     ldaxr   %w0, %1\n"
        "       cbnz    %w0, 1f\n"
        "       stxr    %w0, %w2, %1\n"
+       "       cbnz    %w0, 2b\n"
        "1:\n"
        : "=&r" (tmp), "+Q" (lock->lock)
        : "r" (1)
diff --git a/arch/arm64/include/asm/sync_bitops.h b/arch/arm64/include/asm/sync_bitops.h
new file mode 100644 (file)
index 0000000..8da0bf4
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __ASM_SYNC_BITOPS_H__
+#define __ASM_SYNC_BITOPS_H__
+
+#include <asm/bitops.h>
+#include <asm/cmpxchg.h>
+
+/* sync_bitops functions are equivalent to the SMP implementation of the
+ * original functions, independently from CONFIG_SMP being defined.
+ *
+ * We need them because _set_bit etc are not SMP safe if !CONFIG_SMP. But
+ * under Xen you might be communicating with a completely external entity
+ * who might be on another CPU (e.g. two uniprocessor guests communicating
+ * via event channels and grant tables). So we need a variant of the bit
+ * ops which are SMP safe even on a UP kernel.
+ */
+
+#define sync_set_bit(nr, p)            set_bit(nr, p)
+#define sync_clear_bit(nr, p)          clear_bit(nr, p)
+#define sync_change_bit(nr, p)         change_bit(nr, p)
+#define sync_test_and_set_bit(nr, p)   test_and_set_bit(nr, p)
+#define sync_test_and_clear_bit(nr, p) test_and_clear_bit(nr, p)
+#define sync_test_and_change_bit(nr, p)        test_and_change_bit(nr, p)
+#define sync_test_bit(nr, addr)                test_bit(nr, addr)
+#define sync_cmpxchg                   cmpxchg
+
+#endif
index b24a31a7e2c94053a41e324c9c24a2cc4fc88916..81a076eb37faff310e32c0a0f6c2d4170083ea98 100644 (file)
 #ifndef __ASM_TIMEX_H
 #define __ASM_TIMEX_H
 
+#include <asm/arch_timer.h>
+
 /*
  * Use the current timer as a cycle counter since this is what we use for
  * the delay loop.
  */
-#define get_cycles()   ({ cycles_t c; read_current_timer(&c); c; })
+#define get_cycles()   arch_counter_get_cntvct()
 
 #include <asm-generic/timex.h>
 
-#define ARCH_HAS_READ_CURRENT_TIMER
-
 #endif
index 654f0968030b702f8040d07d54445c3f34174c20..46b3beb4b773c85cd381f72301b8f2e9dfdc7a97 100644 (file)
@@ -187,4 +187,10 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
 
 #define tlb_migrate_finish(mm)         do { } while (0)
 
+static inline void
+tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr)
+{
+       tlb_add_flush(tlb, addr);
+}
+
 #endif
index 122d6320f7453d985a6eb5754a245752c7abb78c..8b482035cfc2434bdba34d3e24e6308ac01f423e 100644 (file)
@@ -117,6 +117,8 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
        dsb();
 }
 
+#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
+
 #endif
 
 #endif
index 008f8481da65d97d5022c3763ec8ba909e9d38b8..edb3d5c73a3232c35532bd5e489add1cabf7201c 100644 (file)
@@ -166,7 +166,7 @@ do {                                                                        \
 
 #define get_user(x, ptr)                                               \
 ({                                                                     \
-       might_sleep();                                                  \
+       might_fault();                                                  \
        access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) ?                 \
                __get_user((x), (ptr)) :                                \
                ((x) = 0, -EFAULT);                                     \
@@ -227,7 +227,7 @@ do {                                                                        \
 
 #define put_user(x, ptr)                                               \
 ({                                                                     \
-       might_sleep();                                                  \
+       might_fault();                                                  \
        access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) ?                \
                __put_user((x), (ptr)) :                                \
                -EFAULT;                                                \
diff --git a/arch/arm64/include/asm/xen/events.h b/arch/arm64/include/asm/xen/events.h
new file mode 100644 (file)
index 0000000..8655321
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _ASM_ARM64_XEN_EVENTS_H
+#define _ASM_ARM64_XEN_EVENTS_H
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
+enum ipi_vector {
+       XEN_PLACEHOLDER_VECTOR,
+
+       /* Xen IPIs go here */
+       XEN_NR_IPIS,
+};
+
+static inline int xen_irqs_disabled(struct pt_regs *regs)
+{
+       return raw_irqs_disabled_flags((unsigned long) regs->pstate);
+}
+
+#define xchg_xen_ulong(ptr, val) xchg((ptr), (val))
+
+#endif /* _ASM_ARM64_XEN_EVENTS_H */
diff --git a/arch/arm64/include/asm/xen/hypercall.h b/arch/arm64/include/asm/xen/hypercall.h
new file mode 100644 (file)
index 0000000..74b0c42
--- /dev/null
@@ -0,0 +1 @@
+#include <../../arm/include/asm/xen/hypercall.h>
diff --git a/arch/arm64/include/asm/xen/hypervisor.h b/arch/arm64/include/asm/xen/hypervisor.h
new file mode 100644 (file)
index 0000000..f263da8
--- /dev/null
@@ -0,0 +1 @@
+#include <../../arm/include/asm/xen/hypervisor.h>
diff --git a/arch/arm64/include/asm/xen/interface.h b/arch/arm64/include/asm/xen/interface.h
new file mode 100644 (file)
index 0000000..44457ae
--- /dev/null
@@ -0,0 +1 @@
+#include <../../arm/include/asm/xen/interface.h>
diff --git a/arch/arm64/include/asm/xen/page.h b/arch/arm64/include/asm/xen/page.h
new file mode 100644 (file)
index 0000000..bed87ec
--- /dev/null
@@ -0,0 +1 @@
+#include <../../arm/include/asm/xen/page.h>
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
new file mode 100644 (file)
index 0000000..5031f42
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/include/uapi/asm/kvm.h:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.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 __ARM_KVM_H__
+#define __ARM_KVM_H__
+
+#define KVM_SPSR_EL1   0
+#define KVM_SPSR_SVC   KVM_SPSR_EL1
+#define KVM_SPSR_ABT   1
+#define KVM_SPSR_UND   2
+#define KVM_SPSR_IRQ   3
+#define KVM_SPSR_FIQ   4
+#define KVM_NR_SPSR    5
+
+#ifndef __ASSEMBLY__
+#include <asm/types.h>
+#include <asm/ptrace.h>
+
+#define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_IRQ_LINE
+
+#define KVM_REG_SIZE(id)                                               \
+       (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
+
+struct kvm_regs {
+       struct user_pt_regs regs;       /* sp = sp_el0 */
+
+       __u64   sp_el1;
+       __u64   elr_el1;
+
+       __u64   spsr[KVM_NR_SPSR];
+
+       struct user_fpsimd_state fp_regs;
+};
+
+/* Supported Processor Types */
+#define KVM_ARM_TARGET_AEM_V8          0
+#define KVM_ARM_TARGET_FOUNDATION_V8   1
+#define KVM_ARM_TARGET_CORTEX_A57      2
+
+#define KVM_ARM_NUM_TARGETS            3
+
+/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
+#define KVM_ARM_DEVICE_TYPE_SHIFT      0
+#define KVM_ARM_DEVICE_TYPE_MASK       (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT)
+#define KVM_ARM_DEVICE_ID_SHIFT                16
+#define KVM_ARM_DEVICE_ID_MASK         (0xffff << KVM_ARM_DEVICE_ID_SHIFT)
+
+/* Supported device IDs */
+#define KVM_ARM_DEVICE_VGIC_V2         0
+
+/* Supported VGIC address types  */
+#define KVM_VGIC_V2_ADDR_TYPE_DIST     0
+#define KVM_VGIC_V2_ADDR_TYPE_CPU      1
+
+#define KVM_VGIC_V2_DIST_SIZE          0x1000
+#define KVM_VGIC_V2_CPU_SIZE           0x2000
+
+#define KVM_ARM_VCPU_POWER_OFF         0 /* CPU is started in OFF state */
+#define KVM_ARM_VCPU_EL1_32BIT         1 /* CPU running a 32bit VM */
+
+struct kvm_vcpu_init {
+       __u32 target;
+       __u32 features[7];
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+};
+
+struct kvm_guest_debug_arch {
+};
+
+struct kvm_debug_exit_arch {
+};
+
+struct kvm_sync_regs {
+};
+
+struct kvm_arch_memory_slot {
+};
+
+/* If you need to interpret the index values, here is the key: */
+#define KVM_REG_ARM_COPROC_MASK                0x000000000FFF0000
+#define KVM_REG_ARM_COPROC_SHIFT       16
+
+/* Normal registers are mapped as coprocessor 16. */
+#define KVM_REG_ARM_CORE               (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_CORE_REG(name)     (offsetof(struct kvm_regs, name) / sizeof(__u32))
+
+/* Some registers need more space to represent values. */
+#define KVM_REG_ARM_DEMUX              (0x0011 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_DEMUX_ID_MASK      0x000000000000FF00
+#define KVM_REG_ARM_DEMUX_ID_SHIFT     8
+#define KVM_REG_ARM_DEMUX_ID_CCSIDR    (0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT)
+#define KVM_REG_ARM_DEMUX_VAL_MASK     0x00000000000000FF
+#define KVM_REG_ARM_DEMUX_VAL_SHIFT    0
+
+/* AArch64 system registers */
+#define KVM_REG_ARM64_SYSREG           (0x0013 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM64_SYSREG_OP0_MASK  0x000000000000c000
+#define KVM_REG_ARM64_SYSREG_OP0_SHIFT 14
+#define KVM_REG_ARM64_SYSREG_OP1_MASK  0x0000000000003800
+#define KVM_REG_ARM64_SYSREG_OP1_SHIFT 11
+#define KVM_REG_ARM64_SYSREG_CRN_MASK  0x0000000000000780
+#define KVM_REG_ARM64_SYSREG_CRN_SHIFT 7
+#define KVM_REG_ARM64_SYSREG_CRM_MASK  0x0000000000000078
+#define KVM_REG_ARM64_SYSREG_CRM_SHIFT 3
+#define KVM_REG_ARM64_SYSREG_OP2_MASK  0x0000000000000007
+#define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0
+
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_TYPE_SHIFT         24
+#define KVM_ARM_IRQ_TYPE_MASK          0xff
+#define KVM_ARM_IRQ_VCPU_SHIFT         16
+#define KVM_ARM_IRQ_VCPU_MASK          0xff
+#define KVM_ARM_IRQ_NUM_SHIFT          0
+#define KVM_ARM_IRQ_NUM_MASK           0xffff
+
+/* irq_type field */
+#define KVM_ARM_IRQ_TYPE_CPU           0
+#define KVM_ARM_IRQ_TYPE_SPI           1
+#define KVM_ARM_IRQ_TYPE_PPI           2
+
+/* out-of-kernel GIC cpu interrupt injection irq_number field */
+#define KVM_ARM_IRQ_CPU_IRQ            0
+#define KVM_ARM_IRQ_CPU_FIQ            1
+
+/* Highest supported SPI, from VGIC_NR_IRQS */
+#define KVM_ARM_IRQ_GIC_MAX            127
+
+/* PSCI interface */
+#define KVM_PSCI_FN_BASE               0x95c1ba5e
+#define KVM_PSCI_FN(n)                 (KVM_PSCI_FN_BASE + (n))
+
+#define KVM_PSCI_FN_CPU_SUSPEND                KVM_PSCI_FN(0)
+#define KVM_PSCI_FN_CPU_OFF            KVM_PSCI_FN(1)
+#define KVM_PSCI_FN_CPU_ON             KVM_PSCI_FN(2)
+#define KVM_PSCI_FN_MIGRATE            KVM_PSCI_FN(3)
+
+#define KVM_PSCI_RET_SUCCESS           0
+#define KVM_PSCI_RET_NI                        ((unsigned long)-1)
+#define KVM_PSCI_RET_INVAL             ((unsigned long)-2)
+#define KVM_PSCI_RET_DENIED            ((unsigned long)-3)
+
+#endif
+
+#endif /* __ARM_KVM_H__ */
index a2a4d810bea3ee70cee2a14b93faec49ba81d7c5..49c162c03b696c9f7f9501c666d093b98a27e8ab 100644 (file)
@@ -104,5 +104,38 @@ int main(void)
   BLANK();
   DEFINE(TZ_MINWEST,           offsetof(struct timezone, tz_minuteswest));
   DEFINE(TZ_DSTTIME,           offsetof(struct timezone, tz_dsttime));
+  BLANK();
+#ifdef CONFIG_KVM_ARM_HOST
+  DEFINE(VCPU_CONTEXT,         offsetof(struct kvm_vcpu, arch.ctxt));
+  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_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_HCR_EL2,         offsetof(struct kvm_vcpu, arch.hcr_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_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_CPU_HCR,         offsetof(struct vgic_cpu, vgic_hcr));
+  DEFINE(VGIC_CPU_VMCR,                offsetof(struct vgic_cpu, vgic_vmcr));
+  DEFINE(VGIC_CPU_MISR,                offsetof(struct vgic_cpu, vgic_misr));
+  DEFINE(VGIC_CPU_EISR,                offsetof(struct vgic_cpu, vgic_eisr));
+  DEFINE(VGIC_CPU_ELRSR,       offsetof(struct vgic_cpu, vgic_elrsr));
+  DEFINE(VGIC_CPU_APR,         offsetof(struct vgic_cpu, vgic_apr));
+  DEFINE(VGIC_CPU_LR,          offsetof(struct vgic_cpu, 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
   return 0;
 }
index f4726dc054b3bbcdd7c7a5d98d3733b6a893ea3e..08018e3df580c65d259470175fc95319d0589322 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/ptrace.h>
 #include <linux/stat.h>
+#include <linux/uaccess.h>
 
 #include <asm/debug-monitors.h>
 #include <asm/local.h>
@@ -226,13 +227,74 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
        return 0;
 }
 
-static int __init single_step_init(void)
+static int brk_handler(unsigned long addr, unsigned int esr,
+                      struct pt_regs *regs)
+{
+       siginfo_t info;
+
+       if (!user_mode(regs))
+               return -EFAULT;
+
+       info = (siginfo_t) {
+               .si_signo = SIGTRAP,
+               .si_errno = 0,
+               .si_code  = TRAP_BRKPT,
+               .si_addr  = (void __user *)instruction_pointer(regs),
+       };
+
+       force_sig_info(SIGTRAP, &info, current);
+       return 0;
+}
+
+int aarch32_break_handler(struct pt_regs *regs)
+{
+       siginfo_t info;
+       unsigned int instr;
+       bool bp = false;
+       void __user *pc = (void __user *)instruction_pointer(regs);
+
+       if (!compat_user_mode(regs))
+               return -EFAULT;
+
+       if (compat_thumb_mode(regs)) {
+               /* get 16-bit Thumb instruction */
+               get_user(instr, (u16 __user *)pc);
+               if (instr == AARCH32_BREAK_THUMB2_LO) {
+                       /* get second half of 32-bit Thumb-2 instruction */
+                       get_user(instr, (u16 __user *)(pc + 2));
+                       bp = instr == AARCH32_BREAK_THUMB2_HI;
+               } else {
+                       bp = instr == AARCH32_BREAK_THUMB;
+               }
+       } else {
+               /* 32-bit ARM instruction */
+               get_user(instr, (u32 __user *)pc);
+               bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
+       }
+
+       if (!bp)
+               return -EFAULT;
+
+       info = (siginfo_t) {
+               .si_signo = SIGTRAP,
+               .si_errno = 0,
+               .si_code  = TRAP_BRKPT,
+               .si_addr  = pc,
+       };
+
+       force_sig_info(SIGTRAP, &info, current);
+       return 0;
+}
+
+static int __init debug_traps_init(void)
 {
        hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP,
                              TRAP_HWBKPT, "single-step handler");
+       hook_debug_fault_code(DBG_ESR_EVT_BRK, brk_handler, SIGTRAP,
+                             TRAP_BRKPT, "ptrace BRK handler");
        return 0;
 }
-arch_initcall(single_step_init);
+arch_initcall(debug_traps_init);
 
 /* Re-enable single step for syscall restarting. */
 void user_rewind_single_step(struct task_struct *task)
index 6e1e77f1831c0cb0bf31306822ebc72ba8d3158a..fecdbf7de82e9a94d6f467f5999428cfcf623145 100644 (file)
@@ -53,28 +53,6 @@ void ptrace_disable(struct task_struct *child)
 {
 }
 
-/*
- * Handle hitting a breakpoint.
- */
-static int ptrace_break(struct pt_regs *regs)
-{
-       siginfo_t info = {
-               .si_signo = SIGTRAP,
-               .si_errno = 0,
-               .si_code  = TRAP_BRKPT,
-               .si_addr  = (void __user *)instruction_pointer(regs),
-       };
-
-       force_sig_info(SIGTRAP, &info, current);
-       return 0;
-}
-
-static int arm64_break_trap(unsigned long addr, unsigned int esr,
-                           struct pt_regs *regs)
-{
-       return ptrace_break(regs);
-}
-
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 /*
  * Handle hitting a HW-breakpoint.
@@ -817,33 +795,6 @@ static const struct user_regset_view user_aarch32_view = {
        .regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets)
 };
 
-int aarch32_break_trap(struct pt_regs *regs)
-{
-       unsigned int instr;
-       bool bp = false;
-       void __user *pc = (void __user *)instruction_pointer(regs);
-
-       if (compat_thumb_mode(regs)) {
-               /* get 16-bit Thumb instruction */
-               get_user(instr, (u16 __user *)pc);
-               if (instr == AARCH32_BREAK_THUMB2_LO) {
-                       /* get second half of 32-bit Thumb-2 instruction */
-                       get_user(instr, (u16 __user *)(pc + 2));
-                       bp = instr == AARCH32_BREAK_THUMB2_HI;
-               } else {
-                       bp = instr == AARCH32_BREAK_THUMB;
-               }
-       } else {
-               /* 32-bit ARM instruction */
-               get_user(instr, (u32 __user *)pc);
-               bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
-       }
-
-       if (bp)
-               return ptrace_break(regs);
-       return 1;
-}
-
 static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
                                   compat_ulong_t __user *ret)
 {
@@ -1111,16 +1062,6 @@ long arch_ptrace(struct task_struct *child, long request,
        return ptrace_request(child, request, addr, data);
 }
 
-
-static int __init ptrace_break_init(void)
-{
-       hook_debug_fault_code(DBG_ESR_EVT_BRK, arm64_break_trap, SIGTRAP,
-                             TRAP_BRKPT, "ptrace BRK handler");
-       return 0;
-}
-core_initcall(ptrace_break_init);
-
-
 asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
 {
        unsigned long saved_reg;
index a551f88ae2c13e173749e75c80a2776f8d2a80cf..03dc3718eb136d24db7295133709a4a9e92c21b5 100644 (file)
@@ -68,12 +68,6 @@ unsigned long long notrace sched_clock(void)
        return arch_timer_read_counter() * sched_clock_mult;
 }
 
-int read_current_timer(unsigned long *timer_value)
-{
-       *timer_value = arch_timer_read_counter();
-       return 0;
-}
-
 void __init time_init(void)
 {
        u32 arch_timer_rate;
index f30852d28590358c6780a22c14049f92a124bdb8..7ffadddb645d32cda5fd54a0c2a5a0c5456b4018 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/syscalls.h>
 
 #include <asm/atomic.h>
+#include <asm/debug-monitors.h>
 #include <asm/traps.h>
 #include <asm/stacktrace.h>
 #include <asm/exception.h>
@@ -261,11 +262,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
        siginfo_t info;
        void __user *pc = (void __user *)instruction_pointer(regs);
 
-#ifdef CONFIG_COMPAT
        /* check for AArch32 breakpoint instructions */
-       if (compat_user_mode(regs) && aarch32_break_trap(regs) == 0)
+       if (!aarch32_break_handler(regs))
                return;
-#endif
 
        if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
            printk_ratelimit()) {
index 3fae2be8b01687a89f12ef87b9a1ae13fa6ab478..f5e55747242f3e9562f70224e764e4661d81fb83 100644 (file)
@@ -17,6 +17,19 @@ ENTRY(stext)
 
 jiffies = jiffies_64;
 
+#define HYPERVISOR_TEXT                                        \
+       /*                                              \
+        * Force the alignment to be compatible with    \
+        * the vectors requirements                     \
+        */                                             \
+       . = ALIGN(2048);                                \
+       VMLINUX_SYMBOL(__hyp_idmap_text_start) = .;     \
+       *(.hyp.idmap.text)                              \
+       VMLINUX_SYMBOL(__hyp_idmap_text_end) = .;       \
+       VMLINUX_SYMBOL(__hyp_text_start) = .;           \
+       *(.hyp.text)                                    \
+       VMLINUX_SYMBOL(__hyp_text_end) = .;
+
 SECTIONS
 {
        /*
@@ -49,6 +62,7 @@ SECTIONS
                        TEXT_TEXT
                        SCHED_TEXT
                        LOCK_TEXT
+                       HYPERVISOR_TEXT
                        *(.fixup)
                        *(.gnu.warning)
                . = ALIGN(16);
@@ -56,7 +70,7 @@ SECTIONS
        }
 
        RO_DATA(PAGE_SIZE)
-
+       EXCEPTION_TABLE(8)
        _etext = .;                     /* End of text and rodata section */
 
        . = ALIGN(PAGE_SIZE);
@@ -98,14 +112,6 @@ SECTIONS
                CACHELINE_ALIGNED_DATA(64)
                READ_MOSTLY_DATA(64)
 
-               /*
-                * The exception fixup table (might need resorting at runtime)
-                */
-               . = ALIGN(32);
-               __start___ex_table = .;
-               *(__ex_table)
-               __stop___ex_table = .;
-
                /*
                 * and the usual data section
                 */
@@ -124,3 +130,9 @@ SECTIONS
        STABS_DEBUG
        .comment 0 : { *(.comment) }
 }
+
+/*
+ * The HYP init code can't be more than a page long.
+ */
+ASSERT(((__hyp_idmap_text_start + PAGE_SIZE) > __hyp_idmap_text_end),
+       "HYP init code too big")
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
new file mode 100644 (file)
index 0000000..72a9fd5
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# Makefile for Kernel-based Virtual Machine module
+#
+
+ccflags-y += -Ivirt/kvm -Iarch/arm64/kvm
+CFLAGS_arm.o := -I.
+CFLAGS_mmu.o := -I.
+
+KVM=../../../virt/kvm
+ARM=../../../arch/arm/kvm
+
+obj-$(CONFIG_KVM_ARM_HOST) += kvm.o
+
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/arm.o $(ARM)/mmu.o $(ARM)/mmio.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/psci.o $(ARM)/perf.o
+
+kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
+kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
+kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o
+
+kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
+kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm64/kvm/emulate.c b/arch/arm64/kvm/emulate.c
new file mode 100644 (file)
index 0000000..124418d
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * (not much of an) Emulation layer for 32bit guests.
+ *
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * based on arch/arm/kvm/emulate.c
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.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/kvm_host.h>
+#include <asm/kvm_emulate.h>
+
+/*
+ * stolen from arch/arm/kernel/opcodes.c
+ *
+ * condition code lookup table
+ * index into the table is test code: EQ, NE, ... LT, GT, AL, NV
+ *
+ * bit position in short is condition code: NZCV
+ */
+static const unsigned short cc_map[16] = {
+       0xF0F0,                 /* EQ == Z set            */
+       0x0F0F,                 /* NE                     */
+       0xCCCC,                 /* CS == C set            */
+       0x3333,                 /* CC                     */
+       0xFF00,                 /* MI == N set            */
+       0x00FF,                 /* PL                     */
+       0xAAAA,                 /* VS == V set            */
+       0x5555,                 /* VC                     */
+       0x0C0C,                 /* HI == C set && Z clear */
+       0xF3F3,                 /* LS == C clear || Z set */
+       0xAA55,                 /* GE == (N==V)           */
+       0x55AA,                 /* LT == (N!=V)           */
+       0x0A05,                 /* GT == (!Z && (N==V))   */
+       0xF5FA,                 /* LE == (Z || (N!=V))    */
+       0xFFFF,                 /* AL always              */
+       0                       /* NV                     */
+};
+
+static int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
+{
+       u32 esr = kvm_vcpu_get_hsr(vcpu);
+
+       if (esr & ESR_EL2_CV)
+               return (esr & ESR_EL2_COND) >> ESR_EL2_COND_SHIFT;
+
+       return -1;
+}
+
+/*
+ * Check if a trapped instruction should have been executed or not.
+ */
+bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)
+{
+       unsigned long cpsr;
+       u32 cpsr_cond;
+       int cond;
+
+       /* Top two bits non-zero?  Unconditional. */
+       if (kvm_vcpu_get_hsr(vcpu) >> 30)
+               return true;
+
+       /* Is condition field valid? */
+       cond = kvm_vcpu_get_condition(vcpu);
+       if (cond == 0xE)
+               return true;
+
+       cpsr = *vcpu_cpsr(vcpu);
+
+       if (cond < 0) {
+               /* This can happen in Thumb mode: examine IT state. */
+               unsigned long it;
+
+               it = ((cpsr >> 8) & 0xFC) | ((cpsr >> 25) & 0x3);
+
+               /* it == 0 => unconditional. */
+               if (it == 0)
+                       return true;
+
+               /* The cond for this insn works out as the top 4 bits. */
+               cond = (it >> 4);
+       }
+
+       cpsr_cond = cpsr >> 28;
+
+       if (!((cc_map[cond] >> cpsr_cond) & 1))
+               return false;
+
+       return true;
+}
+
+/**
+ * adjust_itstate - adjust ITSTATE when emulating instructions in IT-block
+ * @vcpu:      The VCPU pointer
+ *
+ * When exceptions occur while instructions are executed in Thumb IF-THEN
+ * blocks, the ITSTATE field of the CPSR is not advanced (updated), so we have
+ * to do this little bit of work manually. The fields map like this:
+ *
+ * IT[7:0] -> CPSR[26:25],CPSR[15:10]
+ */
+static void kvm_adjust_itstate(struct kvm_vcpu *vcpu)
+{
+       unsigned long itbits, cond;
+       unsigned long cpsr = *vcpu_cpsr(vcpu);
+       bool is_arm = !(cpsr & COMPAT_PSR_T_BIT);
+
+       BUG_ON(is_arm && (cpsr & COMPAT_PSR_IT_MASK));
+
+       if (!(cpsr & COMPAT_PSR_IT_MASK))
+               return;
+
+       cond = (cpsr & 0xe000) >> 13;
+       itbits = (cpsr & 0x1c00) >> (10 - 2);
+       itbits |= (cpsr & (0x3 << 25)) >> 25;
+
+       /* Perform ITAdvance (see page A2-52 in ARM DDI 0406C) */
+       if ((itbits & 0x7) == 0)
+               itbits = cond = 0;
+       else
+               itbits = (itbits << 1) & 0x1f;
+
+       cpsr &= ~COMPAT_PSR_IT_MASK;
+       cpsr |= cond << 13;
+       cpsr |= (itbits & 0x1c) << (10 - 2);
+       cpsr |= (itbits & 0x3) << 25;
+       *vcpu_cpsr(vcpu) = cpsr;
+}
+
+/**
+ * kvm_skip_instr - skip a trapped instruction and proceed to the next
+ * @vcpu: The vcpu pointer
+ */
+void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr)
+{
+       bool is_thumb;
+
+       is_thumb = !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_T_BIT);
+       if (is_thumb && !is_wide_instr)
+               *vcpu_pc(vcpu) += 2;
+       else
+               *vcpu_pc(vcpu) += 4;
+       kvm_adjust_itstate(vcpu);
+}
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
new file mode 100644 (file)
index 0000000..2c3ff67
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/guest.c:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.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/errno.h>
+#include <linux/err.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#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>
+
+struct kvm_stats_debugfs_item debugfs_entries[] = {
+       { NULL }
+};
+
+int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
+       return 0;
+}
+
+static u64 core_reg_offset_from_id(u64 id)
+{
+       return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
+}
+
+static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       /*
+        * Because the kvm_regs structure is a mix of 32, 64 and
+        * 128bit fields, we index it as if it was a 32bit
+        * array. Hence below, nr_regs is the number of entries, and
+        * off the index in the "array".
+        */
+       __u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr;
+       struct kvm_regs *regs = vcpu_gp_regs(vcpu);
+       int nr_regs = sizeof(*regs) / sizeof(__u32);
+       u32 off;
+
+       /* Our ID is an index into the kvm_regs struct. */
+       off = core_reg_offset_from_id(reg->id);
+       if (off >= nr_regs ||
+           (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
+               return -ENOENT;
+
+       if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       __u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr;
+       struct kvm_regs *regs = vcpu_gp_regs(vcpu);
+       int nr_regs = sizeof(*regs) / sizeof(__u32);
+       __uint128_t tmp;
+       void *valp = &tmp;
+       u64 off;
+       int err = 0;
+
+       /* Our ID is an index into the kvm_regs struct. */
+       off = core_reg_offset_from_id(reg->id);
+       if (off >= nr_regs ||
+           (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
+               return -ENOENT;
+
+       if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
+               return -EINVAL;
+
+       if (copy_from_user(valp, uaddr, KVM_REG_SIZE(reg->id))) {
+               err = -EFAULT;
+               goto out;
+       }
+
+       if (off == KVM_REG_ARM_CORE_REG(regs.pstate)) {
+               u32 mode = (*(u32 *)valp) & COMPAT_PSR_MODE_MASK;
+               switch (mode) {
+               case COMPAT_PSR_MODE_USR:
+               case COMPAT_PSR_MODE_FIQ:
+               case COMPAT_PSR_MODE_IRQ:
+               case COMPAT_PSR_MODE_SVC:
+               case COMPAT_PSR_MODE_ABT:
+               case COMPAT_PSR_MODE_UND:
+               case PSR_MODE_EL0t:
+               case PSR_MODE_EL1t:
+               case PSR_MODE_EL1h:
+                       break;
+               default:
+                       err = -EINVAL;
+                       goto out;
+               }
+       }
+
+       memcpy((u32 *)regs + off, valp, KVM_REG_SIZE(reg->id));
+out:
+       return err;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+       return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+       return -EINVAL;
+}
+
+static unsigned long num_core_regs(void)
+{
+       return sizeof(struct kvm_regs) / sizeof(__u32);
+}
+
+/**
+ * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
+ *
+ * This is for all registers.
+ */
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
+{
+       return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu);
+}
+
+/**
+ * kvm_arm_copy_reg_indices - get indices of all registers.
+ *
+ * We do core registers right here, then we apppend system regs.
+ */
+int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+       unsigned int i;
+       const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
+
+       for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
+               if (put_user(core_reg | i, uindices))
+                       return -EFAULT;
+               uindices++;
+       }
+
+       return kvm_arm_copy_sys_reg_indices(vcpu, uindices);
+}
+
+int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       /* We currently use nothing arch-specific in upper 32 bits */
+       if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
+               return -EINVAL;
+
+       /* Register group 16 means we want a core register. */
+       if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
+               return get_core_reg(vcpu, reg);
+
+       return kvm_arm_sys_reg_get_reg(vcpu, reg);
+}
+
+int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       /* We currently use nothing arch-specific in upper 32 bits */
+       if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
+               return -EINVAL;
+
+       /* Register group 16 means we set a core register. */
+       if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
+               return set_core_reg(vcpu, reg);
+
+       return kvm_arm_sys_reg_set_reg(vcpu, reg);
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+                                 struct kvm_sregs *sregs)
+{
+       return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+                                 struct kvm_sregs *sregs)
+{
+       return -EINVAL;
+}
+
+int __attribute_const__ kvm_target_cpu(void)
+{
+       unsigned long implementor = read_cpuid_implementor();
+       unsigned long part_number = read_cpuid_part_number();
+
+       if (implementor != ARM_CPU_IMP_ARM)
+               return -EINVAL;
+
+       switch (part_number) {
+       case ARM_CPU_PART_AEM_V8:
+               return KVM_ARM_TARGET_AEM_V8;
+       case ARM_CPU_PART_FOUNDATION:
+               return KVM_ARM_TARGET_FOUNDATION_V8;
+       case ARM_CPU_PART_CORTEX_A57:
+               /* Currently handled by the generic backend */
+               return KVM_ARM_TARGET_CORTEX_A57;
+       default:
+               return -EINVAL;
+       }
+}
+
+int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
+                       const struct kvm_vcpu_init *init)
+{
+       unsigned int i;
+       int phys_target = kvm_target_cpu();
+
+       if (init->target != phys_target)
+               return -EINVAL;
+
+       vcpu->arch.target = phys_target;
+       bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES);
+
+       /* -ENOENT for unknown features, -EINVAL for invalid combinations. */
+       for (i = 0; i < sizeof(init->features) * 8; i++) {
+               if (init->features[i / 32] & (1 << (i % 32))) {
+                       if (i >= KVM_VCPU_MAX_FEATURES)
+                               return -ENOENT;
+                       set_bit(i, vcpu->arch.features);
+               }
+       }
+
+       /* Now we know what it is, we can reset it. */
+       return kvm_reset_vcpu(vcpu);
+}
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+       return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+       return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+                                 struct kvm_translation *tr)
+{
+       return -EINVAL;
+}
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
new file mode 100644 (file)
index 0000000..9beaca0
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/handle_exit.c:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.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/kvm.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+#include <asm/kvm_mmu.h>
+#include <asm/kvm_psci.h>
+
+typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
+
+static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+       if (kvm_psci_call(vcpu))
+               return 1;
+
+       kvm_inject_undefined(vcpu);
+       return 1;
+}
+
+static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+       if (kvm_psci_call(vcpu))
+               return 1;
+
+       kvm_inject_undefined(vcpu);
+       return 1;
+}
+
+/**
+ * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
+ * @vcpu:      the vcpu pointer
+ *
+ * Simply call kvm_vcpu_block(), which will halt execution of
+ * world-switches and schedule other host processes until there is an
+ * incoming IRQ or FIQ to the VM.
+ */
+static int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+       kvm_vcpu_block(vcpu);
+       return 1;
+}
+
+static exit_handle_fn arm_exit_handlers[] = {
+       [ESR_EL2_EC_WFI]        = kvm_handle_wfi,
+       [ESR_EL2_EC_CP15_32]    = kvm_handle_cp15_32,
+       [ESR_EL2_EC_CP15_64]    = kvm_handle_cp15_64,
+       [ESR_EL2_EC_CP14_MR]    = kvm_handle_cp14_access,
+       [ESR_EL2_EC_CP14_LS]    = kvm_handle_cp14_load_store,
+       [ESR_EL2_EC_CP14_64]    = kvm_handle_cp14_access,
+       [ESR_EL2_EC_HVC32]      = handle_hvc,
+       [ESR_EL2_EC_SMC32]      = handle_smc,
+       [ESR_EL2_EC_HVC64]      = handle_hvc,
+       [ESR_EL2_EC_SMC64]      = handle_smc,
+       [ESR_EL2_EC_SYS64]      = kvm_handle_sys_reg,
+       [ESR_EL2_EC_IABT]       = kvm_handle_guest_abort,
+       [ESR_EL2_EC_DABT]       = kvm_handle_guest_abort,
+};
+
+static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
+{
+       u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
+
+       if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers) ||
+           !arm_exit_handlers[hsr_ec]) {
+               kvm_err("Unkown exception class: hsr: %#08x\n",
+                       (unsigned int)kvm_vcpu_get_hsr(vcpu));
+               BUG();
+       }
+
+       return arm_exit_handlers[hsr_ec];
+}
+
+/*
+ * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
+ * proper exit to userspace.
+ */
+int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
+                      int exception_index)
+{
+       exit_handle_fn exit_handler;
+
+       switch (exception_index) {
+       case ARM_EXCEPTION_IRQ:
+               return 1;
+       case ARM_EXCEPTION_TRAP:
+               /*
+                * See ARM ARM B1.14.1: "Hyp traps on instructions
+                * that fail their condition code check"
+                */
+               if (!kvm_condition_valid(vcpu)) {
+                       kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+                       return 1;
+               }
+
+               exit_handler = kvm_get_exit_handler(vcpu);
+
+               return exit_handler(vcpu, run);
+       default:
+               kvm_pr_unimpl("Unsupported exception type: %d",
+                             exception_index);
+               run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+               return 0;
+       }
+}
diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
new file mode 100644 (file)
index 0000000..ba84e67
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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 <asm/assembler.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+
+       .text
+       .pushsection    .hyp.idmap.text, "ax"
+
+       .align  11
+
+ENTRY(__kvm_hyp_init)
+       ventry  __invalid               // Synchronous EL2t
+       ventry  __invalid               // IRQ EL2t
+       ventry  __invalid               // FIQ EL2t
+       ventry  __invalid               // Error EL2t
+
+       ventry  __invalid               // Synchronous EL2h
+       ventry  __invalid               // IRQ EL2h
+       ventry  __invalid               // FIQ EL2h
+       ventry  __invalid               // Error EL2h
+
+       ventry  __do_hyp_init           // Synchronous 64-bit EL1
+       ventry  __invalid               // IRQ 64-bit EL1
+       ventry  __invalid               // FIQ 64-bit EL1
+       ventry  __invalid               // Error 64-bit EL1
+
+       ventry  __invalid               // Synchronous 32-bit EL1
+       ventry  __invalid               // IRQ 32-bit EL1
+       ventry  __invalid               // FIQ 32-bit EL1
+       ventry  __invalid               // Error 32-bit EL1
+
+__invalid:
+       b       .
+
+       /*
+        * x0: HYP boot pgd
+        * x1: HYP pgd
+        * x2: HYP stack
+        * x3: HYP vectors
+        */
+__do_hyp_init:
+
+       msr     ttbr0_el2, x0
+
+       mrs     x4, tcr_el1
+       ldr     x5, =TCR_EL2_MASK
+       and     x4, x4, x5
+       ldr     x5, =TCR_EL2_FLAGS
+       orr     x4, x4, x5
+       msr     tcr_el2, x4
+
+       ldr     x4, =VTCR_EL2_FLAGS
+       msr     vtcr_el2, x4
+
+       mrs     x4, mair_el1
+       msr     mair_el2, x4
+       isb
+
+       mov     x4, #SCTLR_EL2_FLAGS
+       msr     sctlr_el2, x4
+       isb
+
+       /* MMU is now enabled. Get ready for the trampoline dance */
+       ldr     x4, =TRAMPOLINE_VA
+       adr     x5, target
+       bfi     x4, x5, #0, #PAGE_SHIFT
+       br      x4
+
+target: /* We're now in the trampoline code, switch page tables */
+       msr     ttbr0_el2, x1
+       isb
+
+       /* Invalidate the old TLBs */
+       tlbi    alle2
+       dsb     sy
+
+       /* Set the stack and new vectors */
+       kern_hyp_va     x2
+       mov     sp, x2
+       kern_hyp_va     x3
+       msr     vbar_el2, x3
+
+       /* Hello, World! */
+       eret
+ENDPROC(__kvm_hyp_init)
+
+       .ltorg
+
+       .popsection
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
new file mode 100644 (file)
index 0000000..ff985e3
--- /dev/null
@@ -0,0 +1,831 @@
+/*
+ * 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/fpsimdmacros.h>
+#include <asm/kvm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.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)
+#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
+
+__kvm_hyp_code_start:
+       .globl __kvm_hyp_code_start
+
+.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            // EL1 PC
+       mrs     x21, spsr_el2           // EL1 pstate
+
+       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                            // EL1 PC
+       msr     spsr_el2, x21                           // EL1 pstate
+
+       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
+
+       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]
+.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]
+
+       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
+.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 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
+       mrs     x6, fpexc32_el2
+       mrs     x7, dbgvcr32_el2
+       stp     x4, x5, [x3]
+       stp     x6, x7, [x3, #16]
+
+       skip_tee_state x8, 1f
+
+       add     x3, x2, #CPU_SYSREG_OFFSET(TEECR32_EL1)
+       mrs     x4, teecr32_el1
+       mrs     x5, teehbr32_el1
+       stp     x4, x5, [x3]
+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]
+       ldp     x6, x7, [x3, #16]
+       msr     dacr32_el2, x4
+       msr     ifsr32_el2, x5
+       msr     fpexc32_el2, x6
+       msr     dbgvcr32_el2, x7
+
+       skip_tee_state x8, 1f
+
+       add     x3, x2, #CPU_SYSREG_OFFSET(TEECR32_EL1)
+       ldp     x4, x5, [x3]
+       msr     teecr32_el1, x4
+       msr     teehbr32_el1, x5
+1:
+.endm
+
+.macro activate_traps
+       ldr     x2, [x0, #VCPU_IRQ_LINES]
+       ldr     x1, [x0, #VCPU_HCR_EL2]
+       orr     x2, x2, x1
+       msr     hcr_el2, x2
+
+       ldr     x2, =(CPTR_EL2_TTA)
+       msr     cptr_el2, x2
+
+       ldr     x2, =(1 << 15)  // Trap CP15 Cr=15
+       msr     hstr_el2, x2
+
+       mrs     x2, mdcr_el2
+       and     x2, x2, #MDCR_EL2_HPMN_MASK
+       orr     x2, x2, #(MDCR_EL2_TPM | MDCR_EL2_TPMCR)
+       msr     mdcr_el2, x2
+.endm
+
+.macro deactivate_traps
+       mov     x2, #HCR_RW
+       msr     hcr_el2, x2
+       msr     cptr_el2, xzr
+       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
+
+/*
+ * Save the VGIC CPU state into memory
+ * x0: Register pointing to VCPU struct
+ * Do not corrupt x1!!!
+ */
+.macro save_vgic_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     w4, [x2, #GICH_HCR]
+       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]
+
+       str     w4, [x3, #VGIC_CPU_HCR]
+       str     w5, [x3, #VGIC_CPU_VMCR]
+       str     w6, [x3, #VGIC_CPU_MISR]
+       str     w7, [x3, #VGIC_CPU_EISR]
+       str     w8, [x3, #(VGIC_CPU_EISR + 4)]
+       str     w9, [x3, #VGIC_CPU_ELRSR]
+       str     w10, [x3, #(VGIC_CPU_ELRSR + 4)]
+       str     w11, [x3, #VGIC_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_CPU_LR
+1:     ldr     w5, [x2], #4
+       str     w5, [x3], #4
+       sub     w4, w4, #1
+       cbnz    w4, 1b
+2:
+.endm
+
+/*
+ * Restore the VGIC CPU state from memory
+ * x0: Register pointing to VCPU struct
+ */
+.macro restore_vgic_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_CPU_HCR]
+       ldr     w5, [x3, #VGIC_CPU_VMCR]
+       ldr     w6, [x3, #VGIC_CPU_APR]
+
+       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_CPU_LR
+1:     ldr     w5, [x3], #4
+       str     w5, [x2], #4
+       sub     w4, w4, #1
+       cbnz    w4, 1b
+2:
+.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]
+       bic     x3, x3, #1              // Clear Enable
+       msr     cntv_ctl_el0, x3
+
+       isb
+
+       mrs     x3, cntv_cval_el0
+       str     x3, [x0, #VCPU_TIMER_CNTV_CVAL]
+
+1:
+       // 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_fpsimd:
+       save_fpsimd
+       ret
+
+__restore_fpsimd:
+       restore_fpsimd
+       ret
+
+/*
+ * 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_fpsimd
+       bl __save_sysregs
+
+       activate_traps
+       activate_vm
+
+       restore_vgic_state
+       restore_timer_state
+
+       // Guest context
+       add     x2, x0, #VCPU_CONTEXT
+
+       bl __restore_sysregs
+       bl __restore_fpsimd
+       restore_guest_32bit_state
+       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
+       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
+       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)
+       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...
+        */
+       tlbi    ipas2e1is, x1
+       dsb     sy
+       tlbi    vmalle1is
+       dsb     sy
+       isb
+
+       msr     vttbr_el2, xzr
+       ret
+ENDPROC(__kvm_tlb_flush_vmid_ipa)
+
+ENTRY(__kvm_flush_vm_context)
+       tlbi    alle1is
+       ic      ialluis
+       dsb     sy
+       ret
+ENDPROC(__kvm_flush_vm_context)
+
+__kvm_hyp_panic:
+       // 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
+
+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
+       mrs     x6, 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:%p ESR:%p\nFAR:%p HPFAR:%p PAR:%p\nVCPU:%p\n\0"
+
+       .align  2
+
+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_EL2_EC_SHIFT
+
+       cmp     x2, #ESR_EL2_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
+
+       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
+       eret
+
+el1_trap:
+       /*
+        * x1: ESR
+        * x2: ESR_EC
+        */
+       cmp     x2, #ESR_EL2_EC_DABT
+       mov     x0, #ESR_EL2_EC_IABT
+       ccmp    x2, x0, #4, ne
+       b.ne    1f              // Not an abort we care about
+
+       /* This is an abort. Check for permission fault */
+       and     x2, x1, #ESR_EL2_FSC_TYPE
+       cmp     x2, #FSC_PERM
+       b.ne    1f              // Not a permission fault
+
+       /*
+        * Check for Stage-1 page table walk, which is guaranteed
+        * to give a valid HPFAR_EL2.
+        */
+       tbnz    x1, #7, 1f      // S1PTW is set
+
+       /*
+        * 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
+       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     x1, [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)
+
+__kvm_hyp_code_end:
+       .globl  __kvm_hyp_code_end
+
+       .popsection
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
new file mode 100644 (file)
index 0000000..81a02a8
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Fault injection for both 32 and 64bit guests.
+ *
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Based on arch/arm/kvm/emulate.c
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.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/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/esr.h>
+
+#define PSTATE_FAULT_BITS_64   (PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
+                                PSR_I_BIT | PSR_D_BIT)
+#define EL1_EXCEPT_SYNC_OFFSET 0x200
+
+static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
+{
+       unsigned long cpsr;
+       unsigned long new_spsr_value = *vcpu_cpsr(vcpu);
+       bool is_thumb = (new_spsr_value & COMPAT_PSR_T_BIT);
+       u32 return_offset = (is_thumb) ? 4 : 0;
+       u32 sctlr = vcpu_cp15(vcpu, c1_SCTLR);
+
+       cpsr = mode | COMPAT_PSR_I_BIT;
+
+       if (sctlr & (1 << 30))
+               cpsr |= COMPAT_PSR_T_BIT;
+       if (sctlr & (1 << 25))
+               cpsr |= COMPAT_PSR_E_BIT;
+
+       *vcpu_cpsr(vcpu) = cpsr;
+
+       /* Note: These now point to the banked copies */
+       *vcpu_spsr(vcpu) = new_spsr_value;
+       *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
+
+       /* Branch to exception vector */
+       if (sctlr & (1 << 13))
+               vect_offset += 0xffff0000;
+       else /* always have security exceptions */
+               vect_offset += vcpu_cp15(vcpu, c12_VBAR);
+
+       *vcpu_pc(vcpu) = vect_offset;
+}
+
+static void inject_undef32(struct kvm_vcpu *vcpu)
+{
+       prepare_fault32(vcpu, COMPAT_PSR_MODE_UND, 4);
+}
+
+/*
+ * Modelled after TakeDataAbortException() and TakePrefetchAbortException
+ * pseudocode.
+ */
+static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
+                        unsigned long addr)
+{
+       u32 vect_offset;
+       u32 *far, *fsr;
+       bool is_lpae;
+
+       if (is_pabt) {
+               vect_offset = 12;
+               far = &vcpu_cp15(vcpu, c6_IFAR);
+               fsr = &vcpu_cp15(vcpu, c5_IFSR);
+       } else { /* !iabt */
+               vect_offset = 16;
+               far = &vcpu_cp15(vcpu, c6_DFAR);
+               fsr = &vcpu_cp15(vcpu, c5_DFSR);
+       }
+
+       prepare_fault32(vcpu, COMPAT_PSR_MODE_ABT | COMPAT_PSR_A_BIT, vect_offset);
+
+       *far = addr;
+
+       /* Give the guest an IMPLEMENTATION DEFINED exception */
+       is_lpae = (vcpu_cp15(vcpu, c2_TTBCR) >> 31);
+       if (is_lpae)
+               *fsr = 1 << 9 | 0x34;
+       else
+               *fsr = 0x14;
+}
+
+static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
+{
+       unsigned long cpsr = *vcpu_cpsr(vcpu);
+       bool is_aarch32;
+       u32 esr = 0;
+
+       is_aarch32 = vcpu_mode_is_32bit(vcpu);
+
+       *vcpu_spsr(vcpu) = cpsr;
+       *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
+
+       *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
+       *vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
+
+       vcpu_sys_reg(vcpu, FAR_EL1) = addr;
+
+       /*
+        * Build an {i,d}abort, depending on the level and the
+        * instruction set. Report an external synchronous abort.
+        */
+       if (kvm_vcpu_trap_il_is32bit(vcpu))
+               esr |= ESR_EL1_IL;
+
+       /*
+        * Here, the guest runs in AArch64 mode when in EL1. If we get
+        * an AArch32 fault, it means we managed to trap an EL0 fault.
+        */
+       if (is_aarch32 || (cpsr & PSR_MODE_MASK) == PSR_MODE_EL0t)
+               esr |= (ESR_EL1_EC_IABT_EL0 << ESR_EL1_EC_SHIFT);
+       else
+               esr |= (ESR_EL1_EC_IABT_EL1 << ESR_EL1_EC_SHIFT);
+
+       if (!is_iabt)
+               esr |= ESR_EL1_EC_DABT_EL0;
+
+       vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_EL2_EC_xABT_xFSR_EXTABT;
+}
+
+static void inject_undef64(struct kvm_vcpu *vcpu)
+{
+       unsigned long cpsr = *vcpu_cpsr(vcpu);
+       u32 esr = (ESR_EL1_EC_UNKNOWN << ESR_EL1_EC_SHIFT);
+
+       *vcpu_spsr(vcpu) = cpsr;
+       *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
+
+       *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
+       *vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
+
+       /*
+        * Build an unknown exception, depending on the instruction
+        * set.
+        */
+       if (kvm_vcpu_trap_il_is32bit(vcpu))
+               esr |= ESR_EL1_IL;
+
+       vcpu_sys_reg(vcpu, ESR_EL1) = esr;
+}
+
+/**
+ * kvm_inject_dabt - inject a data abort into the guest
+ * @vcpu: The VCPU to receive the undefined exception
+ * @addr: The address to report in the DFAR
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
+{
+       if (!(vcpu->arch.hcr_el2 & HCR_RW))
+               inject_abt32(vcpu, false, addr);
+
+       inject_abt64(vcpu, false, addr);
+}
+
+/**
+ * kvm_inject_pabt - inject a prefetch abort into the guest
+ * @vcpu: The VCPU to receive the undefined exception
+ * @addr: The address to report in the DFAR
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
+{
+       if (!(vcpu->arch.hcr_el2 & HCR_RW))
+               inject_abt32(vcpu, true, addr);
+
+       inject_abt64(vcpu, true, addr);
+}
+
+/**
+ * kvm_inject_undefined - inject an undefined instruction into the guest
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_undefined(struct kvm_vcpu *vcpu)
+{
+       if (!(vcpu->arch.hcr_el2 & HCR_RW))
+               inject_undef32(vcpu);
+
+       inject_undef64(vcpu);
+}
diff --git a/arch/arm64/kvm/regmap.c b/arch/arm64/kvm/regmap.c
new file mode 100644 (file)
index 0000000..bbc6ae3
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/emulate.c:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.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/mm.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/ptrace.h>
+
+#define VCPU_NR_MODES 6
+#define REG_OFFSET(_reg) \
+       (offsetof(struct user_pt_regs, _reg) / sizeof(unsigned long))
+
+#define USR_REG_OFFSET(R) REG_OFFSET(compat_usr(R))
+
+static const unsigned long vcpu_reg_offsets[VCPU_NR_MODES][16] = {
+       /* USR Registers */
+       {
+               USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+               USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+               USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+               USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+               USR_REG_OFFSET(12), USR_REG_OFFSET(13), USR_REG_OFFSET(14),
+               REG_OFFSET(pc)
+       },
+
+       /* FIQ Registers */
+       {
+               USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+               USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+               USR_REG_OFFSET(6), USR_REG_OFFSET(7),
+               REG_OFFSET(compat_r8_fiq),  /* r8 */
+               REG_OFFSET(compat_r9_fiq),  /* r9 */
+               REG_OFFSET(compat_r10_fiq), /* r10 */
+               REG_OFFSET(compat_r11_fiq), /* r11 */
+               REG_OFFSET(compat_r12_fiq), /* r12 */
+               REG_OFFSET(compat_sp_fiq),  /* r13 */
+               REG_OFFSET(compat_lr_fiq),  /* r14 */
+               REG_OFFSET(pc)
+       },
+
+       /* IRQ Registers */
+       {
+               USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+               USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+               USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+               USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+               USR_REG_OFFSET(12),
+               REG_OFFSET(compat_sp_irq), /* r13 */
+               REG_OFFSET(compat_lr_irq), /* r14 */
+               REG_OFFSET(pc)
+       },
+
+       /* SVC Registers */
+       {
+               USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+               USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+               USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+               USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+               USR_REG_OFFSET(12),
+               REG_OFFSET(compat_sp_svc), /* r13 */
+               REG_OFFSET(compat_lr_svc), /* r14 */
+               REG_OFFSET(pc)
+       },
+
+       /* ABT Registers */
+       {
+               USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+               USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+               USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+               USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+               USR_REG_OFFSET(12),
+               REG_OFFSET(compat_sp_abt), /* r13 */
+               REG_OFFSET(compat_lr_abt), /* r14 */
+               REG_OFFSET(pc)
+       },
+
+       /* UND Registers */
+       {
+               USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+               USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+               USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+               USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+               USR_REG_OFFSET(12),
+               REG_OFFSET(compat_sp_und), /* r13 */
+               REG_OFFSET(compat_lr_und), /* r14 */
+               REG_OFFSET(pc)
+       },
+};
+
+/*
+ * Return a pointer to the register number valid in the current mode of
+ * the virtual CPU.
+ */
+unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num)
+{
+       unsigned long *reg_array = (unsigned long *)&vcpu->arch.ctxt.gp_regs.regs;
+       unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
+
+       switch (mode) {
+       case COMPAT_PSR_MODE_USR ... COMPAT_PSR_MODE_SVC:
+               mode &= ~PSR_MODE32_BIT; /* 0 ... 3 */
+               break;
+
+       case COMPAT_PSR_MODE_ABT:
+               mode = 4;
+               break;
+
+       case COMPAT_PSR_MODE_UND:
+               mode = 5;
+               break;
+
+       case COMPAT_PSR_MODE_SYS:
+               mode = 0;       /* SYS maps to USR */
+               break;
+
+       default:
+               BUG();
+       }
+
+       return reg_array + vcpu_reg_offsets[mode][reg_num];
+}
+
+/*
+ * Return the SPSR for the current mode of the virtual CPU.
+ */
+unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu)
+{
+       unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
+       switch (mode) {
+       case COMPAT_PSR_MODE_SVC:
+               mode = KVM_SPSR_SVC;
+               break;
+       case COMPAT_PSR_MODE_ABT:
+               mode = KVM_SPSR_ABT;
+               break;
+       case COMPAT_PSR_MODE_UND:
+               mode = KVM_SPSR_UND;
+               break;
+       case COMPAT_PSR_MODE_IRQ:
+               mode = KVM_SPSR_IRQ;
+               break;
+       case COMPAT_PSR_MODE_FIQ:
+               mode = KVM_SPSR_FIQ;
+               break;
+       default:
+               BUG();
+       }
+
+       return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[mode];
+}
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
new file mode 100644 (file)
index 0000000..70a7816
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/reset.c
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.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/errno.h>
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+
+#include <kvm/arm_arch_timer.h>
+
+#include <asm/cputype.h>
+#include <asm/ptrace.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_coproc.h>
+
+/*
+ * ARMv8 Reset Values
+ */
+static const struct kvm_regs default_regs_reset = {
+       .regs.pstate = (PSR_MODE_EL1h | PSR_A_BIT | PSR_I_BIT |
+                       PSR_F_BIT | PSR_D_BIT),
+};
+
+static const struct kvm_regs default_regs_reset32 = {
+       .regs.pstate = (COMPAT_PSR_MODE_SVC | COMPAT_PSR_A_BIT |
+                       COMPAT_PSR_I_BIT | COMPAT_PSR_F_BIT),
+};
+
+static const struct kvm_irq_level default_vtimer_irq = {
+       .irq    = 27,
+       .level  = 1,
+};
+
+static bool cpu_has_32bit_el1(void)
+{
+       u64 pfr0;
+
+       pfr0 = read_cpuid(ID_AA64PFR0_EL1);
+       return !!(pfr0 & 0x20);
+}
+
+int kvm_arch_dev_ioctl_check_extension(long ext)
+{
+       int r;
+
+       switch (ext) {
+       case KVM_CAP_ARM_EL1_32BIT:
+               r = cpu_has_32bit_el1();
+               break;
+       default:
+               r = 0;
+       }
+
+       return r;
+}
+
+/**
+ * kvm_reset_vcpu - sets core registers and sys_regs to reset value
+ * @vcpu: The VCPU pointer
+ *
+ * This function finds the right table above and sets the registers on
+ * the virtual CPU struct to their architectually defined reset
+ * values.
+ */
+int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
+{
+       const struct kvm_irq_level *cpu_vtimer_irq;
+       const struct kvm_regs *cpu_reset;
+
+       switch (vcpu->arch.target) {
+       default:
+               if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) {
+                       if (!cpu_has_32bit_el1())
+                               return -EINVAL;
+                       cpu_reset = &default_regs_reset32;
+                       vcpu->arch.hcr_el2 &= ~HCR_RW;
+               } else {
+                       cpu_reset = &default_regs_reset;
+               }
+
+               cpu_vtimer_irq = &default_vtimer_irq;
+               break;
+       }
+
+       /* Reset core registers */
+       memcpy(vcpu_gp_regs(vcpu), cpu_reset, sizeof(*cpu_reset));
+
+       /* Reset system registers */
+       kvm_reset_sys_regs(vcpu);
+
+       /* Reset timer */
+       kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
+
+       return 0;
+}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
new file mode 100644 (file)
index 0000000..9492360
--- /dev/null
@@ -0,0 +1,1050 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/coproc.c:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Authors: Rusty Russell <rusty@rustcorp.com.au>
+ *          Christoffer Dall <c.dall@virtualopensystems.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/mm.h>
+#include <linux/kvm_host.h>
+#include <linux/uaccess.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <trace/events/kvm.h>
+
+#include "sys_regs.h"
+
+/*
+ * All of this file is extremly similar to the ARM coproc.c, but the
+ * types are different. My gut feeling is that it should be pretty
+ * easy to merge, but that would be an ABI breakage -- again. VFP
+ * would also need to be abstracted.
+ *
+ * For AArch32, we only take care of what is being trapped. Anything
+ * that has to do with init and userspace access has to go via the
+ * 64bit interface.
+ */
+
+/* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
+static u32 cache_levels;
+
+/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */
+#define CSSELR_MAX 12
+
+/* Which cache CCSIDR represents depends on CSSELR value. */
+static u32 get_ccsidr(u32 csselr)
+{
+       u32 ccsidr;
+
+       /* Make sure noone else changes CSSELR during this! */
+       local_irq_disable();
+       /* Put value into CSSELR */
+       asm volatile("msr csselr_el1, %x0" : : "r" (csselr));
+       isb();
+       /* Read result out of CCSIDR */
+       asm volatile("mrs %0, ccsidr_el1" : "=r" (ccsidr));
+       local_irq_enable();
+
+       return ccsidr;
+}
+
+static void do_dc_cisw(u32 val)
+{
+       asm volatile("dc cisw, %x0" : : "r" (val));
+       dsb();
+}
+
+static void do_dc_csw(u32 val)
+{
+       asm volatile("dc csw, %x0" : : "r" (val));
+       dsb();
+}
+
+/* See note at ARM ARM B1.14.4 */
+static bool access_dcsw(struct kvm_vcpu *vcpu,
+                       const struct sys_reg_params *p,
+                       const struct sys_reg_desc *r)
+{
+       unsigned long val;
+       int cpu;
+
+       if (!p->is_write)
+               return read_from_write_only(vcpu, p);
+
+       cpu = get_cpu();
+
+       cpumask_setall(&vcpu->arch.require_dcache_flush);
+       cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush);
+
+       /* If we were already preempted, take the long way around */
+       if (cpu != vcpu->arch.last_pcpu) {
+               flush_cache_all();
+               goto done;
+       }
+
+       val = *vcpu_reg(vcpu, p->Rt);
+
+       switch (p->CRm) {
+       case 6:                 /* Upgrade DCISW to DCCISW, as per HCR.SWIO */
+       case 14:                /* DCCISW */
+               do_dc_cisw(val);
+               break;
+
+       case 10:                /* DCCSW */
+               do_dc_csw(val);
+               break;
+       }
+
+done:
+       put_cpu();
+
+       return true;
+}
+
+/*
+ * We could trap ID_DFR0 and tell the guest we don't support performance
+ * monitoring.  Unfortunately the patch to make the kernel check ID_DFR0 was
+ * NAKed, so it will read the PMCR anyway.
+ *
+ * Therefore we tell the guest we have 0 counters.  Unfortunately, we
+ * must always support PMCCNTR (the cycle counter): we just RAZ/WI for
+ * all PM registers, which doesn't crash the guest kernel at least.
+ */
+static bool pm_fake(struct kvm_vcpu *vcpu,
+                   const struct sys_reg_params *p,
+                   const struct sys_reg_desc *r)
+{
+       if (p->is_write)
+               return ignore_write(vcpu, p);
+       else
+               return read_zero(vcpu, p);
+}
+
+static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+       u64 amair;
+
+       asm volatile("mrs %0, amair_el1\n" : "=r" (amair));
+       vcpu_sys_reg(vcpu, AMAIR_EL1) = amair;
+}
+
+static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+       /*
+        * Simply map the vcpu_id into the Aff0 field of the MPIDR.
+        */
+       vcpu_sys_reg(vcpu, MPIDR_EL1) = (1UL << 31) | (vcpu->vcpu_id & 0xff);
+}
+
+/*
+ * Architected system registers.
+ * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
+ */
+static const struct sys_reg_desc sys_reg_descs[] = {
+       /* DC ISW */
+       { Op0(0b01), Op1(0b000), CRn(0b0111), CRm(0b0110), Op2(0b010),
+         access_dcsw },
+       /* DC CSW */
+       { Op0(0b01), Op1(0b000), CRn(0b0111), CRm(0b1010), Op2(0b010),
+         access_dcsw },
+       /* DC CISW */
+       { Op0(0b01), Op1(0b000), CRn(0b0111), CRm(0b1110), Op2(0b010),
+         access_dcsw },
+
+       /* TEECR32_EL1 */
+       { Op0(0b10), Op1(0b010), CRn(0b0000), CRm(0b0000), Op2(0b000),
+         NULL, reset_val, TEECR32_EL1, 0 },
+       /* TEEHBR32_EL1 */
+       { Op0(0b10), Op1(0b010), CRn(0b0001), CRm(0b0000), Op2(0b000),
+         NULL, reset_val, TEEHBR32_EL1, 0 },
+       /* DBGVCR32_EL2 */
+       { Op0(0b10), Op1(0b100), CRn(0b0000), CRm(0b0111), Op2(0b000),
+         NULL, reset_val, DBGVCR32_EL2, 0 },
+
+       /* MPIDR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0000), Op2(0b101),
+         NULL, reset_mpidr, MPIDR_EL1 },
+       /* SCTLR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000),
+         NULL, reset_val, SCTLR_EL1, 0x00C50078 },
+       /* CPACR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010),
+         NULL, reset_val, CPACR_EL1, 0 },
+       /* TTBR0_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b000),
+         NULL, reset_unknown, TTBR0_EL1 },
+       /* TTBR1_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b001),
+         NULL, reset_unknown, TTBR1_EL1 },
+       /* TCR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b010),
+         NULL, reset_val, TCR_EL1, 0 },
+
+       /* AFSR0_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b000),
+         NULL, reset_unknown, AFSR0_EL1 },
+       /* AFSR1_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b001),
+         NULL, reset_unknown, AFSR1_EL1 },
+       /* ESR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0010), Op2(0b000),
+         NULL, reset_unknown, ESR_EL1 },
+       /* FAR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000),
+         NULL, reset_unknown, FAR_EL1 },
+
+       /* PMINTENSET_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
+         pm_fake },
+       /* PMINTENCLR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
+         pm_fake },
+
+       /* MAIR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
+         NULL, reset_unknown, MAIR_EL1 },
+       /* AMAIR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0011), Op2(0b000),
+         NULL, reset_amair_el1, AMAIR_EL1 },
+
+       /* VBAR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000),
+         NULL, reset_val, VBAR_EL1, 0 },
+       /* CONTEXTIDR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001),
+         NULL, reset_val, CONTEXTIDR_EL1, 0 },
+       /* TPIDR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b100),
+         NULL, reset_unknown, TPIDR_EL1 },
+
+       /* CNTKCTL_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b1110), CRm(0b0001), Op2(0b000),
+         NULL, reset_val, CNTKCTL_EL1, 0},
+
+       /* CSSELR_EL1 */
+       { Op0(0b11), Op1(0b010), CRn(0b0000), CRm(0b0000), Op2(0b000),
+         NULL, reset_unknown, CSSELR_EL1 },
+
+       /* PMCR_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b000),
+         pm_fake },
+       /* PMCNTENSET_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
+         pm_fake },
+       /* PMCNTENCLR_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
+         pm_fake },
+       /* PMOVSCLR_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
+         pm_fake },
+       /* PMSWINC_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
+         pm_fake },
+       /* PMSELR_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
+         pm_fake },
+       /* PMCEID0_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
+         pm_fake },
+       /* PMCEID1_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b111),
+         pm_fake },
+       /* PMCCNTR_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
+         pm_fake },
+       /* PMXEVTYPER_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
+         pm_fake },
+       /* PMXEVCNTR_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
+         pm_fake },
+       /* PMUSERENR_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
+         pm_fake },
+       /* PMOVSSET_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
+         pm_fake },
+
+       /* TPIDR_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b010),
+         NULL, reset_unknown, TPIDR_EL0 },
+       /* TPIDRRO_EL0 */
+       { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b011),
+         NULL, reset_unknown, TPIDRRO_EL0 },
+
+       /* DACR32_EL2 */
+       { Op0(0b11), Op1(0b100), CRn(0b0011), CRm(0b0000), Op2(0b000),
+         NULL, reset_unknown, DACR32_EL2 },
+       /* IFSR32_EL2 */
+       { Op0(0b11), Op1(0b100), CRn(0b0101), CRm(0b0000), Op2(0b001),
+         NULL, reset_unknown, IFSR32_EL2 },
+       /* FPEXC32_EL2 */
+       { Op0(0b11), Op1(0b100), CRn(0b0101), CRm(0b0011), Op2(0b000),
+         NULL, reset_val, FPEXC32_EL2, 0x70 },
+};
+
+/* Trapped cp15 registers */
+static const struct sys_reg_desc cp15_regs[] = {
+       /*
+        * DC{C,I,CI}SW operations:
+        */
+       { Op1( 0), CRn( 7), CRm( 6), Op2( 2), access_dcsw },
+       { Op1( 0), CRn( 7), CRm(10), Op2( 2), access_dcsw },
+       { Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
+       { Op1( 0), CRn( 9), CRm(12), Op2( 0), pm_fake },
+       { Op1( 0), CRn( 9), CRm(12), Op2( 1), pm_fake },
+       { Op1( 0), CRn( 9), CRm(12), Op2( 2), pm_fake },
+       { Op1( 0), CRn( 9), CRm(12), Op2( 3), pm_fake },
+       { Op1( 0), CRn( 9), CRm(12), Op2( 5), pm_fake },
+       { Op1( 0), CRn( 9), CRm(12), Op2( 6), pm_fake },
+       { Op1( 0), CRn( 9), CRm(12), Op2( 7), pm_fake },
+       { Op1( 0), CRn( 9), CRm(13), Op2( 0), pm_fake },
+       { Op1( 0), CRn( 9), CRm(13), Op2( 1), pm_fake },
+       { Op1( 0), CRn( 9), CRm(13), Op2( 2), pm_fake },
+       { Op1( 0), CRn( 9), CRm(14), Op2( 0), pm_fake },
+       { Op1( 0), CRn( 9), CRm(14), Op2( 1), pm_fake },
+       { Op1( 0), CRn( 9), CRm(14), Op2( 2), pm_fake },
+};
+
+/* Target specific emulation tables */
+static struct kvm_sys_reg_target_table *target_tables[KVM_ARM_NUM_TARGETS];
+
+void kvm_register_target_sys_reg_table(unsigned int target,
+                                      struct kvm_sys_reg_target_table *table)
+{
+       target_tables[target] = table;
+}
+
+/* Get specific register table for this target. */
+static const struct sys_reg_desc *get_target_table(unsigned target,
+                                                  bool mode_is_64,
+                                                  size_t *num)
+{
+       struct kvm_sys_reg_target_table *table;
+
+       table = target_tables[target];
+       if (mode_is_64) {
+               *num = table->table64.num;
+               return table->table64.table;
+       } else {
+               *num = table->table32.num;
+               return table->table32.table;
+       }
+}
+
+static const struct sys_reg_desc *find_reg(const struct sys_reg_params *params,
+                                        const struct sys_reg_desc table[],
+                                        unsigned int num)
+{
+       unsigned int i;
+
+       for (i = 0; i < num; i++) {
+               const struct sys_reg_desc *r = &table[i];
+
+               if (params->Op0 != r->Op0)
+                       continue;
+               if (params->Op1 != r->Op1)
+                       continue;
+               if (params->CRn != r->CRn)
+                       continue;
+               if (params->CRm != r->CRm)
+                       continue;
+               if (params->Op2 != r->Op2)
+                       continue;
+
+               return r;
+       }
+       return NULL;
+}
+
+int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+       kvm_inject_undefined(vcpu);
+       return 1;
+}
+
+int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+       kvm_inject_undefined(vcpu);
+       return 1;
+}
+
+static void emulate_cp15(struct kvm_vcpu *vcpu,
+                        const struct sys_reg_params *params)
+{
+       size_t num;
+       const struct sys_reg_desc *table, *r;
+
+       table = get_target_table(vcpu->arch.target, false, &num);
+
+       /* Search target-specific then generic table. */
+       r = find_reg(params, table, num);
+       if (!r)
+               r = find_reg(params, cp15_regs, ARRAY_SIZE(cp15_regs));
+
+       if (likely(r)) {
+               /*
+                * Not having an accessor means that we have
+                * configured a trap that we don't know how to
+                * handle. This certainly qualifies as a gross bug
+                * that should be fixed right away.
+                */
+               BUG_ON(!r->access);
+
+               if (likely(r->access(vcpu, params, r))) {
+                       /* Skip instruction, since it was emulated */
+                       kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+                       return;
+               }
+               /* If access function fails, it should complain. */
+       }
+
+       kvm_err("Unsupported guest CP15 access at: %08lx\n", *vcpu_pc(vcpu));
+       print_sys_reg_instr(params);
+       kvm_inject_undefined(vcpu);
+}
+
+/**
+ * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access
+ * @vcpu: The VCPU pointer
+ * @run:  The kvm_run struct
+ */
+int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+       struct sys_reg_params params;
+       u32 hsr = kvm_vcpu_get_hsr(vcpu);
+       int Rt2 = (hsr >> 10) & 0xf;
+
+       params.CRm = (hsr >> 1) & 0xf;
+       params.Rt = (hsr >> 5) & 0xf;
+       params.is_write = ((hsr & 1) == 0);
+
+       params.Op0 = 0;
+       params.Op1 = (hsr >> 16) & 0xf;
+       params.Op2 = 0;
+       params.CRn = 0;
+
+       /*
+        * Massive hack here. Store Rt2 in the top 32bits so we only
+        * have one register to deal with. As we use the same trap
+        * backends between AArch32 and AArch64, we get away with it.
+        */
+       if (params.is_write) {
+               u64 val = *vcpu_reg(vcpu, params.Rt);
+               val &= 0xffffffff;
+               val |= *vcpu_reg(vcpu, Rt2) << 32;
+               *vcpu_reg(vcpu, params.Rt) = val;
+       }
+
+       emulate_cp15(vcpu, &params);
+
+       /* Do the opposite hack for the read side */
+       if (!params.is_write) {
+               u64 val = *vcpu_reg(vcpu, params.Rt);
+               val >>= 32;
+               *vcpu_reg(vcpu, Rt2) = val;
+       }
+
+       return 1;
+}
+
+/**
+ * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access
+ * @vcpu: The VCPU pointer
+ * @run:  The kvm_run struct
+ */
+int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+       struct sys_reg_params params;
+       u32 hsr = kvm_vcpu_get_hsr(vcpu);
+
+       params.CRm = (hsr >> 1) & 0xf;
+       params.Rt  = (hsr >> 5) & 0xf;
+       params.is_write = ((hsr & 1) == 0);
+       params.CRn = (hsr >> 10) & 0xf;
+       params.Op0 = 0;
+       params.Op1 = (hsr >> 14) & 0x7;
+       params.Op2 = (hsr >> 17) & 0x7;
+
+       emulate_cp15(vcpu, &params);
+       return 1;
+}
+
+static int emulate_sys_reg(struct kvm_vcpu *vcpu,
+                          const struct sys_reg_params *params)
+{
+       size_t num;
+       const struct sys_reg_desc *table, *r;
+
+       table = get_target_table(vcpu->arch.target, true, &num);
+
+       /* Search target-specific then generic table. */
+       r = find_reg(params, table, num);
+       if (!r)
+               r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+
+       if (likely(r)) {
+               /*
+                * Not having an accessor means that we have
+                * configured a trap that we don't know how to
+                * handle. This certainly qualifies as a gross bug
+                * that should be fixed right away.
+                */
+               BUG_ON(!r->access);
+
+               if (likely(r->access(vcpu, params, r))) {
+                       /* Skip instruction, since it was emulated */
+                       kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+                       return 1;
+               }
+               /* If access function fails, it should complain. */
+       } else {
+               kvm_err("Unsupported guest sys_reg access at: %lx\n",
+                       *vcpu_pc(vcpu));
+               print_sys_reg_instr(params);
+       }
+       kvm_inject_undefined(vcpu);
+       return 1;
+}
+
+static void reset_sys_reg_descs(struct kvm_vcpu *vcpu,
+                             const struct sys_reg_desc *table, size_t num)
+{
+       unsigned long i;
+
+       for (i = 0; i < num; i++)
+               if (table[i].reset)
+                       table[i].reset(vcpu, &table[i]);
+}
+
+/**
+ * kvm_handle_sys_reg -- handles a mrs/msr trap on a guest sys_reg access
+ * @vcpu: The VCPU pointer
+ * @run:  The kvm_run struct
+ */
+int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+       struct sys_reg_params params;
+       unsigned long esr = kvm_vcpu_get_hsr(vcpu);
+
+       params.Op0 = (esr >> 20) & 3;
+       params.Op1 = (esr >> 14) & 0x7;
+       params.CRn = (esr >> 10) & 0xf;
+       params.CRm = (esr >> 1) & 0xf;
+       params.Op2 = (esr >> 17) & 0x7;
+       params.Rt = (esr >> 5) & 0x1f;
+       params.is_write = !(esr & 1);
+
+       return emulate_sys_reg(vcpu, &params);
+}
+
+/******************************************************************************
+ * Userspace API
+ *****************************************************************************/
+
+static bool index_to_params(u64 id, struct sys_reg_params *params)
+{
+       switch (id & KVM_REG_SIZE_MASK) {
+       case KVM_REG_SIZE_U64:
+               /* Any unused index bits means it's not valid. */
+               if (id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK
+                             | KVM_REG_ARM_COPROC_MASK
+                             | KVM_REG_ARM64_SYSREG_OP0_MASK
+                             | KVM_REG_ARM64_SYSREG_OP1_MASK
+                             | KVM_REG_ARM64_SYSREG_CRN_MASK
+                             | KVM_REG_ARM64_SYSREG_CRM_MASK
+                             | KVM_REG_ARM64_SYSREG_OP2_MASK))
+                       return false;
+               params->Op0 = ((id & KVM_REG_ARM64_SYSREG_OP0_MASK)
+                              >> KVM_REG_ARM64_SYSREG_OP0_SHIFT);
+               params->Op1 = ((id & KVM_REG_ARM64_SYSREG_OP1_MASK)
+                              >> KVM_REG_ARM64_SYSREG_OP1_SHIFT);
+               params->CRn = ((id & KVM_REG_ARM64_SYSREG_CRN_MASK)
+                              >> KVM_REG_ARM64_SYSREG_CRN_SHIFT);
+               params->CRm = ((id & KVM_REG_ARM64_SYSREG_CRM_MASK)
+                              >> KVM_REG_ARM64_SYSREG_CRM_SHIFT);
+               params->Op2 = ((id & KVM_REG_ARM64_SYSREG_OP2_MASK)
+                              >> KVM_REG_ARM64_SYSREG_OP2_SHIFT);
+               return true;
+       default:
+               return false;
+       }
+}
+
+/* Decode an index value, and find the sys_reg_desc entry. */
+static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
+                                                   u64 id)
+{
+       size_t num;
+       const struct sys_reg_desc *table, *r;
+       struct sys_reg_params params;
+
+       /* We only do sys_reg for now. */
+       if ((id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM64_SYSREG)
+               return NULL;
+
+       if (!index_to_params(id, &params))
+               return NULL;
+
+       table = get_target_table(vcpu->arch.target, true, &num);
+       r = find_reg(&params, table, num);
+       if (!r)
+               r = find_reg(&params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+
+       /* Not saved in the sys_reg array? */
+       if (r && !r->reg)
+               r = NULL;
+
+       return r;
+}
+
+/*
+ * These are the invariant sys_reg registers: we let the guest see the
+ * host versions of these, so they're part of the guest state.
+ *
+ * A future CPU may provide a mechanism to present different values to
+ * the guest, or a future kvm may trap them.
+ */
+
+#define FUNCTION_INVARIANT(reg)                                                \
+       static void get_##reg(struct kvm_vcpu *v,                       \
+                             const struct sys_reg_desc *r)             \
+       {                                                               \
+               u64 val;                                                \
+                                                                       \
+               asm volatile("mrs %0, " __stringify(reg) "\n"           \
+                            : "=r" (val));                             \
+               ((struct sys_reg_desc *)r)->val = val;                  \
+       }
+
+FUNCTION_INVARIANT(midr_el1)
+FUNCTION_INVARIANT(ctr_el0)
+FUNCTION_INVARIANT(revidr_el1)
+FUNCTION_INVARIANT(id_pfr0_el1)
+FUNCTION_INVARIANT(id_pfr1_el1)
+FUNCTION_INVARIANT(id_dfr0_el1)
+FUNCTION_INVARIANT(id_afr0_el1)
+FUNCTION_INVARIANT(id_mmfr0_el1)
+FUNCTION_INVARIANT(id_mmfr1_el1)
+FUNCTION_INVARIANT(id_mmfr2_el1)
+FUNCTION_INVARIANT(id_mmfr3_el1)
+FUNCTION_INVARIANT(id_isar0_el1)
+FUNCTION_INVARIANT(id_isar1_el1)
+FUNCTION_INVARIANT(id_isar2_el1)
+FUNCTION_INVARIANT(id_isar3_el1)
+FUNCTION_INVARIANT(id_isar4_el1)
+FUNCTION_INVARIANT(id_isar5_el1)
+FUNCTION_INVARIANT(clidr_el1)
+FUNCTION_INVARIANT(aidr_el1)
+
+/* ->val is filled in by kvm_sys_reg_table_init() */
+static struct sys_reg_desc invariant_sys_regs[] = {
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0000), Op2(0b000),
+         NULL, get_midr_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0000), Op2(0b110),
+         NULL, get_revidr_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b000),
+         NULL, get_id_pfr0_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b001),
+         NULL, get_id_pfr1_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b010),
+         NULL, get_id_dfr0_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b011),
+         NULL, get_id_afr0_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b100),
+         NULL, get_id_mmfr0_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b101),
+         NULL, get_id_mmfr1_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b110),
+         NULL, get_id_mmfr2_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b111),
+         NULL, get_id_mmfr3_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b000),
+         NULL, get_id_isar0_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b001),
+         NULL, get_id_isar1_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b010),
+         NULL, get_id_isar2_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b011),
+         NULL, get_id_isar3_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b100),
+         NULL, get_id_isar4_el1 },
+       { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b101),
+         NULL, get_id_isar5_el1 },
+       { Op0(0b11), Op1(0b001), CRn(0b0000), CRm(0b0000), Op2(0b001),
+         NULL, get_clidr_el1 },
+       { Op0(0b11), Op1(0b001), CRn(0b0000), CRm(0b0000), Op2(0b111),
+         NULL, get_aidr_el1 },
+       { Op0(0b11), Op1(0b011), CRn(0b0000), CRm(0b0000), Op2(0b001),
+         NULL, get_ctr_el0 },
+};
+
+static int reg_from_user(void *val, const void __user *uaddr, u64 id)
+{
+       /* This Just Works because we are little endian. */
+       if (copy_from_user(val, uaddr, KVM_REG_SIZE(id)) != 0)
+               return -EFAULT;
+       return 0;
+}
+
+static int reg_to_user(void __user *uaddr, const void *val, u64 id)
+{
+       /* This Just Works because we are little endian. */
+       if (copy_to_user(uaddr, val, KVM_REG_SIZE(id)) != 0)
+               return -EFAULT;
+       return 0;
+}
+
+static int get_invariant_sys_reg(u64 id, void __user *uaddr)
+{
+       struct sys_reg_params params;
+       const struct sys_reg_desc *r;
+
+       if (!index_to_params(id, &params))
+               return -ENOENT;
+
+       r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
+       if (!r)
+               return -ENOENT;
+
+       return reg_to_user(uaddr, &r->val, id);
+}
+
+static int set_invariant_sys_reg(u64 id, void __user *uaddr)
+{
+       struct sys_reg_params params;
+       const struct sys_reg_desc *r;
+       int err;
+       u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
+
+       if (!index_to_params(id, &params))
+               return -ENOENT;
+       r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
+       if (!r)
+               return -ENOENT;
+
+       err = reg_from_user(&val, uaddr, id);
+       if (err)
+               return err;
+
+       /* This is what we mean by invariant: you can't change it. */
+       if (r->val != val)
+               return -EINVAL;
+
+       return 0;
+}
+
+static bool is_valid_cache(u32 val)
+{
+       u32 level, ctype;
+
+       if (val >= CSSELR_MAX)
+               return -ENOENT;
+
+       /* Bottom bit is Instruction or Data bit.  Next 3 bits are level. */
+       level = (val >> 1);
+       ctype = (cache_levels >> (level * 3)) & 7;
+
+       switch (ctype) {
+       case 0: /* No cache */
+               return false;
+       case 1: /* Instruction cache only */
+               return (val & 1);
+       case 2: /* Data cache only */
+       case 4: /* Unified cache */
+               return !(val & 1);
+       case 3: /* Separate instruction and data caches */
+               return true;
+       default: /* Reserved: we can't know instruction or data. */
+               return false;
+       }
+}
+
+static int demux_c15_get(u64 id, void __user *uaddr)
+{
+       u32 val;
+       u32 __user *uval = uaddr;
+
+       /* Fail if we have unknown bits set. */
+       if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK
+                  | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1)))
+               return -ENOENT;
+
+       switch (id & KVM_REG_ARM_DEMUX_ID_MASK) {
+       case KVM_REG_ARM_DEMUX_ID_CCSIDR:
+               if (KVM_REG_SIZE(id) != 4)
+                       return -ENOENT;
+               val = (id & KVM_REG_ARM_DEMUX_VAL_MASK)
+                       >> KVM_REG_ARM_DEMUX_VAL_SHIFT;
+               if (!is_valid_cache(val))
+                       return -ENOENT;
+
+               return put_user(get_ccsidr(val), uval);
+       default:
+               return -ENOENT;
+       }
+}
+
+static int demux_c15_set(u64 id, void __user *uaddr)
+{
+       u32 val, newval;
+       u32 __user *uval = uaddr;
+
+       /* Fail if we have unknown bits set. */
+       if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK
+                  | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1)))
+               return -ENOENT;
+
+       switch (id & KVM_REG_ARM_DEMUX_ID_MASK) {
+       case KVM_REG_ARM_DEMUX_ID_CCSIDR:
+               if (KVM_REG_SIZE(id) != 4)
+                       return -ENOENT;
+               val = (id & KVM_REG_ARM_DEMUX_VAL_MASK)
+                       >> KVM_REG_ARM_DEMUX_VAL_SHIFT;
+               if (!is_valid_cache(val))
+                       return -ENOENT;
+
+               if (get_user(newval, uval))
+                       return -EFAULT;
+
+               /* This is also invariant: you can't change it. */
+               if (newval != get_ccsidr(val))
+                       return -EINVAL;
+               return 0;
+       default:
+               return -ENOENT;
+       }
+}
+
+int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       const struct sys_reg_desc *r;
+       void __user *uaddr = (void __user *)(unsigned long)reg->addr;
+
+       if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
+               return demux_c15_get(reg->id, uaddr);
+
+       if (KVM_REG_SIZE(reg->id) != sizeof(__u64))
+               return -ENOENT;
+
+       r = index_to_sys_reg_desc(vcpu, reg->id);
+       if (!r)
+               return get_invariant_sys_reg(reg->id, uaddr);
+
+       return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
+}
+
+int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+       const struct sys_reg_desc *r;
+       void __user *uaddr = (void __user *)(unsigned long)reg->addr;
+
+       if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
+               return demux_c15_set(reg->id, uaddr);
+
+       if (KVM_REG_SIZE(reg->id) != sizeof(__u64))
+               return -ENOENT;
+
+       r = index_to_sys_reg_desc(vcpu, reg->id);
+       if (!r)
+               return set_invariant_sys_reg(reg->id, uaddr);
+
+       return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
+}
+
+static unsigned int num_demux_regs(void)
+{
+       unsigned int i, count = 0;
+
+       for (i = 0; i < CSSELR_MAX; i++)
+               if (is_valid_cache(i))
+                       count++;
+
+       return count;
+}
+
+static int write_demux_regids(u64 __user *uindices)
+{
+       u64 val = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_DEMUX;
+       unsigned int i;
+
+       val |= KVM_REG_ARM_DEMUX_ID_CCSIDR;
+       for (i = 0; i < CSSELR_MAX; i++) {
+               if (!is_valid_cache(i))
+                       continue;
+               if (put_user(val | i, uindices))
+                       return -EFAULT;
+               uindices++;
+       }
+       return 0;
+}
+
+static u64 sys_reg_to_index(const struct sys_reg_desc *reg)
+{
+       return (KVM_REG_ARM64 | KVM_REG_SIZE_U64 |
+               KVM_REG_ARM64_SYSREG |
+               (reg->Op0 << KVM_REG_ARM64_SYSREG_OP0_SHIFT) |
+               (reg->Op1 << KVM_REG_ARM64_SYSREG_OP1_SHIFT) |
+               (reg->CRn << KVM_REG_ARM64_SYSREG_CRN_SHIFT) |
+               (reg->CRm << KVM_REG_ARM64_SYSREG_CRM_SHIFT) |
+               (reg->Op2 << KVM_REG_ARM64_SYSREG_OP2_SHIFT));
+}
+
+static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
+{
+       if (!*uind)
+               return true;
+
+       if (put_user(sys_reg_to_index(reg), *uind))
+               return false;
+
+       (*uind)++;
+       return true;
+}
+
+/* Assumed ordered tables, see kvm_sys_reg_table_init. */
+static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
+{
+       const struct sys_reg_desc *i1, *i2, *end1, *end2;
+       unsigned int total = 0;
+       size_t num;
+
+       /* We check for duplicates here, to allow arch-specific overrides. */
+       i1 = get_target_table(vcpu->arch.target, true, &num);
+       end1 = i1 + num;
+       i2 = sys_reg_descs;
+       end2 = sys_reg_descs + ARRAY_SIZE(sys_reg_descs);
+
+       BUG_ON(i1 == end1 || i2 == end2);
+
+       /* Walk carefully, as both tables may refer to the same register. */
+       while (i1 || i2) {
+               int cmp = cmp_sys_reg(i1, i2);
+               /* target-specific overrides generic entry. */
+               if (cmp <= 0) {
+                       /* Ignore registers we trap but don't save. */
+                       if (i1->reg) {
+                               if (!copy_reg_to_user(i1, &uind))
+                                       return -EFAULT;
+                               total++;
+                       }
+               } else {
+                       /* Ignore registers we trap but don't save. */
+                       if (i2->reg) {
+                               if (!copy_reg_to_user(i2, &uind))
+                                       return -EFAULT;
+                               total++;
+                       }
+               }
+
+               if (cmp <= 0 && ++i1 == end1)
+                       i1 = NULL;
+               if (cmp >= 0 && ++i2 == end2)
+                       i2 = NULL;
+       }
+       return total;
+}
+
+unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu)
+{
+       return ARRAY_SIZE(invariant_sys_regs)
+               + num_demux_regs()
+               + walk_sys_regs(vcpu, (u64 __user *)NULL);
+}
+
+int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+       unsigned int i;
+       int err;
+
+       /* Then give them all the invariant registers' indices. */
+       for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++) {
+               if (put_user(sys_reg_to_index(&invariant_sys_regs[i]), uindices))
+                       return -EFAULT;
+               uindices++;
+       }
+
+       err = walk_sys_regs(vcpu, uindices);
+       if (err < 0)
+               return err;
+       uindices += err;
+
+       return write_demux_regids(uindices);
+}
+
+void kvm_sys_reg_table_init(void)
+{
+       unsigned int i;
+       struct sys_reg_desc clidr;
+
+       /* Make sure tables are unique and in order. */
+       for (i = 1; i < ARRAY_SIZE(sys_reg_descs); i++)
+               BUG_ON(cmp_sys_reg(&sys_reg_descs[i-1], &sys_reg_descs[i]) >= 0);
+
+       /* We abuse the reset function to overwrite the table itself. */
+       for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++)
+               invariant_sys_regs[i].reset(NULL, &invariant_sys_regs[i]);
+
+       /*
+        * CLIDR format is awkward, so clean it up.  See ARM B4.1.20:
+        *
+        *   If software reads the Cache Type fields from Ctype1
+        *   upwards, once it has seen a value of 0b000, no caches
+        *   exist at further-out levels of the hierarchy. So, for
+        *   example, if Ctype3 is the first Cache Type field with a
+        *   value of 0b000, the values of Ctype4 to Ctype7 must be
+        *   ignored.
+        */
+       get_clidr_el1(NULL, &clidr); /* Ugly... */
+       cache_levels = clidr.val;
+       for (i = 0; i < 7; i++)
+               if (((cache_levels >> (i*3)) & 7) == 0)
+                       break;
+       /* Clear all higher bits. */
+       cache_levels &= (1 << (i*3))-1;
+}
+
+/**
+ * kvm_reset_sys_regs - sets system registers to reset value
+ * @vcpu: The VCPU pointer
+ *
+ * This function finds the right table above and sets the registers on the
+ * virtual CPU struct to their architecturally defined reset values.
+ */
+void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
+{
+       size_t num;
+       const struct sys_reg_desc *table;
+
+       /* Catch someone adding a register without putting in reset entry. */
+       memset(&vcpu->arch.ctxt.sys_regs, 0x42, sizeof(vcpu->arch.ctxt.sys_regs));
+
+       /* Generic chip reset first (so target could override). */
+       reset_sys_reg_descs(vcpu, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+
+       table = get_target_table(vcpu->arch.target, true, &num);
+       reset_sys_reg_descs(vcpu, table, num);
+
+       for (num = 1; num < NR_SYS_REGS; num++)
+               if (vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
+                       panic("Didn't reset vcpu_sys_reg(%zi)", num);
+}
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
new file mode 100644 (file)
index 0000000..d50d372
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/coproc.h
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Authors: Christoffer Dall <c.dall@virtualopensystems.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_SYS_REGS_LOCAL_H__
+#define __ARM64_KVM_SYS_REGS_LOCAL_H__
+
+struct sys_reg_params {
+       u8      Op0;
+       u8      Op1;
+       u8      CRn;
+       u8      CRm;
+       u8      Op2;
+       u8      Rt;
+       bool    is_write;
+};
+
+struct sys_reg_desc {
+       /* MRS/MSR instruction which accesses it. */
+       u8      Op0;
+       u8      Op1;
+       u8      CRn;
+       u8      CRm;
+       u8      Op2;
+
+       /* Trapped access from guest, if non-NULL. */
+       bool (*access)(struct kvm_vcpu *,
+                      const struct sys_reg_params *,
+                      const struct sys_reg_desc *);
+
+       /* Initialization for vcpu. */
+       void (*reset)(struct kvm_vcpu *, const struct sys_reg_desc *);
+
+       /* Index into sys_reg[], or 0 if we don't need to save it. */
+       int reg;
+
+       /* Value (usually reset value) */
+       u64 val;
+};
+
+static inline void print_sys_reg_instr(const struct sys_reg_params *p)
+{
+       /* Look, we even formatted it for you to paste into the table! */
+       kvm_pr_unimpl(" { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u), func_%s },\n",
+                     p->Op0, p->Op1, p->CRn, p->CRm, p->Op2, p->is_write ? "write" : "read");
+}
+
+static inline bool ignore_write(struct kvm_vcpu *vcpu,
+                               const struct sys_reg_params *p)
+{
+       return true;
+}
+
+static inline bool read_zero(struct kvm_vcpu *vcpu,
+                            const struct sys_reg_params *p)
+{
+       *vcpu_reg(vcpu, p->Rt) = 0;
+       return true;
+}
+
+static inline bool write_to_read_only(struct kvm_vcpu *vcpu,
+                                     const struct sys_reg_params *params)
+{
+       kvm_debug("sys_reg write to read-only register at: %lx\n",
+                 *vcpu_pc(vcpu));
+       print_sys_reg_instr(params);
+       return false;
+}
+
+static inline bool read_from_write_only(struct kvm_vcpu *vcpu,
+                                       const struct sys_reg_params *params)
+{
+       kvm_debug("sys_reg read to write-only register at: %lx\n",
+                 *vcpu_pc(vcpu));
+       print_sys_reg_instr(params);
+       return false;
+}
+
+/* Reset functions */
+static inline void reset_unknown(struct kvm_vcpu *vcpu,
+                                const struct sys_reg_desc *r)
+{
+       BUG_ON(!r->reg);
+       BUG_ON(r->reg >= NR_SYS_REGS);
+       vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
+}
+
+static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+       BUG_ON(!r->reg);
+       BUG_ON(r->reg >= NR_SYS_REGS);
+       vcpu_sys_reg(vcpu, r->reg) = r->val;
+}
+
+static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
+                             const struct sys_reg_desc *i2)
+{
+       BUG_ON(i1 == i2);
+       if (!i1)
+               return 1;
+       else if (!i2)
+               return -1;
+       if (i1->Op0 != i2->Op0)
+               return i1->Op0 - i2->Op0;
+       if (i1->Op1 != i2->Op1)
+               return i1->Op1 - i2->Op1;
+       if (i1->CRn != i2->CRn)
+               return i1->CRn - i2->CRn;
+       if (i1->CRm != i2->CRm)
+               return i1->CRm - i2->CRm;
+       return i1->Op2 - i2->Op2;
+}
+
+
+#define Op0(_x)        .Op0 = _x
+#define Op1(_x)        .Op1 = _x
+#define CRn(_x)                .CRn = _x
+#define CRm(_x)        .CRm = _x
+#define Op2(_x)        .Op2 = _x
+
+#endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */
diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
new file mode 100644 (file)
index 0000000..4268ab9
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Based on arch/arm/kvm/coproc_a15.c:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Authors: Rusty Russell <rusty@rustcorp.au>
+ *          Christoffer Dall <c.dall@virtualopensystems.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/kvm_host.h>
+#include <asm/cputype.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+#include <linux/init.h>
+
+#include "sys_regs.h"
+
+static bool access_actlr(struct kvm_vcpu *vcpu,
+                        const struct sys_reg_params *p,
+                        const struct sys_reg_desc *r)
+{
+       if (p->is_write)
+               return ignore_write(vcpu, p);
+
+       *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, ACTLR_EL1);
+       return true;
+}
+
+static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+       u64 actlr;
+
+       asm volatile("mrs %0, actlr_el1\n" : "=r" (actlr));
+       vcpu_sys_reg(vcpu, ACTLR_EL1) = actlr;
+}
+
+/*
+ * Implementation specific sys-reg registers.
+ * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
+ */
+static const struct sys_reg_desc genericv8_sys_regs[] = {
+       /* ACTLR_EL1 */
+       { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b001),
+         access_actlr, reset_actlr, ACTLR_EL1 },
+};
+
+static const struct sys_reg_desc genericv8_cp15_regs[] = {
+       /* ACTLR */
+       { Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b001),
+         access_actlr },
+};
+
+static struct kvm_sys_reg_target_table genericv8_target_table = {
+       .table64 = {
+               .table = genericv8_sys_regs,
+               .num = ARRAY_SIZE(genericv8_sys_regs),
+       },
+       .table32 = {
+               .table = genericv8_cp15_regs,
+               .num = ARRAY_SIZE(genericv8_cp15_regs),
+       },
+};
+
+static int __init sys_reg_genericv8_init(void)
+{
+       unsigned int i;
+
+       for (i = 1; i < ARRAY_SIZE(genericv8_sys_regs); i++)
+               BUG_ON(cmp_sys_reg(&genericv8_sys_regs[i-1],
+                              &genericv8_sys_regs[i]) >= 0);
+
+       kvm_register_target_sys_reg_table(KVM_ARM_TARGET_AEM_V8,
+                                         &genericv8_target_table);
+       kvm_register_target_sys_reg_table(KVM_ARM_TARGET_FOUNDATION_V8,
+                                         &genericv8_target_table);
+       kvm_register_target_sys_reg_table(KVM_ARM_TARGET_CORTEX_A57,
+                                         &genericv8_target_table);
+       return 0;
+}
+late_initcall(sys_reg_genericv8_init);
index 3140a2abcdc276738951f1621c7e63539507a5de..b51d36401d83fc50bafb31a11e4ad67d30e8cec7 100644 (file)
@@ -2,3 +2,4 @@ obj-y                           := dma-mapping.o extable.o fault.o init.o \
                                   cache.o copypage.o flush.o \
                                   ioremap.o mmap.o pgd.o mmu.o \
                                   context.o tlb.o proc.o
+obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
index 1426468b77f3bb7b6df96d604851449db13ed0da..0ecac8980aaefa799d063221666220c305c0de3d 100644 (file)
@@ -364,17 +364,6 @@ static int __kprobes do_translation_fault(unsigned long addr,
        return 0;
 }
 
-/*
- * Some section permission faults need to be handled gracefully.  They can
- * happen due to a __{get,put}_user during an oops.
- */
-static int do_sect_fault(unsigned long addr, unsigned int esr,
-                        struct pt_regs *regs)
-{
-       do_bad_area(addr, esr, regs);
-       return 0;
-}
-
 /*
  * This abort handler always returns "fault".
  */
@@ -398,12 +387,12 @@ static struct fault_info {
        { do_translation_fault, SIGSEGV, SEGV_MAPERR,   "level 2 translation fault"     },
        { do_page_fault,        SIGSEGV, SEGV_MAPERR,   "level 3 translation fault"     },
        { do_bad,               SIGBUS,  0,             "reserved access flag fault"    },
-       { do_bad,               SIGSEGV, SEGV_ACCERR,   "level 1 access flag fault"     },
-       { do_bad,               SIGSEGV, SEGV_ACCERR,   "level 2 access flag fault"     },
+       { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 1 access flag fault"     },
+       { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 access flag fault"     },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 access flag fault"     },
        { do_bad,               SIGBUS,  0,             "reserved permission fault"     },
-       { do_bad,               SIGSEGV, SEGV_ACCERR,   "level 1 permission fault"      },
-       { do_sect_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 permission fault"      },
+       { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 1 permission fault"      },
+       { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 2 permission fault"      },
        { do_page_fault,        SIGSEGV, SEGV_ACCERR,   "level 3 permission fault"      },
        { do_bad,               SIGBUS,  0,             "synchronous external abort"    },
        { do_bad,               SIGBUS,  0,             "asynchronous external abort"   },
index 88611c3a421aecd15391e734e9646089ee6ce54d..e4193e3adc7f9dbbbe57c63eac0ee60b32aaa3e5 100644 (file)
@@ -70,23 +70,16 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
 #endif
 }
 
-void __flush_dcache_page(struct page *page)
-{
-       __flush_dcache_area(page_address(page), PAGE_SIZE);
-}
-
 void __sync_icache_dcache(pte_t pte, unsigned long addr)
 {
-       unsigned long pfn;
-       struct page *page;
+       struct page *page = pte_page(pte);
 
-       pfn = pte_pfn(pte);
-       if (!pfn_valid(pfn))
+       /* no flushing needed for anonymous pages */
+       if (!page_mapping(page))
                return;
 
-       page = pfn_to_page(pfn);
        if (!test_and_set_bit(PG_dcache_clean, &page->flags)) {
-               __flush_dcache_page(page);
+               __flush_dcache_area(page_address(page), PAGE_SIZE);
                __flush_icache_all();
        } else if (icache_is_aivivt()) {
                __flush_icache_all();
@@ -94,28 +87,14 @@ void __sync_icache_dcache(pte_t pte, unsigned long addr)
 }
 
 /*
- * Ensure cache coherency between kernel mapping and userspace mapping of this
- * page.
+ * This function is called when a page has been modified by the kernel. Mark
+ * it as dirty for later flushing when mapped in user space (if executable,
+ * see __sync_icache_dcache).
  */
 void flush_dcache_page(struct page *page)
 {
-       struct address_space *mapping;
-
-       /*
-        * The zero page is never written to, so never has any dirty cache
-        * lines, and therefore never needs to be flushed.
-        */
-       if (page == ZERO_PAGE(0))
-               return;
-
-       mapping = page_mapping(page);
-       if (mapping && mapping_mapped(mapping)) {
-               __flush_dcache_page(page);
-               __flush_icache_all();
-               set_bit(PG_dcache_clean, &page->flags);
-       } else {
+       if (test_bit(PG_dcache_clean, &page->flags))
                clear_bit(PG_dcache_clean, &page->flags);
-       }
 }
 EXPORT_SYMBOL(flush_dcache_page);
 
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
new file mode 100644 (file)
index 0000000..2fc8258
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * arch/arm64/mm/hugetlbpage.c
+ *
+ * Copyright (C) 2013 Linaro Ltd.
+ *
+ * Based on arch/x86/mm/hugetlbpage.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+#include <linux/sysctl.h>
+#include <asm/mman.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
+
+#ifndef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
+int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
+{
+       return 0;
+}
+#endif
+
+struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
+                             int write)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+int pmd_huge(pmd_t pmd)
+{
+       return !(pmd_val(pmd) & PMD_TABLE_BIT);
+}
+
+int pud_huge(pud_t pud)
+{
+       return !(pud_val(pud) & PUD_TABLE_BIT);
+}
+
+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 {
+               pr_err("hugepagesz: Unsupported page size %lu M\n", ps >> 20);
+               return 0;
+       }
+       return 1;
+}
+__setup("hugepagesz=", setup_hugepagesz);
index f497ca77925ac71e98036e43030b2b73dc2ca162..67e8d7ce3fe7a68ac1c974058de83b8d6226086e 100644 (file)
@@ -197,14 +197,6 @@ void __init bootmem_init(void)
        max_pfn = max_low_pfn = max;
 }
 
-/*
- * Poison init memory with an undefined instruction (0x0).
- */
-static inline void poison_init_mem(void *s, size_t count)
-{
-       memset(s, 0, count);
-}
-
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
 static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn)
 {
@@ -280,59 +272,17 @@ static void __init free_unused_memmap(void)
  */
 void __init mem_init(void)
 {
-       unsigned long reserved_pages, free_pages;
-       struct memblock_region *reg;
-
        arm64_swiotlb_init();
 
        max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
 
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
-       /* this will put all unused low memory onto the freelists */
        free_unused_memmap();
 #endif
+       /* this will put all unused low memory onto the freelists */
+       free_all_bootmem();
 
-       totalram_pages += free_all_bootmem();
-
-       reserved_pages = free_pages = 0;
-
-       for_each_memblock(memory, reg) {
-               unsigned int pfn1, pfn2;
-               struct page *page, *end;
-
-               pfn1 = __phys_to_pfn(reg->base);
-               pfn2 = pfn1 + __phys_to_pfn(reg->size);
-
-               page = pfn_to_page(pfn1);
-               end  = pfn_to_page(pfn2 - 1) + 1;
-
-               do {
-                       if (PageReserved(page))
-                               reserved_pages++;
-                       else if (!page_count(page))
-                               free_pages++;
-                       page++;
-               } while (page < end);
-       }
-
-       /*
-        * Since our memory may not be contiguous, calculate the real number
-        * of pages we have in this system.
-        */
-       pr_info("Memory:");
-       num_physpages = 0;
-       for_each_memblock(memory, reg) {
-               unsigned long pages = memblock_region_memory_end_pfn(reg) -
-                       memblock_region_memory_base_pfn(reg);
-               num_physpages += pages;
-               printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
-       }
-       printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
-
-       pr_notice("Memory: %luk/%luk available, %luk reserved\n",
-                 nr_free_pages() << (PAGE_SHIFT-10),
-                 free_pages << (PAGE_SHIFT-10),
-                 reserved_pages << (PAGE_SHIFT-10));
+       mem_init_print_info(NULL);
 
 #define MLK(b, t) b, t, ((t) - (b)) >> 10
 #define MLM(b, t) b, t, ((t) - (b)) >> 20
@@ -374,7 +324,7 @@ void __init mem_init(void)
        BUILD_BUG_ON(TASK_SIZE_64                       > MODULES_VADDR);
        BUG_ON(TASK_SIZE_64                             > MODULES_VADDR);
 
-       if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
+       if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
                extern int sysctl_overcommit_memory;
                /*
                 * On a machine this small we won't get anywhere without
@@ -386,7 +336,6 @@ void __init mem_init(void)
 
 void free_initmem(void)
 {
-       poison_init_mem(__init_begin, __init_end - __init_begin);
        free_initmem_default(0);
 }
 
@@ -396,10 +345,8 @@ static int keep_initrd;
 
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       if (!keep_initrd) {
-               poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
-               free_reserved_area(start, end, 0, "initrd");
-       }
+       if (!keep_initrd)
+               free_reserved_area((void *)start, (void *)end, 0, "initrd");
 }
 
 static int __init keepinitrd_setup(char *__unused)
index 916701e6d040b92b5edbf63935ff2ecd8f3e101a..d519f4f50c8c6f5431281ee5e15346e860e9f741 100644 (file)
@@ -1,3 +1,2 @@
-extern void __flush_dcache_page(struct page *page);
 extern void __init bootmem_init(void);
 extern void __init arm64_swiotlb_init(void);
index eeecc9c8ed6860accacc36bb5f5aa0e6c7db7e58..a8d1059b91b2d916f1baf60f137ac81279c9a038 100644 (file)
@@ -297,6 +297,16 @@ static void __init map_mem(void)
 {
        struct memblock_region *reg;
 
+       /*
+        * Temporarily limit the memblock range. We need to do this as
+        * create_mapping requires puds, pmds and ptes to be allocated from
+        * memory addressable from the initial direct kernel mapping.
+        *
+        * The initial direct kernel mapping, located at swapper_pg_dir,
+        * gives us PGDIR_SIZE memory starting from PHYS_OFFSET (aligned).
+        */
+       memblock_set_current_limit((PHYS_OFFSET & PGDIR_MASK) + PGDIR_SIZE);
+
        /* map all the memory banks */
        for_each_memblock(memory, reg) {
                phys_addr_t start = reg->base;
@@ -307,6 +317,9 @@ static void __init map_mem(void)
 
                create_mapping(start, __phys_to_virt(start), end - start);
        }
+
+       /* Limit no longer required. */
+       memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
 }
 
 /*
@@ -317,12 +330,6 @@ void __init paging_init(void)
 {
        void *zero_page;
 
-       /*
-        * Maximum PGDIR_SIZE addressable via the initial direct kernel
-        * mapping in swapper_pg_dir.
-        */
-       memblock_set_current_limit((PHYS_OFFSET & PGDIR_MASK) + PGDIR_SIZE);
-
        init_mem_pgprot();
        map_mem();
 
@@ -339,7 +346,6 @@ void __init paging_init(void)
        bootmem_init();
 
        empty_zero_page = virt_to_page(zero_page);
-       __flush_dcache_page(empty_zero_page);
 
        /*
         * TTBR0 is only used for the identity mapping at this stage. Make it
diff --git a/arch/arm64/xen/Makefile b/arch/arm64/xen/Makefile
new file mode 100644 (file)
index 0000000..be24040
--- /dev/null
@@ -0,0 +1,2 @@
+xen-arm-y      += $(addprefix ../../arm/xen/, enlighten.o grant-table.o)
+obj-y          := xen-arm.o hypercall.o
diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S
new file mode 100644 (file)
index 0000000..2816c47
--- /dev/null
@@ -0,0 +1,92 @@
+/******************************************************************************
+ * hypercall.S
+ *
+ * Xen hypercall wrappers
+ *
+ * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * The Xen hypercall calling convention is very similar to the procedure
+ * call standard for the ARM 64-bit architecture: the first parameter is
+ * passed in x0, the second in x1, the third in x2, the fourth in x3 and
+ * the fifth in x4.
+ *
+ * The hypercall number is passed in x16.
+ *
+ * The return value is in x0.
+ *
+ * The hvc ISS is required to be 0xEA1, that is the Xen specific ARM
+ * hypercall tag.
+ *
+ * Parameter structs passed to hypercalls are laid out according to
+ * the ARM 64-bit EABI standard.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <xen/interface/xen.h>
+
+
+#define XEN_IMM 0xEA1
+
+#define HYPERCALL_SIMPLE(hypercall)            \
+ENTRY(HYPERVISOR_##hypercall)                  \
+       mov x16, #__HYPERVISOR_##hypercall;     \
+       hvc XEN_IMM;                            \
+       ret;                                    \
+ENDPROC(HYPERVISOR_##hypercall)
+
+#define HYPERCALL0 HYPERCALL_SIMPLE
+#define HYPERCALL1 HYPERCALL_SIMPLE
+#define HYPERCALL2 HYPERCALL_SIMPLE
+#define HYPERCALL3 HYPERCALL_SIMPLE
+#define HYPERCALL4 HYPERCALL_SIMPLE
+#define HYPERCALL5 HYPERCALL_SIMPLE
+
+                .text
+
+HYPERCALL2(xen_version);
+HYPERCALL3(console_io);
+HYPERCALL3(grant_table_op);
+HYPERCALL2(sched_op);
+HYPERCALL2(event_channel_op);
+HYPERCALL2(hvm_op);
+HYPERCALL2(memory_op);
+HYPERCALL2(physdev_op);
+HYPERCALL3(vcpu_op);
+
+ENTRY(privcmd_call)
+       mov x16, x0
+       mov x0, x1
+       mov x1, x2
+       mov x2, x3
+       mov x3, x4
+       mov x4, x5
+       hvc XEN_IMM
+       ret
+ENDPROC(privcmd_call);
index e7b61494c312e7a4683f11707b2a7ff8a32f6e3b..c2731003edef556c18cd137f4a0b1aac5e770cc3 100644 (file)
@@ -341,7 +341,7 @@ unsigned long get_wchan(struct task_struct *p)
                 * is actually quite ugly. It might be possible to
                 * determine the frame size automatically at build
                 * time by doing this:
-                *   - compile sched.c
+                *   - compile sched/core.c
                 *   - disassemble the resulting sched.o
                 *   - look for 'sub sp,??' shortly after '<schedule>:'
                 */
index b4247f4780657993eef27f9e15ed2169b088793b..209ae5ad34958044ae3d6addcafa090f890a8be7 100644 (file)
@@ -555,7 +555,7 @@ void __init setup_arch (char **cmdline_p)
 {
        struct clk *cpu_clk;
 
-       init_mm.start_code = (unsigned long)_text;
+       init_mm.start_code = (unsigned long)_stext;
        init_mm.end_code = (unsigned long)_etext;
        init_mm.end_data = (unsigned long)_edata;
        init_mm.brk = (unsigned long)_end;
index 9cd2bd91d64a613a90b07e148c9e06bda955b9b1..a4589176bed5d7940d1f0e66d144a933892557f5 100644 (file)
@@ -23,7 +23,7 @@ SECTIONS
 {
        . = CONFIG_ENTRY_ADDRESS;
        .init           : AT(ADDR(.init) - LOAD_OFFSET) {
-               _stext = .;
+               _text = .;
                __init_begin = .;
                        _sinittext = .;
                        *(.text.reset)
@@ -46,7 +46,7 @@ SECTIONS
 
        .text           : AT(ADDR(.text) - LOAD_OFFSET) {
                _evba = .;
-               _text = .;
+               _stext = .;
                *(.ex.text)
                *(.irq.text)
                KPROBES_TEXT
index 7c2f6685bf434d06afa68bfc4f2f86b34db3d4c8..7f8759a8a92a08b8ed8e772d9f08c9d3404d8697 100644 (file)
@@ -1060,7 +1060,9 @@ struct platform_device *__init at32_add_device_usart(unsigned int id)
 
 void __init at32_setup_serial_console(unsigned int usart_id)
 {
+#ifdef CONFIG_SERIAL_ATMEL
        atmel_default_console_device = at32_usarts[usart_id];
+#endif
 }
 
 /* --------------------------------------------------------------------
index e66e8406f99211ba17e28ae59b491c029aa5ace6..def5391d927ac353682e1607162d1770365840cf 100644 (file)
@@ -100,60 +100,26 @@ void __init paging_init(void)
 
 void __init mem_init(void)
 {
-       int codesize, reservedpages, datasize, initsize;
-       int nid, i;
+       pg_data_t *pgdat;
 
-       reservedpages = 0;
        high_memory = NULL;
+       for_each_online_pgdat(pgdat)
+               high_memory = max_t(void *, high_memory,
+                                   __va(pgdat_end_pfn(pgdat) << PAGE_SHIFT));
 
-       /* this will put all low memory onto the freelists */
-       for_each_online_node(nid) {
-               pg_data_t *pgdat = NODE_DATA(nid);
-               unsigned long node_pages = 0;
-               void *node_high_memory;
-
-               num_physpages += pgdat->node_present_pages;
-
-               if (pgdat->node_spanned_pages != 0)
-                       node_pages = free_all_bootmem_node(pgdat);
-
-               totalram_pages += node_pages;
-
-               for (i = 0; i < node_pages; i++)
-                       if (PageReserved(pgdat->node_mem_map + i))
-                               reservedpages++;
-
-               node_high_memory = (void *)((pgdat->node_start_pfn
-                                            + pgdat->node_spanned_pages)
-                                           << PAGE_SHIFT);
-               if (node_high_memory > high_memory)
-                       high_memory = node_high_memory;
-       }
-
-       max_mapnr = MAP_NR(high_memory);
-
-       codesize = (unsigned long)_etext - (unsigned long)_text;
-       datasize = (unsigned long)_edata - (unsigned long)_data;
-       initsize = (unsigned long)__init_end - (unsigned long)__init_begin;
-
-       printk ("Memory: %luk/%luk available (%dk kernel code, "
-               "%dk reserved, %dk data, %dk init)\n",
-               nr_free_pages() << (PAGE_SHIFT - 10),
-               totalram_pages << (PAGE_SHIFT - 10),
-               codesize >> 10,
-               reservedpages << (PAGE_SHIFT - 10),
-               datasize >> 10,
-               initsize >> 10);
+       set_max_mapnr(MAP_NR(high_memory));
+       free_all_bootmem();
+       mem_init_print_info(NULL);
 }
 
 void free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
index d58f50e5aa4b856e51664d5495c873e04d04cb82..1e7be62fccb60f7e216dc3120f0752f3387c14a5 100644 (file)
@@ -283,14 +283,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
-};
-#endif
-
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #if defined(CONFIG_MTD_M25P80) \
        || defined(CONFIG_MTD_M25P80_MODULE)
@@ -800,10 +792,6 @@ static struct platform_device *stamp_devices[] __initdata = {
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
        &bfin_i2s,
 #endif
-
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
-#endif
 };
 
 static int __init ad7160eval_init(void)
index 29f16e5c37b925cdbbd0447e536e77e35bc451c3..d0a0c5e527cd6806d5d6b05f5c724f926c0c4de3 100644 (file)
@@ -493,8 +493,7 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
-       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
 
 static const u16 bfin_snd_pin[][7] = {
        {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
@@ -549,13 +548,6 @@ static struct platform_device bfin_i2s_pcm = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
-       .name = "bfin-tdm-pcm-audio",
-       .id = -1,
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97_pcm = {
        .name = "bfin-ac97-pcm-audio",
@@ -575,22 +567,10 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
-       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
-       .dev = {
-               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
-       },
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
                || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
 static const char * const ad1836_link[] = {
-       "bfin-tdm.0",
+       "bfin-i2s.0",
        "spi0.4",
 };
 static struct platform_device bfin_ad1836_machine = {
@@ -1269,10 +1249,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s_pcm,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm_pcm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97_pcm,
 #endif
@@ -1281,10 +1257,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
        defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
        &bfin_ad1836_machine,
index 07811c209b9d38f020180d44045ef497a2f4095c..90fb0d14b147d17fed9598ca35325821a37e4402 100644 (file)
@@ -450,14 +450,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
@@ -516,10 +508,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97,
 #endif
index 6fca8698bf3bce5c2108bef0bc86d529e5099e7b..4a8c2e3fd7e5649b469738ae163721854f279d99 100644 (file)
@@ -542,8 +542,7 @@ static struct platform_device bfin_dpmc = {
 };
 
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
-       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) \
-       || defined(CONFIG_SND_BF5XX_AC97) || \
+       defined(CONFIG_SND_BF5XX_AC97) || \
        defined(CONFIG_SND_BF5XX_AC97_MODULE)
 
 #include <asm/bfin_sport.h>
@@ -603,13 +602,6 @@ static struct platform_device bfin_i2s_pcm = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
-       .name = "bfin-tdm-pcm-audio",
-       .id = -1,
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97_pcm = {
        .name = "bfin-ac97-pcm-audio",
@@ -620,7 +612,7 @@ static struct platform_device bfin_ac97_pcm = {
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
                || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
 static const char * const ad1836_link[] = {
-       "bfin-tdm.0",
+       "bfin-i2s.0",
        "spi0.4",
 };
 static struct platform_device bfin_ad1836_machine = {
@@ -675,20 +667,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || \
-       defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       .num_resources =
-               ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
-       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
-       .dev = {
-               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
-       },
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AC97) || \
        defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
@@ -761,10 +739,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s_pcm,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm_pcm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97_pcm,
 #endif
@@ -792,11 +766,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || \
-       defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AC97) || \
        defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
        &bfin_ac97,
index 6a3a14bcd3a1ee338be3c90d68f3672575904d39..44fd1d4682ac3f3e411acfcf728cb74011f163d4 100644 (file)
@@ -2570,7 +2570,6 @@ static struct platform_device bfin_dpmc = {
 };
 
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
-       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
        defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 
 #define SPORT_REQ(x) \
@@ -2628,13 +2627,6 @@ static struct platform_device bfin_i2s_pcm = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
-       .name = "bfin-tdm-pcm-audio",
-       .id = -1,
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97_pcm = {
        .name = "bfin-ac97-pcm-audio",
@@ -2645,7 +2637,7 @@ static struct platform_device bfin_ac97_pcm = {
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
                || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
 static const char * const ad1836_link[] = {
-       "bfin-tdm.0",
+       "bfin-i2s.0",
        "spi0.4",
 };
 static struct platform_device bfin_ad1836_machine = {
@@ -2699,18 +2691,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
-       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
-       .dev = {
-               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
-       },
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
@@ -2935,10 +2915,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s_pcm,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm_pcm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97_pcm,
 #endif
@@ -2961,10 +2937,6 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
        &bfin_ac97,
 #endif
index c4d07f040947cba025c1df2d87d9431c7bc2fd36..372eb54944eff3cbb12269c7a69947f9b1c86ee4 100644 (file)
@@ -1393,7 +1393,6 @@ static struct platform_device bfin_dpmc = {
 };
 
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
-       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
        defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 
 #define SPORT_REQ(x) \
@@ -1461,13 +1460,6 @@ static struct platform_device bfin_i2s_pcm = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
-       .name = "bfin-tdm-pcm-audio",
-       .id = -1,
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97_pcm = {
        .name = "bfin-ac97-pcm-audio",
@@ -1501,18 +1493,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
-       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
-       .dev = {
-               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
-       },
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
@@ -1646,9 +1626,7 @@ static struct platform_device *ezkit_devices[] __initdata = {
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
        &bfin_i2s_pcm,
 #endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm_pcm,
-#endif
+
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97_pcm,
 #endif
@@ -1661,10 +1639,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97,
 #endif
index 551f866172cf7ae51cd5af8e631a821c38ea5f80..92938e79b9e32b925b5f87c687a48957a5d7601a 100644 (file)
@@ -523,14 +523,6 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
-       .name = "bfin-tdm",
-       .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
-};
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
@@ -542,7 +534,7 @@ static struct platform_device bfin_ac97 = {
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
                || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
 static const char * const ad1836_link[] = {
-       "bfin-tdm.0",
+       "bfin-i2s.0",
        "spi0.4",
 };
 static struct platform_device bfin_ad1836_machine = {
@@ -611,10 +603,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
-#endif
-
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97,
 #endif
index 97d701639585241dbac5b47d350c2552008c0656..bba40aed4273b288302ed6e28f17a475e54cc638 100644 (file)
@@ -821,7 +821,7 @@ static struct platform_device bfin_i2s = {
 #if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
                || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
 static const char * const ad1836_link[] = {
-       "bfin-tdm.0",
+       "bfin-i2s.0",
        "spi0.76",
 };
 static struct platform_device bfin_ad1836_machine = {
index 82d01a71207ffbd4eb89f9a2eb8afde424528c16..166842de3dc7622403cb575b811803a20f83c41c 100644 (file)
@@ -90,50 +90,24 @@ asmlinkage void __init init_pda(void)
 
 void __init mem_init(void)
 {
-       unsigned int codek = 0, datak = 0, initk = 0;
-       unsigned int reservedpages = 0, freepages = 0;
-       unsigned long tmp;
-       unsigned long start_mem = memory_start;
-       unsigned long end_mem = memory_end;
+       char buf[64];
 
-       end_mem &= PAGE_MASK;
-       high_memory = (void *)end_mem;
-
-       start_mem = PAGE_ALIGN(start_mem);
-       max_mapnr = num_physpages = MAP_NR(high_memory);
-       printk(KERN_DEBUG "Kernel managed physical pages: %lu\n", num_physpages);
+       high_memory = (void *)(memory_end & PAGE_MASK);
+       max_mapnr = MAP_NR(high_memory);
+       printk(KERN_DEBUG "Kernel managed physical pages: %lu\n", max_mapnr);
 
        /* This will put all low memory onto the freelists. */
-       totalram_pages = free_all_bootmem();
-
-       reservedpages = 0;
-       for (tmp = ARCH_PFN_OFFSET; tmp < max_mapnr; tmp++)
-               if (PageReserved(pfn_to_page(tmp)))
-                       reservedpages++;
-       freepages =  max_mapnr - ARCH_PFN_OFFSET - reservedpages;
-
-       /* do not count in kernel image between _rambase and _ramstart */
-       reservedpages -= (_ramstart - _rambase) >> PAGE_SHIFT;
-#if (defined(CONFIG_BFIN_EXTMEM_ICACHEABLE) && ANOMALY_05000263)
-       reservedpages += (_ramend - memory_end - DMA_UNCACHED_REGION) >> PAGE_SHIFT;
-#endif
-
-       codek = (_etext - _stext) >> 10;
-       initk = (__init_end - __init_begin) >> 10;
-       datak = ((_ramstart - _rambase) >> 10) - codek - initk;
+       free_all_bootmem();
 
-       printk(KERN_INFO
-            "Memory available: %luk/%luk RAM, "
-               "(%uk init code, %uk kernel code, %uk data, %uk dma, %uk reserved)\n",
-               (unsigned long) freepages << (PAGE_SHIFT-10), (_ramend - CONFIG_PHY_RAM_BASE_ADDRESS) >> 10,
-               initk, codek, datak, DMA_UNCACHED_REGION >> 10, (reservedpages << (PAGE_SHIFT-10)));
+       snprintf(buf, sizeof(buf) - 1, "%uK DMA", DMA_UNCACHED_REGION >> 10);
+       mem_init_print_info(buf);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
 #ifndef CONFIG_MPU
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 #endif
 }
 #endif
@@ -141,7 +115,7 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
 void __init_refok free_initmem(void)
 {
 #if defined CONFIG_RAMKERNEL && !defined CONFIG_MPU
-       free_initmem_default(0);
+       free_initmem_default(-1);
        if (memory_start == (unsigned long)(&__init_end))
                memory_start = (unsigned long)(&__init_begin);
 #endif
index 4258b088aa93af29c550405b62a2b36ad4ec9a29..e49f918531ad443671b6226a9f0f951f60156b7f 100644 (file)
@@ -55,3 +55,4 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += user.h
 generic-y += vga.h
+generic-y += xor.h
index 1d81c4c129eccb83d9cda4b1cbc170ed40b5b715..279d80725128fa638f300fb3471de57a57c58630 100644 (file)
@@ -54,16 +54,15 @@ SECTIONS
        }
 
        . = ALIGN(PAGE_SIZE);
+       __init_begin = .;
        .init :
        {
-               _stext = .;
                _sinittext = .;
                HEAD_TEXT
                INIT_TEXT
                _einittext = .;
        }
 
-       __init_begin = _stext;
        INIT_DATA_SECTION(16)
 
        PERCPU_SECTION(128)
@@ -74,6 +73,7 @@ SECTIONS
        .text :
        {
                _text = .;
+               _stext = .;
                TEXT_TEXT
                SCHED_TEXT
                LOCK_TEXT
index a9fcd89b251b6ebd25eef44ce010cc8cf2f7c8a9..63f5560d6eb25df9fbf8b2a739748581c8482fc6 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/initrd.h>
 
 #include <asm/sections.h>
+#include <asm/uaccess.h>
 
 /*
  * ZERO_PAGE is a special page that is used for zero-initialized
@@ -57,31 +58,22 @@ void __init paging_init(void)
 
 void __init mem_init(void)
 {
-       int codek, datak;
-       unsigned long tmp;
-       unsigned long len = memory_end - memory_start;
-
        high_memory = (void *)(memory_end & PAGE_MASK);
 
        /* this will put all memory onto the freelists */
-       totalram_pages = free_all_bootmem();
-
-       codek = (_etext - _stext) >> 10;
-       datak = (_end - _sdata) >> 10;
+       free_all_bootmem();
 
-       tmp = nr_free_pages() << PAGE_SHIFT;
-       printk(KERN_INFO "Memory: %luk/%luk RAM (%dk kernel code, %dk data)\n",
-              tmp >> 10, len >> 10, codek, datak);
+       mem_init_print_info(NULL);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
 
 void __init free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
index 8769a9045a543995c137f02f9bfc92bf3ce0da36..3201ddb8da6a039d3fd56b3fa13969648a004d08 100644 (file)
@@ -134,11 +134,13 @@ config SVINTO_SIM
 
 config ETRAXFS
        bool "ETRAX-FS-V32"
+       select CPU_FREQ_TABLE if CPU_FREQ
        help
          Support CRIS V32.
 
 config CRIS_MACH_ARTPEC3
         bool "ARTPEC-3"
+       select CPU_FREQ_TABLE if CPU_FREQ
         help
           Support Axis ARTPEC-3.
 
@@ -637,40 +639,10 @@ endchoice
 
 endmenu
 
-source "drivers/base/Kconfig"
-
-# standard linux drivers
-source "drivers/mtd/Kconfig"
-
-source "drivers/parport/Kconfig"
-
-source "drivers/pnp/Kconfig"
-
-source "drivers/block/Kconfig"
-
-source "drivers/ide/Kconfig"
-
-source "drivers/net/Kconfig"
-
-source "drivers/i2c/Kconfig"
-
-source "drivers/rtc/Kconfig"
-
-#
-# input before char - char/joystick depends on it. As does USB.
-#
-source "drivers/input/Kconfig"
-
-source "drivers/char/Kconfig"
+source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "drivers/usb/Kconfig"
-
-source "drivers/uwb/Kconfig"
-
-source "drivers/staging/Kconfig"
-
 source "arch/cris/Kconfig.debug"
 
 source "security/Kconfig"
index 37e6d2c50b764a1d72ea95b632f267d7d450fa80..22d846bfc570c6add486d620a9c1430bbd11a46a 100644 (file)
@@ -230,46 +230,6 @@ struct register_image
        unsigned int    usp;   /* 0x66 User mode stack pointer */
 } registers;
 
-/************** Prototypes for local library functions ***********************/
-
-/* Copy of strcpy from libc. */
-static char *gdb_cris_strcpy (char *s1, const char *s2);
-
-/* Copy of strlen from libc. */
-static int gdb_cris_strlen (const char *s);
-
-/* Copy of memchr from libc. */
-static void *gdb_cris_memchr (const void *s, int c, int n);
-
-/* Copy of strtol from libc. Does only support base 16. */
-static int gdb_cris_strtol (const char *s, char **endptr, int base);
-
-/********************** Prototypes for local functions. **********************/
-/* Copy the content of a register image into another. The size n is
-   the size of the register image. Due to struct assignment generation of
-   memcpy in libc. */
-static void copy_registers (registers *dptr, registers *sptr, int n);
-
-/* Copy the stored registers from the stack. Put the register contents
-   of thread thread_id in the struct reg. */
-static void copy_registers_from_stack (int thread_id, registers *reg);
-
-/* Copy the registers to the stack. Put the register contents of thread
-   thread_id from struct reg to the stack. */
-static void copy_registers_to_stack (int thread_id, registers *reg);
-
-/* Write a value to a specified register regno in the register image
-   of the current thread. */
-static int write_register (int regno, char *val);
-
-/* Write a value to a specified register in the stack of a thread other
-   than the current thread. */
-static int write_stack_register(int thread_id, int regno, char *valptr);
-
-/* Read a value from a specified register in the register image. Returns the
-   status of the read operation. The register value is returned in valptr. */
-static int read_register (char regno, unsigned int *valptr);
-
 /* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
 int getDebugChar (void);
 
@@ -278,42 +238,6 @@ void putDebugChar (int val);
 
 void enableDebugIRQ (void);
 
-/* Returns the integer equivalent of a hexadecimal character. */
-static int hex (char ch);
-
-/* Convert the memory, pointed to by mem into hexadecimal representation.
-   Put the result in buf, and return a pointer to the last character
-   in buf (null). */
-static char *mem2hex (char *buf, unsigned char *mem, int count);
-
-/* Convert the array, in hexadecimal representation, pointed to by buf into
-   binary representation. Put the result in mem, and return a pointer to
-   the character after the last byte written. */
-static unsigned char *hex2mem (unsigned char *mem, char *buf, int count);
-
-/* Put the content of the array, in binary representation, pointed to by buf
-   into memory pointed to by mem, and return a pointer to
-   the character after the last byte written. */
-static unsigned char *bin2mem (unsigned char *mem, unsigned char *buf, int count);
-
-/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
-   returned. */
-static void getpacket (char *buffer);
-
-/* Send $<data>#<checksum> from the <data> in the array buffer. */
-static void putpacket (char *buffer);
-
-/* Build and send a response packet in order to inform the host the
-   stub is stopped. */
-static void stub_is_stopped (int sigval);
-
-/* All expected commands are sent from remote.c. Send a response according
-   to the description in remote.c. */
-static void handle_exception (int sigval);
-
-/* Performs a complete re-start from scratch. ETRAX specific. */
-static void kill_restart (void);
-
 /******************** Prototypes for global functions. ***********************/
 
 /* The string str is prepended with the GDB printout token and sent. */
@@ -336,10 +260,6 @@ extern unsigned char executing_task;
 /* The number of characters used for a 64 bit thread identifier. */
 #define HEXCHARS_IN_THREAD_ID 16
 
-/* Avoid warning as the internal_stack is not used in the C-code. */
-#define USEDVAR(name)    { if (name) { ; } }
-#define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) }
-
 /********************************** Packet I/O ******************************/
 /* BUFMAX defines the maximum number of characters in
    inbound/outbound buffers */
@@ -405,7 +325,7 @@ static int register_size[] =
 
 /* Contains the register image of the executing thread in the assembler
    part of the code in order to avoid horrible addressing modes. */
-static registers reg;
+registers cris_reg;
 
 /* FIXME: Should this be used? Delete otherwise. */
 /* Contains the assumed consistency state of the register image. Uses the
@@ -413,7 +333,7 @@ static registers reg;
 static int consistency_status = SUCCESS;
 
 /********************************** Handle exceptions ************************/
-/* The variable reg contains the register image associated with the
+/* The variable cris_reg contains the register image associated with the
    current_thread_c variable. It is a complete register image created at
    entry. The reg_g contains a register image of a task where the general
    registers are taken from the stack and all special registers are taken
@@ -421,18 +341,10 @@ static int consistency_status = SUCCESS;
    in order to provide access mainly for 'g', 'G' and 'P'.
 */
 
-/* Need two task id pointers in order to handle Hct and Hgt commands. */
-static int current_thread_c = 0;
-static int current_thread_g = 0;
-
-/* Need two register images in order to handle Hct and Hgt commands. The
-   variable reg_g is in addition to reg above. */
-static registers reg_g;
-
 /********************************** Breakpoint *******************************/
 /* Use an internal stack in the breakpoint and interrupt response routines */
 #define INTERNAL_STACK_SIZE 1024
-static char internal_stack[INTERNAL_STACK_SIZE];
+char internal_stack[INTERNAL_STACK_SIZE];
 
 /* Due to the breakpoint return pointer, a state variable is needed to keep
    track of whether it is a static (compiled) or dynamic (gdb-invoked)
@@ -500,164 +412,6 @@ gdb_cris_strtol (const char *s, char **endptr, int base)
        return x;
 }
 
-/********************************* Register image ****************************/
-/* Copy the content of a register image into another. The size n is
-   the size of the register image. Due to struct assignment generation of
-   memcpy in libc. */
-static void
-copy_registers (registers *dptr, registers *sptr, int n)
-{
-       unsigned char *dreg;
-       unsigned char *sreg;
-       
-       for (dreg = (unsigned char*)dptr, sreg = (unsigned char*)sptr; n > 0; n--)
-               *dreg++ = *sreg++;
-}
-
-#ifdef PROCESS_SUPPORT
-/* Copy the stored registers from the stack. Put the register contents
-   of thread thread_id in the struct reg. */
-static void
-copy_registers_from_stack (int thread_id, registers *regptr)
-{
-       int j;
-       stack_registers *s = (stack_registers *)stack_list[thread_id];
-       unsigned int *d = (unsigned int *)regptr;
-       
-       for (j = 13; j >= 0; j--)
-               *d++ = s->r[j];
-       regptr->sp = (unsigned int)stack_list[thread_id];
-       regptr->pc = s->pc;
-       regptr->dccr = s->dccr;
-       regptr->srp = s->srp;
-}
-
-/* Copy the registers to the stack. Put the register contents of thread
-   thread_id from struct reg to the stack. */
-static void
-copy_registers_to_stack (int thread_id, registers *regptr)
-{
-       int i;
-       stack_registers *d = (stack_registers *)stack_list[thread_id];
-       unsigned int *s = (unsigned int *)regptr;
-       
-       for (i = 0; i < 14; i++) {
-               d->r[i] = *s++;
-       }
-       d->pc = regptr->pc;
-       d->dccr = regptr->dccr;
-       d->srp = regptr->srp;
-}
-#endif
-
-/* Write a value to a specified register in the register image of the current
-   thread. Returns status code SUCCESS, E02 or E05. */
-static int
-write_register (int regno, char *val)
-{
-       int status = SUCCESS;
-       registers *current_reg = &reg;
-
-        if (regno >= R0 && regno <= PC) {
-               /* 32-bit register with simple offset. */
-               hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int),
-                        val, sizeof(unsigned int));
-       }
-        else if (regno == P0 || regno == VR || regno == P4 || regno == P8) {
-               /* Do not support read-only registers. */
-               status = E02;
-       }
-        else if (regno == CCR) {
-               /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented, 
-                   and P7 (MOF) is 32 bits in ETRAX 100LX. */
-               hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short),
-                        val, sizeof(unsigned short));
-       }
-       else if (regno >= MOF && regno <= USP) {
-               /* 32 bit register with complex offset.  (P8 has been taken care of.) */
-               hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int),
-                        val, sizeof(unsigned int));
-       } 
-        else {
-               /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
-               status = E05;
-       }
-       return status;
-}
-
-#ifdef PROCESS_SUPPORT
-/* Write a value to a specified register in the stack of a thread other
-   than the current thread. Returns status code SUCCESS or E07. */
-static int
-write_stack_register (int thread_id, int regno, char *valptr)
-{
-       int status = SUCCESS;
-       stack_registers *d = (stack_registers *)stack_list[thread_id];
-       unsigned int val;
-       
-       hex2mem ((unsigned char *)&val, valptr, sizeof(unsigned int));
-       if (regno >= R0 && regno < SP) {
-               d->r[regno] = val;
-       }
-       else if (regno == SP) {
-               stack_list[thread_id] = val;
-       }
-       else if (regno == PC) {
-               d->pc = val;
-       }
-       else if (regno == SRP) {
-               d->srp = val;
-       }
-       else if (regno == DCCR) {
-               d->dccr = val;
-       }
-       else {
-               /* Do not support registers in the current thread. */
-               status = E07;
-       }
-       return status;
-}
-#endif
-
-/* Read a value from a specified register in the register image. Returns the
-   value in the register or -1 for non-implemented registers.
-   Should check consistency_status after a call which may be E05 after changes
-   in the implementation. */
-static int
-read_register (char regno, unsigned int *valptr)
-{
-       registers *current_reg = &reg;
-
-       if (regno >= R0 && regno <= PC) {
-               /* 32-bit register with simple offset. */
-               *valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int));
-                return SUCCESS;
-       }
-       else if (regno == P0 || regno == VR) {
-               /* 8 bit register with complex offset. */
-               *valptr = (unsigned int)(*(unsigned char *)
-                                         ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char)));
-                return SUCCESS;
-       }
-       else if (regno == P4 || regno == CCR) {
-               /* 16 bit register with complex offset. */
-               *valptr = (unsigned int)(*(unsigned short *)
-                                         ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short)));
-                return SUCCESS;
-       }
-       else if (regno >= MOF && regno <= USP) {
-               /* 32 bit register with complex offset. */
-               *valptr = *(unsigned int *)((char *)&(current_reg->p8)
-                                            + (regno-P8) * sizeof(unsigned int));
-                return SUCCESS;
-       }
-       else {
-               /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
-               consistency_status = E05;
-               return E05;
-       }
-}
-
 /********************************** Packet I/O ******************************/
 /* Returns the integer equivalent of a hexadecimal character. */
 static int
@@ -676,8 +430,6 @@ hex (char ch)
    Put the result in buf, and return a pointer to the last character
    in buf (null). */
 
-static int do_printk = 0;
-
 static char *
 mem2hex(char *buf, unsigned char *mem, int count)
 {
@@ -761,7 +513,7 @@ getpacket (char *buffer)
                xmitcsum = -1;
                count = 0;
                /* Read until a # or the end of the buffer is reached */
-               while (count < BUFMAX) {
+               while (count < BUFMAX - 1) {
                        ch = getDebugChar ();
                        if (ch == '#')
                                break;
@@ -845,6 +597,81 @@ putDebugString (const unsigned char *str, int length)
         putpacket(remcomOutBuffer);
 }
 
+/********************************* Register image ****************************/
+/* Write a value to a specified register in the register image of the current
+   thread. Returns status code SUCCESS, E02 or E05. */
+static int
+write_register (int regno, char *val)
+{
+       int status = SUCCESS;
+       registers *current_reg = &cris_reg;
+
+        if (regno >= R0 && regno <= PC) {
+               /* 32-bit register with simple offset. */
+               hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int),
+                        val, sizeof(unsigned int));
+       }
+        else if (regno == P0 || regno == VR || regno == P4 || regno == P8) {
+               /* Do not support read-only registers. */
+               status = E02;
+       }
+        else if (regno == CCR) {
+               /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented, 
+                   and P7 (MOF) is 32 bits in ETRAX 100LX. */
+               hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short),
+                        val, sizeof(unsigned short));
+       }
+       else if (regno >= MOF && regno <= USP) {
+               /* 32 bit register with complex offset.  (P8 has been taken care of.) */
+               hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int),
+                        val, sizeof(unsigned int));
+       } 
+        else {
+               /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+               status = E05;
+       }
+       return status;
+}
+
+/* Read a value from a specified register in the register image. Returns the
+   value in the register or -1 for non-implemented registers.
+   Should check consistency_status after a call which may be E05 after changes
+   in the implementation. */
+static int
+read_register (char regno, unsigned int *valptr)
+{
+       registers *current_reg = &cris_reg;
+
+       if (regno >= R0 && regno <= PC) {
+               /* 32-bit register with simple offset. */
+               *valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int));
+                return SUCCESS;
+       }
+       else if (regno == P0 || regno == VR) {
+               /* 8 bit register with complex offset. */
+               *valptr = (unsigned int)(*(unsigned char *)
+                                         ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char)));
+                return SUCCESS;
+       }
+       else if (regno == P4 || regno == CCR) {
+               /* 16 bit register with complex offset. */
+               *valptr = (unsigned int)(*(unsigned short *)
+                                         ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short)));
+                return SUCCESS;
+       }
+       else if (regno >= MOF && regno <= USP) {
+               /* 32 bit register with complex offset. */
+               *valptr = *(unsigned int *)((char *)&(current_reg->p8)
+                                            + (regno-P8) * sizeof(unsigned int));
+                return SUCCESS;
+       }
+       else {
+               /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+               consistency_status = E05;
+               return E05;
+       }
+}
+
 /********************************** Handle exceptions ************************/
 /* Build and send a response packet in order to inform the host the
    stub is stopped. TAAn...:r...;n...:r...;n...:r...;
@@ -891,26 +718,6 @@ stub_is_stopped(int sigval)
                 
        }
 
-#ifdef PROCESS_SUPPORT
-       /* Store the registers of the executing thread. Assume that both step,
-          continue, and register content requests are with respect to this
-          thread. The executing task is from the operating system scheduler. */
-
-       current_thread_c = executing_task;
-       current_thread_g = executing_task;
-
-       /* A struct assignment translates into a libc memcpy call. Avoid
-          all libc functions in order to prevent recursive break points. */
-       copy_registers (&reg_g, &reg, sizeof(registers));
-
-       /* Store thread:r...; with the executing task TID. */
-       gdb_cris_strcpy (&remcomOutBuffer[pos], "thread:");
-       pos += gdb_cris_strlen ("thread:");
-       remcomOutBuffer[pos++] = hex_asc_hi(executing_task);
-       remcomOutBuffer[pos++] = hex_asc_lo(executing_task);
-       gdb_cris_strcpy (&remcomOutBuffer[pos], ";");
-#endif
-
        /* null-terminate and send it off */
 
        *ptr = 0;
@@ -918,16 +725,18 @@ stub_is_stopped(int sigval)
        putpacket (remcomOutBuffer);
 }
 
+/* Performs a complete re-start from scratch. */
+static void
+kill_restart (void)
+{
+       machine_restart("");
+}
+
 /* All expected commands are sent from remote.c. Send a response according
    to the description in remote.c. */
-static void
+void
 handle_exception (int sigval)
 {
-       /* Avoid warning of not used. */
-
-       USEDFUN(handle_exception);
-       USEDVAR(internal_stack[0]);
-
        /* Send response. */
 
        stub_is_stopped (sigval);
@@ -943,19 +752,7 @@ handle_exception (int sigval)
                                   in a register  are in the same order the machine uses.
                                   Failure: void. */
                                
-                               {
-#ifdef PROCESS_SUPPORT
-                                       /* Use the special register content in the executing thread. */
-                                       copy_registers (&reg_g, &reg, sizeof(registers));
-                                       /* Replace the content available on the stack. */
-                                       if (current_thread_g != executing_task) {
-                                               copy_registers_from_stack (current_thread_g, &reg_g);
-                                       }
-                                       mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)&reg_g, sizeof(registers));
-#else
-                                       mem2hex(remcomOutBuffer, (char *)&reg, sizeof(registers));
-#endif
-                               }
+                               mem2hex(remcomOutBuffer, (char *)&cris_reg, sizeof(registers));
                                break;
                                
                        case 'G':
@@ -963,17 +760,7 @@ handle_exception (int sigval)
                                   Each byte of register data  is described by two hex digits.
                                   Success: OK
                                   Failure: void. */
-#ifdef PROCESS_SUPPORT
-                               hex2mem ((unsigned char *)&reg_g, &remcomInBuffer[1], sizeof(registers));
-                               if (current_thread_g == executing_task) {
-                                       copy_registers (&reg, &reg_g, sizeof(registers));
-                               }
-                               else {
-                                       copy_registers_to_stack(current_thread_g, &reg_g);
-                               }
-#else
-                               hex2mem((char *)&reg, &remcomInBuffer[1], sizeof(registers));
-#endif
+                               hex2mem((char *)&cris_reg, &remcomInBuffer[1], sizeof(registers));
                                gdb_cris_strcpy (remcomOutBuffer, "OK");
                                break;
                                
@@ -989,12 +776,7 @@ handle_exception (int sigval)
                                        char *suffix;
                                        int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16);
                                        int status;
-#ifdef PROCESS_SUPPORT
-                                       if (current_thread_g != executing_task)
-                                               status = write_stack_register (current_thread_g, regno, suffix+1);
-                                       else
-#endif
-                                               status = write_register (regno, suffix+1);
+                                       status = write_register (regno, suffix+1);
 
                                        switch (status) {
                                                case E02:
@@ -1073,7 +855,7 @@ handle_exception (int sigval)
                                   Success: return to the executing thread.
                                   Failure: will never know. */
                                if (remcomInBuffer[1] != '\0') {
-                                       reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
+                                       cris_reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
                                }
                                enableDebugIRQ();
                                return;
@@ -1129,119 +911,6 @@ handle_exception (int sigval)
                                   Not supported: E04 */
                                gdb_cris_strcpy (remcomOutBuffer, error_message[E04]);
                                break;
-#ifdef PROCESS_SUPPORT
-
-                       case 'T':
-                               /* Thread alive. TXX
-                                  Is thread XX alive?
-                                  Success: OK, thread XX is alive.
-                                  Failure: E03, thread XX is dead. */
-                               {
-                                       int thread_id = (int)gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
-                                       /* Cannot tell whether it is alive or not. */
-                                       if (thread_id >= 0 && thread_id < number_of_tasks)
-                                               gdb_cris_strcpy (remcomOutBuffer, "OK");
-                               }
-                               break;
-                                                               
-                       case 'H':
-                               /* Set thread for subsequent operations: Hct
-                                  c = 'c' for thread used in step and continue;
-                                  t can be -1 for all threads.
-                                  c = 'g' for thread used in other  operations.
-                                  t = 0 means pick any thread.
-                                  Success: OK
-                                  Failure: E01 */
-                               {
-                                       int thread_id = gdb_cris_strtol (&remcomInBuffer[2], 0, 16);
-                                       if (remcomInBuffer[1] == 'c') {
-                                               /* c = 'c' for thread used in step and continue */
-                                               /* Do not change current_thread_c here. It would create a mess in
-                                                  the scheduler. */
-                                               gdb_cris_strcpy (remcomOutBuffer, "OK");
-                                       }
-                                       else if (remcomInBuffer[1] == 'g') {
-                                               /* c = 'g' for thread used in other  operations.
-                                                  t = 0 means pick any thread. Impossible since the scheduler does
-                                                  not allow that. */
-                                               if (thread_id >= 0 && thread_id < number_of_tasks) {
-                                                       current_thread_g = thread_id;
-                                                       gdb_cris_strcpy (remcomOutBuffer, "OK");
-                                               }
-                                               else {
-                                                       /* Not expected - send an error message. */
-                                                       gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
-                                               }
-                                       }
-                                       else {
-                                               /* Not expected - send an error message. */
-                                               gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
-                                       }
-                               }
-                               break;
-                               
-                       case 'q':
-                       case 'Q':
-                               /* Query of general interest. qXXXX
-                                  Set general value XXXX. QXXXX=yyyy */
-                               {
-                                       int pos;
-                                       int nextpos;
-                                       int thread_id;
-                                       
-                                       switch (remcomInBuffer[1]) {
-                                               case 'C':
-                                                       /* Identify the remote current thread. */
-                                                       gdb_cris_strcpy (&remcomOutBuffer[0], "QC");
-                                                       remcomOutBuffer[2] = hex_asc_hi(current_thread_c);
-                                                       remcomOutBuffer[3] = hex_asc_lo(current_thread_c);
-                                                       remcomOutBuffer[4] = '\0';
-                                                       break;
-                                               case 'L':
-                                                       gdb_cris_strcpy (&remcomOutBuffer[0], "QM");
-                                                       /* Reply with number of threads. */
-                                                       if (os_is_started()) {
-                                                               remcomOutBuffer[2] = hex_asc_hi(number_of_tasks);
-                                                               remcomOutBuffer[3] = hex_asc_lo(number_of_tasks);
-                                                       }
-                                                       else {
-                                                               remcomOutBuffer[2] = hex_asc_hi(0);
-                                                               remcomOutBuffer[3] = hex_asc_lo(1);
-                                                       }
-                                                       /* Done with the reply. */
-                                                       remcomOutBuffer[4] = hex_asc_lo(1);
-                                                       pos = 5;
-                                                       /* Expects the argument thread id. */
-                                                       for (; pos < (5 + HEXCHARS_IN_THREAD_ID); pos++)
-                                                               remcomOutBuffer[pos] = remcomInBuffer[pos];
-                                                       /* Reply with the thread identifiers. */
-                                                       if (os_is_started()) {
-                                                               /* Store the thread identifiers of all tasks. */
-                                                               for (thread_id = 0; thread_id < number_of_tasks; thread_id++) {
-                                                                       nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
-                                                                       for (; pos < nextpos; pos ++)
-                                                                               remcomOutBuffer[pos] = hex_asc_lo(0);
-                                                                       remcomOutBuffer[pos++] = hex_asc_lo(thread_id);
-                                                               }
-                                                       }
-                                                       else {
-                                                               /* Store the thread identifier of the boot task. */
-                                                               nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
-                                                               for (; pos < nextpos; pos ++)
-                                                                       remcomOutBuffer[pos] = hex_asc_lo(0);
-                                                               remcomOutBuffer[pos++] = hex_asc_lo(current_thread_c);
-                                                       }
-                                                       remcomOutBuffer[pos] = '\0';
-                                                       break;
-                                               default:
-                                                       /* Not supported: "" */
-                                                       /* Request information about section offsets: qOffsets. */
-                                                       remcomOutBuffer[0] = 0;
-                                                       break;
-                                       }
-                               }
-                               break;
-#endif /* PROCESS_SUPPORT */
                                
                        default:
                                /* The stub should ignore other request and send an empty
@@ -1254,13 +923,6 @@ handle_exception (int sigval)
        }
 }
 
-/* Performs a complete re-start from scratch. */
-static void
-kill_restart ()
-{
-       machine_restart("");
-}
-
 /********************************** Breakpoint *******************************/
 /* The hook for both a static (compiled) and a dynamic breakpoint set by GDB.
    An internal stack is used by the stub. The register image of the caller is
@@ -1270,93 +932,93 @@ kill_restart ()
 
 void kgdb_handle_breakpoint(void);
 
-asm ("
-  .global kgdb_handle_breakpoint
-kgdb_handle_breakpoint:
-;;
-;; Response to the break-instruction
-;;
-;; Create a register image of the caller
-;;
-  move     $dccr,[reg+0x5E] ; Save the flags in DCCR before disable interrupts
-  di                        ; Disable interrupts
-  move.d   $r0,[reg]        ; Save R0
-  move.d   $r1,[reg+0x04]   ; Save R1
-  move.d   $r2,[reg+0x08]   ; Save R2
-  move.d   $r3,[reg+0x0C]   ; Save R3
-  move.d   $r4,[reg+0x10]   ; Save R4
-  move.d   $r5,[reg+0x14]   ; Save R5
-  move.d   $r6,[reg+0x18]   ; Save R6
-  move.d   $r7,[reg+0x1C]   ; Save R7
-  move.d   $r8,[reg+0x20]   ; Save R8
-  move.d   $r9,[reg+0x24]   ; Save R9
-  move.d   $r10,[reg+0x28]  ; Save R10
-  move.d   $r11,[reg+0x2C]  ; Save R11
-  move.d   $r12,[reg+0x30]  ; Save R12
-  move.d   $r13,[reg+0x34]  ; Save R13
-  move.d   $sp,[reg+0x38]   ; Save SP (R14)
-;; Due to the old assembler-versions BRP might not be recognized
-  .word 0xE670              ; move brp,$r0
-  subq     2,$r0             ; Set to address of previous instruction.
-  move.d   $r0,[reg+0x3c]   ; Save the address in PC (R15)
-  clear.b  [reg+0x40]      ; Clear P0
-  move     $vr,[reg+0x41]   ; Save special register P1
-  clear.w  [reg+0x42]      ; Clear P4
-  move     $ccr,[reg+0x44]  ; Save special register CCR
-  move     $mof,[reg+0x46]  ; P7
-  clear.d  [reg+0x4A]      ; Clear P8
-  move     $ibr,[reg+0x4E]  ; P9,
-  move     $irp,[reg+0x52]  ; P10,
-  move     $srp,[reg+0x56]  ; P11,
-  move     $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR
-                            ; P13, register DCCR already saved
-;; Due to the old assembler-versions BRP might not be recognized
-  .word 0xE670              ; move brp,r0
-;; Static (compiled) breakpoints must return to the next instruction in order
-;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction
-;; in order to execute it when execution is continued.
-  test.b   [is_dyn_brkp]    ; Is this a dynamic breakpoint?
-  beq      is_static         ; No, a static breakpoint
-  nop
-  subq     2,$r0              ; rerun the instruction the break replaced
-is_static:
-  moveq    1,$r1
-  move.b   $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint
-  move.d   $r0,[reg+0x62]    ; Save the return address in BRP
-  move     $usp,[reg+0x66]   ; USP
-;;
-;; Handle the communication
-;;
-  move.d   internal_stack+1020,$sp ; Use the internal stack which grows upward
-  moveq    5,$r10                   ; SIGTRAP
-  jsr      handle_exception       ; Interactive routine
-;;
-;; Return to the caller
-;;
-   move.d  [reg],$r0         ; Restore R0
-   move.d  [reg+0x04],$r1    ; Restore R1
-   move.d  [reg+0x08],$r2    ; Restore R2
-   move.d  [reg+0x0C],$r3    ; Restore R3
-   move.d  [reg+0x10],$r4    ; Restore R4
-   move.d  [reg+0x14],$r5    ; Restore R5
-   move.d  [reg+0x18],$r6    ; Restore R6
-   move.d  [reg+0x1C],$r7    ; Restore R7
-   move.d  [reg+0x20],$r8    ; Restore R8
-   move.d  [reg+0x24],$r9    ; Restore R9
-   move.d  [reg+0x28],$r10   ; Restore R10
-   move.d  [reg+0x2C],$r11   ; Restore R11
-   move.d  [reg+0x30],$r12   ; Restore R12
-   move.d  [reg+0x34],$r13   ; Restore R13
-;;
-;; FIXME: Which registers should be restored?
-;;
-   move.d  [reg+0x38],$sp    ; Restore SP (R14)
-   move    [reg+0x56],$srp   ; Restore the subroutine return pointer.
-   move    [reg+0x5E],$dccr  ; Restore DCCR
-   move    [reg+0x66],$usp   ; Restore USP
-   jump    [reg+0x62]       ; A jump to the content in register BRP works.
-   nop                       ;
-");
+asm ("\n"
+"  .global kgdb_handle_breakpoint\n"
+"kgdb_handle_breakpoint:\n"
+";;\n"
+";; Response to the break-instruction\n"
+";;\n"
+";; Create a register image of the caller\n"
+";;\n"
+"  move     $dccr,[cris_reg+0x5E] ; Save the flags in DCCR before disable interrupts\n"
+"  di                        ; Disable interrupts\n"
+"  move.d   $r0,[cris_reg]        ; Save R0\n"
+"  move.d   $r1,[cris_reg+0x04]   ; Save R1\n"
+"  move.d   $r2,[cris_reg+0x08]   ; Save R2\n"
+"  move.d   $r3,[cris_reg+0x0C]   ; Save R3\n"
+"  move.d   $r4,[cris_reg+0x10]   ; Save R4\n"
+"  move.d   $r5,[cris_reg+0x14]   ; Save R5\n"
+"  move.d   $r6,[cris_reg+0x18]   ; Save R6\n"
+"  move.d   $r7,[cris_reg+0x1C]   ; Save R7\n"
+"  move.d   $r8,[cris_reg+0x20]   ; Save R8\n"
+"  move.d   $r9,[cris_reg+0x24]   ; Save R9\n"
+"  move.d   $r10,[cris_reg+0x28]  ; Save R10\n"
+"  move.d   $r11,[cris_reg+0x2C]  ; Save R11\n"
+"  move.d   $r12,[cris_reg+0x30]  ; Save R12\n"
+"  move.d   $r13,[cris_reg+0x34]  ; Save R13\n"
+"  move.d   $sp,[cris_reg+0x38]   ; Save SP (R14)\n"
+";; Due to the old assembler-versions BRP might not be recognized\n"
+"  .word 0xE670              ; move brp,$r0\n"
+"  subq     2,$r0             ; Set to address of previous instruction.\n"
+"  move.d   $r0,[cris_reg+0x3c]   ; Save the address in PC (R15)\n"
+"  clear.b  [cris_reg+0x40]      ; Clear P0\n"
+"  move     $vr,[cris_reg+0x41]   ; Save special register P1\n"
+"  clear.w  [cris_reg+0x42]      ; Clear P4\n"
+"  move     $ccr,[cris_reg+0x44]  ; Save special register CCR\n"
+"  move     $mof,[cris_reg+0x46]  ; P7\n"
+"  clear.d  [cris_reg+0x4A]      ; Clear P8\n"
+"  move     $ibr,[cris_reg+0x4E]  ; P9,\n"
+"  move     $irp,[cris_reg+0x52]  ; P10,\n"
+"  move     $srp,[cris_reg+0x56]  ; P11,\n"
+"  move     $dtp0,[cris_reg+0x5A] ; P12, register BAR, assembler might not know BAR\n"
+"                            ; P13, register DCCR already saved\n"
+";; Due to the old assembler-versions BRP might not be recognized\n"
+"  .word 0xE670              ; move brp,r0\n"
+";; Static (compiled) breakpoints must return to the next instruction in order\n"
+";; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction\n"
+";; in order to execute it when execution is continued.\n"
+"  test.b   [is_dyn_brkp]    ; Is this a dynamic breakpoint?\n"
+"  beq      is_static         ; No, a static breakpoint\n"
+"  nop\n"
+"  subq     2,$r0              ; rerun the instruction the break replaced\n"
+"is_static:\n"
+"  moveq    1,$r1\n"
+"  move.b   $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint\n"
+"  move.d   $r0,[cris_reg+0x62]    ; Save the return address in BRP\n"
+"  move     $usp,[cris_reg+0x66]   ; USP\n"
+";;\n"
+";; Handle the communication\n"
+";;\n"
+"  move.d   internal_stack+1020,$sp ; Use the internal stack which grows upward\n"
+"  moveq    5,$r10                   ; SIGTRAP\n"
+"  jsr      handle_exception       ; Interactive routine\n"
+";;\n"
+";; Return to the caller\n"
+";;\n"
+"   move.d  [cris_reg],$r0         ; Restore R0\n"
+"   move.d  [cris_reg+0x04],$r1    ; Restore R1\n"
+"   move.d  [cris_reg+0x08],$r2    ; Restore R2\n"
+"   move.d  [cris_reg+0x0C],$r3    ; Restore R3\n"
+"   move.d  [cris_reg+0x10],$r4    ; Restore R4\n"
+"   move.d  [cris_reg+0x14],$r5    ; Restore R5\n"
+"   move.d  [cris_reg+0x18],$r6    ; Restore R6\n"
+"   move.d  [cris_reg+0x1C],$r7    ; Restore R7\n"
+"   move.d  [cris_reg+0x20],$r8    ; Restore R8\n"
+"   move.d  [cris_reg+0x24],$r9    ; Restore R9\n"
+"   move.d  [cris_reg+0x28],$r10   ; Restore R10\n"
+"   move.d  [cris_reg+0x2C],$r11   ; Restore R11\n"
+"   move.d  [cris_reg+0x30],$r12   ; Restore R12\n"
+"   move.d  [cris_reg+0x34],$r13   ; Restore R13\n"
+";;\n"
+";; FIXME: Which registers should be restored?\n"
+";;\n"
+"   move.d  [cris_reg+0x38],$sp    ; Restore SP (R14)\n"
+"   move    [cris_reg+0x56],$srp   ; Restore the subroutine return pointer.\n"
+"   move    [cris_reg+0x5E],$dccr  ; Restore DCCR\n"
+"   move    [cris_reg+0x66],$usp   ; Restore USP\n"
+"   jump    [cris_reg+0x62]       ; A jump to the content in register BRP works.\n"
+"   nop                       ;\n"
+"\n");
 
 /* The hook for an interrupt generated by GDB. An internal stack is used
    by the stub. The register image of the caller is stored in the structure
@@ -1367,94 +1029,94 @@ is_static:
 
 void kgdb_handle_serial(void);
 
-asm ("
-  .global kgdb_handle_serial
-kgdb_handle_serial:
-;;
-;; Response to a serial interrupt
-;;
-
-  move     $dccr,[reg+0x5E] ; Save the flags in DCCR
-  di                        ; Disable interrupts
-  move.d   $r0,[reg]        ; Save R0
-  move.d   $r1,[reg+0x04]   ; Save R1
-  move.d   $r2,[reg+0x08]   ; Save R2
-  move.d   $r3,[reg+0x0C]   ; Save R3
-  move.d   $r4,[reg+0x10]   ; Save R4
-  move.d   $r5,[reg+0x14]   ; Save R5
-  move.d   $r6,[reg+0x18]   ; Save R6
-  move.d   $r7,[reg+0x1C]   ; Save R7
-  move.d   $r8,[reg+0x20]   ; Save R8
-  move.d   $r9,[reg+0x24]   ; Save R9
-  move.d   $r10,[reg+0x28]  ; Save R10
-  move.d   $r11,[reg+0x2C]  ; Save R11
-  move.d   $r12,[reg+0x30]  ; Save R12
-  move.d   $r13,[reg+0x34]  ; Save R13
-  move.d   $sp,[reg+0x38]   ; Save SP (R14)
-  move     $irp,[reg+0x3c]  ; Save the address in PC (R15)
-  clear.b  [reg+0x40]      ; Clear P0
-  move     $vr,[reg+0x41]   ; Save special register P1,
-  clear.w  [reg+0x42]      ; Clear P4
-  move     $ccr,[reg+0x44]  ; Save special register CCR
-  move     $mof,[reg+0x46]  ; P7
-  clear.d  [reg+0x4A]      ; Clear P8
-  move     $ibr,[reg+0x4E]  ; P9,
-  move     $irp,[reg+0x52]  ; P10,
-  move     $srp,[reg+0x56]  ; P11,
-  move     $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR
-                            ; P13, register DCCR already saved
-;; Due to the old assembler-versions BRP might not be recognized
-  .word 0xE670              ; move brp,r0
-  move.d   $r0,[reg+0x62]   ; Save the return address in BRP
-  move     $usp,[reg+0x66]  ; USP
-
-;; get the serial character (from debugport.c) and check if it is a ctrl-c
-
-  jsr getDebugChar
-  cmp.b 3, $r10
-  bne goback
-  nop
-
-  move.d  [reg+0x5E], $r10             ; Get DCCR
-  btstq           8, $r10                      ; Test the U-flag.
-  bmi     goback
-  nop
-
-;;
-;; Handle the communication
-;;
-  move.d   internal_stack+1020,$sp ; Use the internal stack
-  moveq    2,$r10                   ; SIGINT
-  jsr      handle_exception       ; Interactive routine
-
-goback:
-;;
-;; Return to the caller
-;;
-   move.d  [reg],$r0         ; Restore R0
-   move.d  [reg+0x04],$r1    ; Restore R1
-   move.d  [reg+0x08],$r2    ; Restore R2
-   move.d  [reg+0x0C],$r3    ; Restore R3
-   move.d  [reg+0x10],$r4    ; Restore R4
-   move.d  [reg+0x14],$r5    ; Restore R5
-   move.d  [reg+0x18],$r6    ; Restore R6
-   move.d  [reg+0x1C],$r7    ; Restore R7
-   move.d  [reg+0x20],$r8    ; Restore R8
-   move.d  [reg+0x24],$r9    ; Restore R9
-   move.d  [reg+0x28],$r10   ; Restore R10
-   move.d  [reg+0x2C],$r11   ; Restore R11
-   move.d  [reg+0x30],$r12   ; Restore R12
-   move.d  [reg+0x34],$r13   ; Restore R13
-;;
-;; FIXME: Which registers should be restored?
-;;
-   move.d  [reg+0x38],$sp    ; Restore SP (R14)
-   move    [reg+0x56],$srp   ; Restore the subroutine return pointer.
-   move    [reg+0x5E],$dccr  ; Restore DCCR
-   move    [reg+0x66],$usp   ; Restore USP
-   reti                      ; Return from the interrupt routine
-   nop
-");
+asm ("\n"
+"  .global kgdb_handle_serial\n"
+"kgdb_handle_serial:\n"
+";;\n"
+";; Response to a serial interrupt\n"
+";;\n"
+"\n"
+"  move     $dccr,[cris_reg+0x5E] ; Save the flags in DCCR\n"
+"  di                        ; Disable interrupts\n"
+"  move.d   $r0,[cris_reg]        ; Save R0\n"
+"  move.d   $r1,[cris_reg+0x04]   ; Save R1\n"
+"  move.d   $r2,[cris_reg+0x08]   ; Save R2\n"
+"  move.d   $r3,[cris_reg+0x0C]   ; Save R3\n"
+"  move.d   $r4,[cris_reg+0x10]   ; Save R4\n"
+"  move.d   $r5,[cris_reg+0x14]   ; Save R5\n"
+"  move.d   $r6,[cris_reg+0x18]   ; Save R6\n"
+"  move.d   $r7,[cris_reg+0x1C]   ; Save R7\n"
+"  move.d   $r8,[cris_reg+0x20]   ; Save R8\n"
+"  move.d   $r9,[cris_reg+0x24]   ; Save R9\n"
+"  move.d   $r10,[cris_reg+0x28]  ; Save R10\n"
+"  move.d   $r11,[cris_reg+0x2C]  ; Save R11\n"
+"  move.d   $r12,[cris_reg+0x30]  ; Save R12\n"
+"  move.d   $r13,[cris_reg+0x34]  ; Save R13\n"
+"  move.d   $sp,[cris_reg+0x38]   ; Save SP (R14)\n"
+"  move     $irp,[cris_reg+0x3c]  ; Save the address in PC (R15)\n"
+"  clear.b  [cris_reg+0x40]      ; Clear P0\n"
+"  move     $vr,[cris_reg+0x41]   ; Save special register P1,\n"
+"  clear.w  [cris_reg+0x42]      ; Clear P4\n"
+"  move     $ccr,[cris_reg+0x44]  ; Save special register CCR\n"
+"  move     $mof,[cris_reg+0x46]  ; P7\n"
+"  clear.d  [cris_reg+0x4A]      ; Clear P8\n"
+"  move     $ibr,[cris_reg+0x4E]  ; P9,\n"
+"  move     $irp,[cris_reg+0x52]  ; P10,\n"
+"  move     $srp,[cris_reg+0x56]  ; P11,\n"
+"  move     $dtp0,[cris_reg+0x5A] ; P12, register BAR, assembler might not know BAR\n"
+"                            ; P13, register DCCR already saved\n"
+";; Due to the old assembler-versions BRP might not be recognized\n"
+"  .word 0xE670              ; move brp,r0\n"
+"  move.d   $r0,[cris_reg+0x62]   ; Save the return address in BRP\n"
+"  move     $usp,[cris_reg+0x66]  ; USP\n"
+"\n"
+";; get the serial character (from debugport.c) and check if it is a ctrl-c\n"
+"\n"
+"  jsr getDebugChar\n"
+"  cmp.b 3, $r10\n"
+"  bne goback\n"
+"  nop\n"
+"\n"
+"  move.d  [cris_reg+0x5E], $r10               ; Get DCCR\n"
+"  btstq          8, $r10                      ; Test the U-flag.\n"
+"  bmi    goback\n"
+"  nop\n"
+"\n"
+";;\n"
+";; Handle the communication\n"
+";;\n"
+"  move.d   internal_stack+1020,$sp ; Use the internal stack\n"
+"  moveq    2,$r10                   ; SIGINT\n"
+"  jsr      handle_exception       ; Interactive routine\n"
+"\n"
+"goback:\n"
+";;\n"
+";; Return to the caller\n"
+";;\n"
+"   move.d  [cris_reg],$r0         ; Restore R0\n"
+"   move.d  [cris_reg+0x04],$r1    ; Restore R1\n"
+"   move.d  [cris_reg+0x08],$r2    ; Restore R2\n"
+"   move.d  [cris_reg+0x0C],$r3    ; Restore R3\n"
+"   move.d  [cris_reg+0x10],$r4    ; Restore R4\n"
+"   move.d  [cris_reg+0x14],$r5    ; Restore R5\n"
+"   move.d  [cris_reg+0x18],$r6    ; Restore R6\n"
+"   move.d  [cris_reg+0x1C],$r7    ; Restore R7\n"
+"   move.d  [cris_reg+0x20],$r8    ; Restore R8\n"
+"   move.d  [cris_reg+0x24],$r9    ; Restore R9\n"
+"   move.d  [cris_reg+0x28],$r10   ; Restore R10\n"
+"   move.d  [cris_reg+0x2C],$r11   ; Restore R11\n"
+"   move.d  [cris_reg+0x30],$r12   ; Restore R12\n"
+"   move.d  [cris_reg+0x34],$r13   ; Restore R13\n"
+";;\n"
+";; FIXME: Which registers should be restored?\n"
+";;\n"
+"   move.d  [cris_reg+0x38],$sp    ; Restore SP (R14)\n"
+"   move    [cris_reg+0x56],$srp   ; Restore the subroutine return pointer.\n"
+"   move    [cris_reg+0x5E],$dccr  ; Restore DCCR\n"
+"   move    [cris_reg+0x66],$usp   ; Restore USP\n"
+"   reti                      ; Return from the interrupt routine\n"
+"   nop\n"
+"\n");
 
 /* Use this static breakpoint in the start-up only. */
 
index ab725edbc680adea502ea245a9ff70ea73e1cdf3..acff3df8c43fcfbb651146ab2b5f75ef52c3be95 100644 (file)
@@ -640,8 +640,6 @@ config ETRAX_STREAMCOPROC
          This option enables a driver for the stream co-processor
          for cryptographic operations.
 
-source drivers/mmc/Kconfig
-
 config ETRAX_MMC_IOP
        tristate "MMC/SD host driver using IO-processor"
        depends on ETRAX_ARCH_V32 && MMC
@@ -833,9 +831,4 @@ config ETRAX_SPI_MMC_WP_GPIO_PIN
          The pin to use for the SD/MMC write-protect signal for a memory
          card.  If defined as " " (space), the card is considered writable.
 
-# Avoid choices causing non-working configs by conditionalizing the inclusion.
-if ETRAX_SPI_MMC
-source drivers/spi/Kconfig
-endif
-
 endif
index be85f6de25d36dcfac1242ad926d16764fe02d78..03d9cfd92c8ab3d2acdb1737712929f58731a58b 100644 (file)
@@ -17,7 +17,7 @@ static inline unsigned long cris_swapnwbrlz(unsigned long w)
           in another register:
           !  __asm__ ("swapnwbr %2\n\tlz %2,%0"
           !          : "=r,r" (res), "=r,X" (dummy) : "1,0" (w));
-          confuses gcc (sched.c, gcc from cris-dist-1.14).  */
+          confuses gcc (core.c, gcc from cris-dist-1.14).  */
 
        unsigned long res;
        __asm__ ("swapnwbr %0 \n\t"
index f1e79edc9dd2258edcbcb08f616719e60217527b..c8325455520ef932fcbbb4ce44834d3618568a4e 100644 (file)
@@ -5,5 +5,9 @@ header-y += arch-v32/
 
 generic-y += clkdev.h
 generic-y += exec.h
+generic-y += kvm_para.h
+generic-y += linkage.h
 generic-y += module.h
 generic-y += trace_clock.h
+generic-y += vga.h
+generic-y += xor.h
index ac12ae2b92863ad3388457c7dffbfb10191b3a8f..5d3047e5563be8e09a583ba77882014bd4d0f578 100644 (file)
@@ -167,6 +167,9 @@ static inline void outsl(unsigned int port, const void *addr,
                cris_iops->write_io(port, (void *)addr, 4, count);
 }
 
+#define inb_p(port)             inb(port)
+#define outb_p(val, port)       outb((val), (port))
+
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
  * access
diff --git a/arch/cris/include/asm/linkage.h b/arch/cris/include/asm/linkage.h
deleted file mode 100644 (file)
index 291c2d0..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_LINKAGE_H
-#define __ASM_LINKAGE_H
-
-/* Nothing to see here... */
-
-#endif
index be45ee366be922f43dd0a4b6e4e1f8dcc9aa3d25..dfc53f9b88ec60d49a262f965329882142af43c3 100644 (file)
@@ -51,7 +51,6 @@ typedef struct page *pgtable_t;
  */ 
 
 #define virt_to_page(kaddr)    (mem_map + (((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT))
-#define VALID_PAGE(page)       (((page) - mem_map) < max_mapnr)
 #define virt_addr_valid(kaddr) pfn_valid((unsigned)(kaddr) >> PAGE_SHIFT)
 
 /* convert a page (based on mem_map and forward) to a physical address
index 9ac80946dada87401fb4a817fb5ed58313841ce8..c81af5bd916792791ea05baf006270cf459fb26a 100644 (file)
@@ -19,9 +19,6 @@ unsigned long empty_zero_page;
 void __init
 mem_init(void)
 {
-       int codesize, reservedpages, datasize, initsize;
-       unsigned long tmp;
-
        BUG_ON(!mem_map);
 
        /* max/min_low_pfn was set by setup.c
@@ -29,35 +26,9 @@ mem_init(void)
         *
         * high_memory was also set in setup.c
         */
-
-       max_mapnr = num_physpages = max_low_pfn - min_low_pfn;
-       /* this will put all memory onto the freelists */
-        totalram_pages = free_all_bootmem();
-
-       reservedpages = 0;
-       for (tmp = 0; tmp < max_mapnr; tmp++) {
-               /*
-                 * Only count reserved RAM pages
-                 */
-               if (PageReserved(mem_map + tmp))
-                       reservedpages++;
-       }
-
-       codesize =  (unsigned long) &_etext - (unsigned long) &_stext;
-        datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
-        initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
-       
-        printk(KERN_INFO
-               "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, "
-              "%dk init)\n" ,
-              nr_free_pages() << (PAGE_SHIFT-10),
-              max_mapnr << (PAGE_SHIFT-10),
-              codesize >> 10,
-              reservedpages << (PAGE_SHIFT-10),
-              datasize >> 10,
-              initsize >> 10
-               );
+       max_mapnr = max_low_pfn - min_low_pfn;
+        free_all_bootmem();
+       mem_init_print_info(NULL);
 }
 
 /* free the pages occupied by initialization code */
@@ -65,5 +36,5 @@ mem_init(void)
 void 
 free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
index 0b67ec5b44141ff5216184380355554197ba2107..3ac9a59d65d4129142d06ba9516455e0c5dc96db 100644 (file)
@@ -280,14 +280,14 @@ extern long __memcpy_user(void *dst, const void *src, unsigned long count);
 static inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        return __copy_to_user_inatomic(to, from, n);
 }
 
 static inline unsigned long
 __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        return __copy_from_user_inatomic(to, from, n);
 }
 
index e9a8cc63ac9413a0233f6f55ec0d91693ee3cf57..a7d0bea9c03619840686186e9468a693c00f12bb 100644 (file)
@@ -479,11 +479,6 @@ __head_mmu_enabled:
 
        LEDS            0x000c
 
-       # initialise the processor and the peripherals
-       #call           SYMBOL_NAME(processor_init)
-       #call           SYMBOL_NAME(unit_init)
-       #LEDS           0x0aff
-
        sethi.p         #0xe5e5,gr3
        setlo           #0xe5e5,gr3
        or.p            gr3,gr0,gr4
index a5136474c6fd6f95628362e8e144d82f8799c773..ae3a6706419bcf5b6ada7f12c95e3b68dbdbd3d0 100644 (file)
@@ -735,7 +735,7 @@ static void __init parse_cmdline_early(char *cmdline)
                /* "mem=XXX[kKmM]" sets SDRAM size to <mem>, overriding the value we worked
                 * out from the SDRAM controller mask register
                 */
-               if (!memcmp(cmdline, "mem=", 4)) {
+               if (!strncmp(cmdline, "mem=", 4)) {
                        unsigned long long mem_size;
 
                        mem_size = memparse(cmdline + 4, &cmdline);
@@ -876,6 +876,7 @@ late_initcall(setup_arch_serial);
 static void __init setup_linux_memory(void)
 {
        unsigned long bootmap_size, low_top_pfn, kstart, kend, high_mem;
+       unsigned long physpages;
 
        kstart  = (unsigned long) &__kernel_image_start - PAGE_OFFSET;
        kend    = (unsigned long) &__kernel_image_end - PAGE_OFFSET;
@@ -893,19 +894,19 @@ static void __init setup_linux_memory(void)
                                         );
 
        /* pass the memory that the kernel can immediately use over to the bootmem allocator */
-       max_mapnr = num_physpages = (memory_end - memory_start) >> PAGE_SHIFT;
+       max_mapnr = physpages = (memory_end - memory_start) >> PAGE_SHIFT;
        low_top_pfn = (KERNEL_LOWMEM_END - KERNEL_LOWMEM_START) >> PAGE_SHIFT;
        high_mem = 0;
 
-       if (num_physpages > low_top_pfn) {
+       if (physpages > low_top_pfn) {
 #ifdef CONFIG_HIGHMEM
-               high_mem = num_physpages - low_top_pfn;
+               high_mem = physpages - low_top_pfn;
 #else
-               max_mapnr = num_physpages = low_top_pfn;
+               max_mapnr = physpages = low_top_pfn;
 #endif
        }
        else {
-               low_top_pfn = num_physpages;
+               low_top_pfn = physpages;
        }
 
        min_low_pfn = memory_start >> PAGE_SHIFT;
@@ -979,7 +980,7 @@ static void __init setup_uclinux_memory(void)
        free_bootmem(memory_start, memory_end - memory_start);
 
        high_memory = (void *) (memory_end & PAGE_MASK);
-       max_mapnr = num_physpages = ((unsigned long) high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
+       max_mapnr = ((unsigned long) high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
 
        min_low_pfn = memory_start >> PAGE_SHIFT;
        max_low_pfn = memory_end >> PAGE_SHIFT;
index 4bff48c19d29733e90d75cbad1d631f3cadc3aaf..a6d105d61b268d09dea36de65e367abde64994c8 100644 (file)
@@ -523,7 +523,7 @@ void die_if_kernel(const char *str, ...)
                return;
 
        va_start(va, str);
-       vsprintf(buffer, str, va);
+       vsnprintf(buffer, sizeof(buffer), str, va);
        va_end(va);
 
        console_verbose();
index dee354fa6b64f93ae7c0e0842fe82b4a304ef1fc..88a15974352857dda020f5aa2c95b452f90b42c2 100644 (file)
@@ -78,7 +78,7 @@ void __init paging_init(void)
        memset((void *) empty_zero_page, 0, PAGE_SIZE);
 
 #ifdef CONFIG_HIGHMEM
-       if (num_physpages - num_mappedpages) {
+       if (get_num_physpages() - num_mappedpages) {
                pgd_t *pge;
                pud_t *pue;
                pmd_t *pme;
@@ -96,7 +96,7 @@ void __init paging_init(void)
         */
        zones_size[ZONE_NORMAL]  = max_low_pfn - min_low_pfn;
 #ifdef CONFIG_HIGHMEM
-       zones_size[ZONE_HIGHMEM] = num_physpages - num_mappedpages;
+       zones_size[ZONE_HIGHMEM] = get_num_physpages() - num_mappedpages;
 #endif
 
        free_area_init(zones_size);
@@ -114,45 +114,24 @@ void __init paging_init(void)
  */
 void __init mem_init(void)
 {
-       unsigned long npages = (memory_end - memory_start) >> PAGE_SHIFT;
-       unsigned long tmp;
-#ifdef CONFIG_MMU
-       unsigned long loop, pfn;
-       int datapages = 0;
-#endif
-       int codek = 0, datak = 0;
+       unsigned long code_size = _etext - _stext;
 
        /* this will put all low memory onto the freelists */
-       totalram_pages = free_all_bootmem();
-
-#ifdef CONFIG_MMU
-       for (loop = 0 ; loop < npages ; loop++)
-               if (PageReserved(&mem_map[loop]))
-                       datapages++;
-
-#ifdef CONFIG_HIGHMEM
-       for (pfn = num_physpages - 1; pfn >= num_mappedpages; pfn--)
-               free_highmem_page(&mem_map[pfn]);
-#endif
-
-       codek = ((unsigned long) &_etext - (unsigned long) &_stext) >> 10;
-       datak = datapages << (PAGE_SHIFT - 10);
-
-#else
-       codek = (_etext - _stext) >> 10;
-       datak = 0; //(__bss_stop - _sdata) >> 10;
+       free_all_bootmem();
+#if defined(CONFIG_MMU) && defined(CONFIG_HIGHMEM)
+       {
+               unsigned long pfn;
+
+               for (pfn = get_num_physpages() - 1;
+                    pfn >= num_mappedpages; pfn--)
+                       free_highmem_page(&mem_map[pfn]);
+       }
 #endif
 
-       tmp = nr_free_pages() << PAGE_SHIFT;
-       printk("Memory available: %luKiB/%luKiB RAM, %luKiB/%luKiB ROM (%dKiB kernel code, %dKiB data)\n",
-              tmp >> 10,
-              npages << (PAGE_SHIFT - 10),
-              (rom_length > 0) ? ((rom_length >> 10) - codek) : 0,
-              rom_length >> 10,
-              codek,
-              datak
-              );
-
+       mem_init_print_info(NULL);
+       if (rom_length > 0 && rom_length >= code_size)
+               printk("Memory available:  %luKiB/%luKiB ROM\n",
+                       (rom_length - code_size) >> 10, rom_length >> 10);
 } /* end mem_init() */
 
 /*****************************************************************************/
@@ -162,7 +141,7 @@ void __init mem_init(void)
 void free_initmem(void)
 {
 #if defined(CONFIG_RAMKERNEL) && !defined(CONFIG_PROTECT_KERNEL)
-       free_initmem_default(0);
+       free_initmem_default(-1);
 #endif
 } /* end free_initmem() */
 
@@ -173,6 +152,6 @@ void free_initmem(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 } /* end free_initrd_mem() */
 #endif
index 303e4f9a79d19998452760a913828a64c5773345..3d6759ee382f2721e29fd5a44f9c06e937fd7e3b 100644 (file)
@@ -94,126 +94,10 @@ endmenu
 
 source "net/Kconfig"
 
-source "drivers/base/Kconfig"
-
-source "drivers/mtd/Kconfig"
-
-source "drivers/block/Kconfig"
-
-source "drivers/ide/Kconfig"
+source "drivers/Kconfig"
 
 source "arch/h8300/Kconfig.ide"
 
-source "drivers/net/Kconfig"
-
-#
-# input - input/joystick depends on it. As does USB.
-#
-source "drivers/input/Kconfig"
-
-menu "Character devices"
-
-config VT
-       bool "Virtual terminal"
-       ---help---
-         If you say Y here, you will get support for terminal devices with
-         display and keyboard devices. These are called "virtual" because you
-         can run several virtual terminals (also called virtual consoles) on
-         one physical terminal. This is rather useful, for example one
-         virtual terminal can collect system messages and warnings, another
-         one can be used for a text-mode user session, and a third could run
-         an X session, all in parallel. Switching between virtual terminals
-         is done with certain key combinations, usually Alt-<function key>.
-
-         The setterm command ("man setterm") can be used to change the
-         properties (such as colors or beeping) of a virtual terminal. The
-         man page console_codes(4) ("man console_codes") contains the special
-         character sequences that can be used to change those properties
-         directly. The fonts used on virtual terminals can be changed with
-         the setfont ("man setfont") command and the key bindings are defined
-         with the loadkeys ("man loadkeys") command.
-
-         You need at least one virtual terminal device in order to make use
-         of your keyboard and monitor. Therefore, only people configuring an
-         embedded system would want to say N here in order to save some
-         memory; the only way to log into such a system is then via a serial
-         or network connection.
-
-         If unsure, say Y, or else you won't be able to do much with your new
-         shiny Linux system :-)
-
-config VT_CONSOLE
-       bool "Support for console on virtual terminal"
-       depends on VT
-       ---help---
-         The system console is the device which receives all kernel messages
-         and warnings and which allows logins in single user mode. If you
-         answer Y here, a virtual terminal (the device used to interact with
-         a physical terminal) can be used as system console. This is the most
-         common mode of operations, so you should say Y here unless you want
-         the kernel messages be output only to a serial port (in which case
-         you should say Y to "Console on serial port", below).
-
-         If you do say Y here, by default the currently visible virtual
-         terminal (/dev/tty0) will be used as system console. You can change
-         that with a kernel command line option such as "console=tty3" which
-         would use the third virtual terminal as system console. (Try "man
-         bootparam" or see the documentation of your boot loader (lilo or
-         loadlin) about how to pass options to the kernel at boot time.)
-
-         If unsure, say Y.
-
-config HW_CONSOLE
-       bool
-       depends on VT
-       default y
-
-comment "Unix98 PTY support"
-
-config UNIX98_PTYS
-       bool "Unix98 PTY support"
-       ---help---
-         A pseudo terminal (PTY) is a software device consisting of two
-         halves: a master and a slave. The slave device behaves identical to
-         a physical terminal; the master device is used by a process to
-         read data from and write data to the slave, thereby emulating a
-         terminal. Typical programs for the master side are telnet servers
-         and xterms.
-
-         Linux has traditionally used the BSD-like names /dev/ptyxx for
-         masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
-         has a number of problems. The GNU C library glibc 2.1 and later,
-         however, supports the Unix98 naming standard: in order to acquire a
-         pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
-         terminal is then made available to the process and the pseudo
-         terminal slave can be accessed as /dev/pts/<number>. What was
-         traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
-         The entries in /dev/pts/ are created on the fly by a virtual
-         file system; therefore, if you say Y here you should say Y to
-         "/dev/pts file system for Unix98 PTYs" as well.
-
-         If you want to say Y here, you need to have the C library glibc 2.1
-         or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
-         Read the instructions in <file:Documentation/Changes> pertaining to
-         pseudo terminals. It's safe to say N.
-
-source "drivers/char/pcmcia/Kconfig"
-
-source "drivers/tty/serial/Kconfig"
-
-source "drivers/i2c/Kconfig"
-
-source "drivers/hwmon/Kconfig"
-
-source "drivers/usb/Kconfig"
-
-source "drivers/uwb/Kconfig"
-
-endmenu
-
-source "drivers/staging/Kconfig"
-
 source "fs/Kconfig"
 
 source "arch/h8300/Kconfig.debug"
index 321f3922728b97b035bb44bd27a9d9756bbaba64..cdee771460ed29b6f6a51ccea242c10cc59b9a34 100644 (file)
@@ -64,6 +64,7 @@ choice
 
 config H83002
        bool "H8/3001,3002,3003"
+       depends on BROKEN
        select CPU_H8300H
 
 config H83007
@@ -72,6 +73,7 @@ config H83007
 
 config H83048
        bool "H8/3044,3045,3046,3047,3048,3052"
+       depends on BROKEN
        select CPU_H8300H
 
 config H83068
@@ -155,10 +157,12 @@ config H8300_TIMER16_CH
 config H8300_ITU_CH
        int "ITU channel"
        depends on H8300_ITU
+       range 0 4
 
 config H8300_TPU_CH
        int "TPU channel"
        depends on H8300_TPU
+       range 0 4
 
 source "kernel/Kconfig.preempt"
 
index 6745cb1ffb4f71340f50a3710f9f8ec9bc2c840e..a6c98fe3bbc3a42affff8d7d5a67462c7cbb2e76 100644 (file)
@@ -16,7 +16,7 @@ OBJECTS = $(obj)/head.o $(obj)/misc.o
 #
 CONFIG_MEMORY_START     ?= 0x00400000
 CONFIG_BOOT_LINK_OFFSET ?= 0x00140000
-IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)])
+IMAGE_OFFSET := $(shell printf "0x%08x" $$(($(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET))))
 
 LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -estartup $(obj)/vmlinux.lds
 
index 51ab6cbd030f58a9c439e9bc65849fd460d7b749..4a1e3dd43948df3d1a30fdf8db703a6abd825618 100644 (file)
@@ -79,7 +79,6 @@ static void error(char *m);
 
 int puts(const char *);
 
-extern int _text;              /* Defined in vmlinux.lds.S */
 extern int _end;
 static unsigned long free_mem_ptr;
 static unsigned long free_mem_end_ptr;
index 995eb47e01bb5c17866f10e8e24aecf4aedacd9c..8ada3cf0c98d8026da5358649facacad1542c80a 100644 (file)
@@ -1,6 +1,8 @@
 
 generic-y += clkdev.h
 generic-y += exec.h
+generic-y += linkage.h
 generic-y += mmu.h
 generic-y += module.h
 generic-y += trace_clock.h
+generic-y += xor.h
index c7283c343c55387448cb581855a355b1d4806325..9e0aa9fc195dc70c4d1cf9a418cdf8e395e42061 100644 (file)
@@ -12,6 +12,8 @@
 #define wmb()  asm volatile (""   : : :"memory")
 #define set_mb(var, value) do { xchg(&var, value); } while (0)
 
+#define read_barrier_depends() do { } while (0)
+
 #ifdef CONFIG_SMP
 #define smp_mb()       mb()
 #define smp_rmb()      rmb()
diff --git a/arch/h8300/include/asm/linkage.h b/arch/h8300/include/asm/linkage.h
deleted file mode 100644 (file)
index 1d81604..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _H8300_LINKAGE_H
-#define _H8300_LINKAGE_H
-
-#undef SYMBOL_NAME_LABEL
-#define SYMBOL_NAME_LABEL(_name_) _##_name_##:
-#endif
index 3dea80ad9e6f85596bd66f1303dd9ff0929b44bb..7f0743051ad5179b25f230647b6157c13f99f5dd 100644 (file)
@@ -1,16 +1,3 @@
-/* 
-  include/asm-h8300/tlb.h 
-*/
-
-#ifndef __H8300_TLB_H__
-#define __H8300_TLB_H__
-
-#define tlb_flush(tlb) do { } while(0)
-
-/* 
-  include/asm-h8300/tlb.h 
-*/
-
 #ifndef __H8300_TLB_H__
 #define __H8300_TLB_H__
 
@@ -19,5 +6,3 @@
 #include <asm-generic/tlb.h>
 
 #endif
-
-#endif
index 617a6878787fa69571b91ebcb54d84cd6262c3c4..94bd30f11df631da604da7a217915dcfc9376f0e 100644 (file)
@@ -87,13 +87,13 @@ INTERRUPTS = 128
        bne     5f
 
        /* user mode */
-       mov.l   sp,@SYMBOL_NAME(sw_usp)
+       mov.l   sp,@_sw_usp
        mov.l   @sp,er0                         /* restore saved er0 */
        orc     #0x10,ccr                       /* switch kernel stack */
-       mov.l   @SYMBOL_NAME(sw_ksp),sp
+       mov.l   @_sw_ksp,sp
        sub.l   #(LRET-LORIG),sp                /* allocate LORIG - LRET */
        SAVEREGS
-       mov.l   @SYMBOL_NAME(sw_usp),er0
+       mov.l   @_sw_usp,er0
        mov.l   @(USERRET:16,er0),er1           /* copy the RET addr */
        mov.l   er1,@(LRET-LER3:16,sp)
        SAVEEXR
@@ -128,7 +128,7 @@ INTERRUPTS = 128
        bne     7f
 
        orc     #0x80,ccr
-       mov.l   @SYMBOL_NAME(sw_usp),er0
+       mov.l   @_sw_usp,er0
        mov.l   @(LER0-LER1:16,sp),er1          /* restore ER0 */
        mov.l   er1,@er0
        RESTOREEXR
@@ -141,7 +141,7 @@ INTERRUPTS = 128
 
        mov.l   @sp+,er1
        add.l   #(LRET-LER1),sp                 /* remove LORIG - LRET */
-       mov.l   sp,@SYMBOL_NAME(sw_ksp)
+       mov.l   sp,@_sw_ksp
        andc    #0xef,ccr                       /* switch to user mode */
        mov.l   er0,sp
        bra     8f
@@ -155,20 +155,20 @@ INTERRUPTS = 128
        rte
        .endm
 
-.globl SYMBOL_NAME(system_call)
-.globl SYMBOL_NAME(ret_from_exception)
-.globl SYMBOL_NAME(ret_from_fork)
-.globl SYMBOL_NAME(ret_from_kernel_thread)
-.globl SYMBOL_NAME(ret_from_interrupt)
-.globl SYMBOL_NAME(interrupt_redirect_table)
-.globl SYMBOL_NAME(sw_ksp),SYMBOL_NAME(sw_usp)
-.globl SYMBOL_NAME(resume)
-.globl SYMBOL_NAME(interrupt_entry)
-.globl SYMBOL_NAME(trace_break)
+.globl _system_call
+.globl _ret_from_exception
+.globl _ret_from_fork
+.globl _ret_from_kernel_thread
+.globl _ret_from_interrupt
+.globl _interrupt_redirect_table
+.globl _sw_ksp,_sw_usp
+.globl _resume
+.globl _interrupt_entry
+.globl _trace_break
 
 #if defined(CONFIG_ROMKERNEL)
        .section .int_redirect,"ax"
-SYMBOL_NAME_LABEL(interrupt_redirect_table)
+_interrupt_redirect_table:
 #if defined(CONFIG_CPU_H8300H)
        .rept   7
        .long   0
@@ -178,54 +178,54 @@ SYMBOL_NAME_LABEL(interrupt_redirect_table)
        .rept   5
        .long   0
        .endr
-       jmp     @SYMBOL_NAME(trace_break)
+       jmp     @_trace_break
        .long   0
 #endif
 
-       jsr     @SYMBOL_NAME(interrupt_entry)   /* NMI */
-       jmp     @SYMBOL_NAME(system_call)       /* TRAPA #0 (System call) */
+       jsr     @_interrupt_entry               /* NMI */
+       jmp     @_system_call                   /* TRAPA #0 (System call) */
        .long   0
        .long   0
-       jmp     @SYMBOL_NAME(trace_break)       /* TRAPA #3 (breakpoint) */
+       jmp     @_trace_break                   /* TRAPA #3 (breakpoint) */
        .rept   INTERRUPTS-12
-       jsr     @SYMBOL_NAME(interrupt_entry)
+       jsr     @_interrupt_entry
        .endr
 #endif
 #if defined(CONFIG_RAMKERNEL)
-.globl SYMBOL_NAME(interrupt_redirect_table)
+.globl _interrupt_redirect_table
        .section .bss
-SYMBOL_NAME_LABEL(interrupt_redirect_table)
+_interrupt_redirect_table:
        .space  4
 #endif
 
        .section .text
        .align  2
-SYMBOL_NAME_LABEL(interrupt_entry)
+_interrupt_entry:
        SAVE_ALL
        mov.l   sp,er0
        add.l   #LVEC,er0
        btst    #4,r1l
        bne     1f
        /* user LVEC */
-       mov.l   @SYMBOL_NAME(sw_usp),er0
+       mov.l   @_sw_usp,er0
        adds    #4,er0
 1:
        mov.l   @er0,er0                        /* LVEC address */
 #if defined(CONFIG_ROMKERNEL)
-       sub.l   #SYMBOL_NAME(interrupt_redirect_table),er0
+       sub.l   #_interrupt_redirect_table,er0
 #endif
 #if defined(CONFIG_RAMKERNEL)
-       mov.l   @SYMBOL_NAME(interrupt_redirect_table),er1
+       mov.l   @_interrupt_redirect_table,er1
        sub.l   er1,er0
 #endif
        SHLR2   er0
        dec.l   #1,er0
        mov.l   sp,er1
        subs    #4,er1                          /* adjust ret_pc */
-       jsr     @SYMBOL_NAME(do_IRQ)
-       jmp     @SYMBOL_NAME(ret_from_interrupt)
+       jsr     @_do_IRQ
+       jmp     @_ret_from_interrupt
 
-SYMBOL_NAME_LABEL(system_call)
+_system_call:
        subs    #4,sp                           /* dummy LVEC */
        SAVE_ALL
        andc    #0x7f,ccr
@@ -233,21 +233,21 @@ SYMBOL_NAME_LABEL(system_call)
 
        /* save top of frame */
        mov.l   sp,er0
-       jsr     @SYMBOL_NAME(set_esp0)
+       jsr     @_set_esp0
        mov.l   sp,er2
        and.w   #0xe000,r2
        mov.b   @((TI_FLAGS+3-(TIF_SYSCALL_TRACE >> 3)):16,er2),r2l
        btst    #(TIF_SYSCALL_TRACE & 7),r2l
        beq     1f
-       jsr     @SYMBOL_NAME(do_syscall_trace)
+       jsr     @_do_syscall_trace
 1:
        cmp.l   #NR_syscalls,er4
        bcc     badsys
        SHLL2   er4
-       mov.l   #SYMBOL_NAME(sys_call_table),er0
+       mov.l   #_sys_call_table,er0
        add.l   er4,er0
        mov.l   @er0,er4
-       beq     SYMBOL_NAME(ret_from_exception):16
+       beq     _ret_from_exception:16
        mov.l   @(LER1:16,sp),er0
        mov.l   @(LER2:16,sp),er1
        mov.l   @(LER3:16,sp),er2
@@ -258,10 +258,10 @@ SYMBOL_NAME_LABEL(system_call)
        mov.b   @((TI_FLAGS+3-(TIF_SYSCALL_TRACE >> 3)):16,er2),r2l
        btst    #(TIF_SYSCALL_TRACE & 7),r2l
        beq     2f
-       jsr     @SYMBOL_NAME(do_syscall_trace)
+       jsr     @_do_syscall_trace
 2:
 #if defined(CONFIG_SYSCALL_PRINT)
-       jsr     @SYMBOL_NAME(syscall_print)
+       jsr     @_syscall_print
 #endif
        orc     #0x80,ccr
        bra     resume_userspace
@@ -275,11 +275,11 @@ badsys:
 #define resume_kernel restore_all
 #endif
 
-SYMBOL_NAME_LABEL(ret_from_exception)
+_ret_from_exception:
 #if defined(CONFIG_PREEMPT)
        orc     #0x80,ccr
 #endif
-SYMBOL_NAME_LABEL(ret_from_interrupt)
+_ret_from_interrupt:
        mov.b   @(LCCR+1:16,sp),r0l
        btst    #4,r0l
        bne     resume_kernel:8         /* return from kernel */
@@ -296,12 +296,12 @@ work_pending:
        /* work notifysig */
        mov.l   sp,er0
        subs    #4,er0                  /* er0: pt_regs */
-       jsr     @SYMBOL_NAME(do_notify_resume)
+       jsr     @_do_notify_resume
        bra     restore_all:8
 work_resched:
        mov.l   sp,er0
-       jsr     @SYMBOL_NAME(set_esp0)
-       jsr     @SYMBOL_NAME(schedule)
+       jsr     @_set_esp0
+       jsr     @_schedule
        bra     resume_userspace:8
 restore_all:
        RESTORE_ALL                     /* Does RTE */
@@ -320,26 +320,26 @@ need_resched:
        mov.l   er0,@(TI_PRE_COUNT:16,er4)
        andc    #0x7f,ccr
        mov.l   sp,er0
-       jsr     @SYMBOL_NAME(set_esp0)
-       jsr     @SYMBOL_NAME(schedule)
+       jsr     @_set_esp0
+       jsr     @_schedule
        orc     #0x80,ccr
        bra     need_resched:8
 #endif
 
-SYMBOL_NAME_LABEL(ret_from_fork)
+_ret_from_fork:
        mov.l   er2,er0
-       jsr     @SYMBOL_NAME(schedule_tail)
-       jmp     @SYMBOL_NAME(ret_from_exception)
+       jsr     @_schedule_tail
+       jmp     @_ret_from_exception
 
-SYMBOL_NAME_LABEL(ret_from_kernel_thread)
+_ret_from_kernel_thread:
        mov.l   er2,er0
-       jsr     @SYMBOL_NAME(schedule_tail)
+       jsr     @_schedule_tail
        mov.l   @(LER4:16,sp),er0
        mov.l   @(LER5:16,sp),er1
        jsr     @er1
-       jmp     @SYMBOL_NAME(ret_from_exception)
+       jmp     @_ret_from_exception
 
-SYMBOL_NAME_LABEL(resume)
+_resume:
        /*
         * Beware - when entering resume, offset of tss is in d1,
         * prev (the current task) is in a0, next (the new task)
@@ -355,7 +355,7 @@ SYMBOL_NAME_LABEL(resume)
 
        /* disable interrupts */
        orc     #0x80,ccr
-       mov.l   @SYMBOL_NAME(sw_usp),er3
+       mov.l   @_sw_usp,er3
        mov.l   er3,@(THREAD_USP:16,er0)
        mov.l   sp,@(THREAD_KSP:16,er0)
 
@@ -363,7 +363,7 @@ SYMBOL_NAME_LABEL(resume)
        /* FIXME: what did we hack out of here, this does nothing! */
 
        mov.l   @(THREAD_USP:16,er1),er0
-       mov.l   er0,@SYMBOL_NAME(sw_usp)
+       mov.l   er0,@_sw_usp
        mov.l   @(THREAD_KSP:16,er1),sp
 
        /* restore status register */
@@ -372,15 +372,15 @@ SYMBOL_NAME_LABEL(resume)
        ldc     r3l,ccr
        rts
 
-SYMBOL_NAME_LABEL(trace_break)
+_trace_break:
        subs    #4,sp
        SAVE_ALL
        sub.l   er1,er1
        dec.l   #1,er1
        mov.l   er1,@(LORIG,sp)
        mov.l   sp,er0
-       jsr     @SYMBOL_NAME(set_esp0)
-       mov.l   @SYMBOL_NAME(sw_usp),er0
+       jsr     @_set_esp0
+       mov.l   @_sw_usp,er0
        mov.l   @er0,er1
        mov.w   @(-2:16,er1),r2
        cmp.w   #0x5730,r2
@@ -390,13 +390,13 @@ SYMBOL_NAME_LABEL(trace_break)
 1:
        and.w   #0xff,e1
        mov.l   er1,er0
-       jsr     @SYMBOL_NAME(trace_trap)
-       jmp     @SYMBOL_NAME(ret_from_exception)
+       jsr     @_trace_trap
+       jmp     @_ret_from_exception
 
        .section        .bss
-SYMBOL_NAME_LABEL(sw_ksp)
+_sw_ksp:
        .space  4
-SYMBOL_NAME_LABEL(sw_usp)
+_sw_usp:
        .space  4
 
        .end
index 5c2168fb9b9ef8317891905a2c8be3b1147cf166..c55e0ed270d5c85fde8020ab83af180b10e847d0 100644 (file)
@@ -2,8 +2,10 @@
 #include <linux/sys.h>
 #include <asm/linkage.h>
 #include <asm/unistd.h>
-       
-.globl SYMBOL_NAME(sys_call_table)
+
+#define CALL(x)        .long _ ## x
+
+.globl _sys_call_table
 
 #if defined(CONFIG_CPU_H8300H)
        .h8300h
 #endif
        .section .text
        .align  2
-SYMBOL_NAME_LABEL(sys_call_table)      
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 0  -  old "setup()" system call*/
-       .long SYMBOL_NAME(sys_exit)
-       .long SYMBOL_NAME(sys_fork)
-       .long SYMBOL_NAME(sys_read)
-       .long SYMBOL_NAME(sys_write)
-       .long SYMBOL_NAME(sys_open)             /* 5 */
-       .long SYMBOL_NAME(sys_close)
-       .long SYMBOL_NAME(sys_waitpid)
-       .long SYMBOL_NAME(sys_creat)
-       .long SYMBOL_NAME(sys_link)
-       .long SYMBOL_NAME(sys_unlink)           /* 10 */
-       .long SYMBOL_NAME(sys_execve)
-       .long SYMBOL_NAME(sys_chdir)
-       .long SYMBOL_NAME(sys_time)
-       .long SYMBOL_NAME(sys_mknod)
-       .long SYMBOL_NAME(sys_chmod)            /* 15 */
-       .long SYMBOL_NAME(sys_chown16)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* old break syscall holder */
-       .long SYMBOL_NAME(sys_stat)
-       .long SYMBOL_NAME(sys_lseek)
-       .long SYMBOL_NAME(sys_getpid)           /* 20 */
-       .long SYMBOL_NAME(sys_mount)
-       .long SYMBOL_NAME(sys_oldumount)
-       .long SYMBOL_NAME(sys_setuid16)
-       .long SYMBOL_NAME(sys_getuid16)
-       .long SYMBOL_NAME(sys_stime)            /* 25 */
-       .long SYMBOL_NAME(sys_ptrace)
-       .long SYMBOL_NAME(sys_alarm)
-       .long SYMBOL_NAME(sys_fstat)
-       .long SYMBOL_NAME(sys_pause)
-       .long SYMBOL_NAME(sys_utime)            /* 30 */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* old stty syscall holder */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* old gtty syscall holder */
-       .long SYMBOL_NAME(sys_access)
-       .long SYMBOL_NAME(sys_nice)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 35 old ftime syscall holder */
-       .long SYMBOL_NAME(sys_sync)
-       .long SYMBOL_NAME(sys_kill)
-       .long SYMBOL_NAME(sys_rename)
-       .long SYMBOL_NAME(sys_mkdir)
-       .long SYMBOL_NAME(sys_rmdir)            /* 40 */
-       .long SYMBOL_NAME(sys_dup)
-       .long SYMBOL_NAME(sys_pipe)
-       .long SYMBOL_NAME(sys_times)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* old prof syscall holder */
-       .long SYMBOL_NAME(sys_brk)              /* 45 */
-       .long SYMBOL_NAME(sys_setgid16)
-       .long SYMBOL_NAME(sys_getgid16)
-       .long SYMBOL_NAME(sys_signal)
-       .long SYMBOL_NAME(sys_geteuid16)
-       .long SYMBOL_NAME(sys_getegid16)        /* 50 */
-       .long SYMBOL_NAME(sys_acct)
-       .long SYMBOL_NAME(sys_umount)           /* recycled never used phys() */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* old lock syscall holder */
-       .long SYMBOL_NAME(sys_ioctl)
-       .long SYMBOL_NAME(sys_fcntl)            /* 55 */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* old mpx syscall holder */
-       .long SYMBOL_NAME(sys_setpgid)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* old ulimit syscall holder */
-       .long SYMBOL_NAME(sys_ni_syscall)
-       .long SYMBOL_NAME(sys_umask)            /* 60 */
-       .long SYMBOL_NAME(sys_chroot)
-       .long SYMBOL_NAME(sys_ustat)
-       .long SYMBOL_NAME(sys_dup2)
-       .long SYMBOL_NAME(sys_getppid)
-       .long SYMBOL_NAME(sys_getpgrp)          /* 65 */
-       .long SYMBOL_NAME(sys_setsid)
-       .long SYMBOL_NAME(sys_sigaction)
-       .long SYMBOL_NAME(sys_sgetmask)
-       .long SYMBOL_NAME(sys_ssetmask)
-       .long SYMBOL_NAME(sys_setreuid16)       /* 70 */
-       .long SYMBOL_NAME(sys_setregid16)
-       .long SYMBOL_NAME(sys_sigsuspend)
-       .long SYMBOL_NAME(sys_sigpending)
-       .long SYMBOL_NAME(sys_sethostname)
-       .long SYMBOL_NAME(sys_setrlimit)        /* 75 */
-       .long SYMBOL_NAME(sys_old_getrlimit)
-       .long SYMBOL_NAME(sys_getrusage)
-       .long SYMBOL_NAME(sys_gettimeofday)
-       .long SYMBOL_NAME(sys_settimeofday)
-       .long SYMBOL_NAME(sys_getgroups16)      /* 80 */
-       .long SYMBOL_NAME(sys_setgroups16)
-       .long SYMBOL_NAME(sys_old_select)
-       .long SYMBOL_NAME(sys_symlink)
-       .long SYMBOL_NAME(sys_lstat)
-       .long SYMBOL_NAME(sys_readlink)         /* 85 */
-       .long SYMBOL_NAME(sys_uselib)
-       .long SYMBOL_NAME(sys_swapon)
-       .long SYMBOL_NAME(sys_reboot)
-       .long SYMBOL_NAME(sys_old_readdir)
-       .long SYMBOL_NAME(sys_old_mmap)         /* 90 */
-       .long SYMBOL_NAME(sys_munmap)
-       .long SYMBOL_NAME(sys_truncate)
-       .long SYMBOL_NAME(sys_ftruncate)
-       .long SYMBOL_NAME(sys_fchmod)
-       .long SYMBOL_NAME(sys_fchown16)         /* 95 */
-       .long SYMBOL_NAME(sys_getpriority)
-       .long SYMBOL_NAME(sys_setpriority)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* old profil syscall holder */
-       .long SYMBOL_NAME(sys_statfs)
-       .long SYMBOL_NAME(sys_fstatfs)          /* 100 */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* ioperm for i386 */
-       .long SYMBOL_NAME(sys_socketcall)
-       .long SYMBOL_NAME(sys_syslog)
-       .long SYMBOL_NAME(sys_setitimer)
-       .long SYMBOL_NAME(sys_getitimer)        /* 105 */
-       .long SYMBOL_NAME(sys_newstat)
-       .long SYMBOL_NAME(sys_newlstat)
-       .long SYMBOL_NAME(sys_newfstat)
-       .long SYMBOL_NAME(sys_ni_syscall)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* iopl for i386 */ /* 110 */
-       .long SYMBOL_NAME(sys_vhangup)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* obsolete idle() syscall */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* vm86old for i386 */
-       .long SYMBOL_NAME(sys_wait4)
-       .long SYMBOL_NAME(sys_swapoff)          /* 115 */
-       .long SYMBOL_NAME(sys_sysinfo)
-       .long SYMBOL_NAME(sys_ipc)
-       .long SYMBOL_NAME(sys_fsync)
-       .long SYMBOL_NAME(sys_sigreturn)
-       .long SYMBOL_NAME(sys_clone)            /* 120 */
-       .long SYMBOL_NAME(sys_setdomainname)
-       .long SYMBOL_NAME(sys_newuname)
-       .long SYMBOL_NAME(sys_cacheflush)       /* modify_ldt for i386 */
-       .long SYMBOL_NAME(sys_adjtimex)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 125 sys_mprotect */
-       .long SYMBOL_NAME(sys_sigprocmask)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_create_module */
-       .long SYMBOL_NAME(sys_init_module)
-       .long SYMBOL_NAME(sys_delete_module)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 130 sys_get_kernel_syms */
-       .long SYMBOL_NAME(sys_quotactl)
-       .long SYMBOL_NAME(sys_getpgid)
-       .long SYMBOL_NAME(sys_fchdir)
-       .long SYMBOL_NAME(sys_bdflush)
-       .long SYMBOL_NAME(sys_sysfs)            /* 135 */
-       .long SYMBOL_NAME(sys_personality)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* for afs_syscall */
-       .long SYMBOL_NAME(sys_setfsuid16)
-       .long SYMBOL_NAME(sys_setfsgid16)
-       .long SYMBOL_NAME(sys_llseek)           /* 140 */
-       .long SYMBOL_NAME(sys_getdents)
-       .long SYMBOL_NAME(sys_select)
-       .long SYMBOL_NAME(sys_flock)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_msync */
-       .long SYMBOL_NAME(sys_readv)            /* 145 */
-       .long SYMBOL_NAME(sys_writev)
-       .long SYMBOL_NAME(sys_getsid)
-       .long SYMBOL_NAME(sys_fdatasync)
-       .long SYMBOL_NAME(sys_sysctl)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 150 sys_mlock */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_munlock */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_mlockall */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_munlockall */
-       .long SYMBOL_NAME(sys_sched_setparam)
-       .long SYMBOL_NAME(sys_sched_getparam)   /* 155 */
-       .long SYMBOL_NAME(sys_sched_setscheduler)
-       .long SYMBOL_NAME(sys_sched_getscheduler)
-       .long SYMBOL_NAME(sys_sched_yield)
-       .long SYMBOL_NAME(sys_sched_get_priority_max)
-       .long SYMBOL_NAME(sys_sched_get_priority_min)  /* 160 */
-       .long SYMBOL_NAME(sys_sched_rr_get_interval)
-       .long SYMBOL_NAME(sys_nanosleep)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_mremap */
-       .long SYMBOL_NAME(sys_setresuid16)
-       .long SYMBOL_NAME(sys_getresuid16)      /* 165 */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* for vm86 */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_query_module */
-       .long SYMBOL_NAME(sys_poll)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* old nfsservctl */
-       .long SYMBOL_NAME(sys_setresgid16)      /* 170 */
-       .long SYMBOL_NAME(sys_getresgid16)
-       .long SYMBOL_NAME(sys_prctl)
-       .long SYMBOL_NAME(sys_rt_sigreturn)
-       .long SYMBOL_NAME(sys_rt_sigaction)
-       .long SYMBOL_NAME(sys_rt_sigprocmask)   /* 175 */
-       .long SYMBOL_NAME(sys_rt_sigpending)
-       .long SYMBOL_NAME(sys_rt_sigtimedwait)
-       .long SYMBOL_NAME(sys_rt_sigqueueinfo)
-       .long SYMBOL_NAME(sys_rt_sigsuspend)
-       .long SYMBOL_NAME(sys_pread64)          /* 180 */
-       .long SYMBOL_NAME(sys_pwrite64)
-       .long SYMBOL_NAME(sys_lchown16);
-       .long SYMBOL_NAME(sys_getcwd)
-       .long SYMBOL_NAME(sys_capget)
-       .long SYMBOL_NAME(sys_capset)           /* 185 */
-       .long SYMBOL_NAME(sys_sigaltstack)
-       .long SYMBOL_NAME(sys_sendfile)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* streams1 */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* streams2 */
-       .long SYMBOL_NAME(sys_vfork)            /* 190 */
-       .long SYMBOL_NAME(sys_getrlimit)
-       .long SYMBOL_NAME(sys_mmap_pgoff)
-       .long SYMBOL_NAME(sys_truncate64)
-       .long SYMBOL_NAME(sys_ftruncate64)
-       .long SYMBOL_NAME(sys_stat64)           /* 195 */
-       .long SYMBOL_NAME(sys_lstat64)
-       .long SYMBOL_NAME(sys_fstat64)
-       .long SYMBOL_NAME(sys_chown)
-       .long SYMBOL_NAME(sys_getuid)
-       .long SYMBOL_NAME(sys_getgid)           /* 200 */
-       .long SYMBOL_NAME(sys_geteuid)
-       .long SYMBOL_NAME(sys_getegid)
-       .long SYMBOL_NAME(sys_setreuid)
-       .long SYMBOL_NAME(sys_setregid)
-       .long SYMBOL_NAME(sys_getgroups)        /* 205 */
-       .long SYMBOL_NAME(sys_setgroups)
-       .long SYMBOL_NAME(sys_fchown)
-       .long SYMBOL_NAME(sys_setresuid)
-       .long SYMBOL_NAME(sys_getresuid)
-       .long SYMBOL_NAME(sys_setresgid)        /* 210 */
-       .long SYMBOL_NAME(sys_getresgid)
-       .long SYMBOL_NAME(sys_lchown)
-       .long SYMBOL_NAME(sys_setuid)
-       .long SYMBOL_NAME(sys_setgid)
-       .long SYMBOL_NAME(sys_setfsuid)         /* 215 */
-       .long SYMBOL_NAME(sys_setfsgid)
-       .long SYMBOL_NAME(sys_pivot_root)
-       .long SYMBOL_NAME(sys_ni_syscall)
-       .long SYMBOL_NAME(sys_ni_syscall)
-       .long SYMBOL_NAME(sys_getdents64)       /* 220 */
-       .long SYMBOL_NAME(sys_fcntl64)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved TUX */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved Security */
-       .long SYMBOL_NAME(sys_gettid)
-       .long SYMBOL_NAME(sys_readahead)        /* 225 */
-       .long SYMBOL_NAME(sys_setxattr)
-       .long SYMBOL_NAME(sys_lsetxattr)
-       .long SYMBOL_NAME(sys_fsetxattr)
-       .long SYMBOL_NAME(sys_getxattr)
-       .long SYMBOL_NAME(sys_lgetxattr)        /* 230 */
-       .long SYMBOL_NAME(sys_fgetxattr)
-       .long SYMBOL_NAME(sys_listxattr)
-       .long SYMBOL_NAME(sys_llistxattr)
-       .long SYMBOL_NAME(sys_flistxattr)
-       .long SYMBOL_NAME(sys_removexattr)      /* 235 */
-       .long SYMBOL_NAME(sys_lremovexattr)
-       .long SYMBOL_NAME(sys_fremovexattr)
-       .long SYMBOL_NAME(sys_tkill)
-       .long SYMBOL_NAME(sys_sendfile64)
-       .long SYMBOL_NAME(sys_futex)            /* 240 */
-       .long SYMBOL_NAME(sys_sched_setaffinity)
-       .long SYMBOL_NAME(sys_sched_getaffinity)
-       .long SYMBOL_NAME(sys_ni_syscall)
-       .long SYMBOL_NAME(sys_ni_syscall)
-       .long SYMBOL_NAME(sys_io_setup)         /* 245 */
-       .long SYMBOL_NAME(sys_io_destroy)
-       .long SYMBOL_NAME(sys_io_getevents)
-       .long SYMBOL_NAME(sys_io_submit)
-       .long SYMBOL_NAME(sys_io_cancel)
-       .long SYMBOL_NAME(sys_fadvise64)        /* 250 */
-       .long SYMBOL_NAME(sys_ni_syscall)
-       .long SYMBOL_NAME(sys_exit_group)
-       .long SYMBOL_NAME(sys_lookup_dcookie)
-       .long SYMBOL_NAME(sys_epoll_create)
-       .long SYMBOL_NAME(sys_epoll_ctl)        /* 255 */
-       .long SYMBOL_NAME(sys_epoll_wait)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_remap_file_pages */
-       .long SYMBOL_NAME(sys_set_tid_address)
-       .long SYMBOL_NAME(sys_timer_create)
-       .long SYMBOL_NAME(sys_timer_settime)    /* 260 */
-       .long SYMBOL_NAME(sys_timer_gettime)
-       .long SYMBOL_NAME(sys_timer_getoverrun)
-       .long SYMBOL_NAME(sys_timer_delete)
-       .long SYMBOL_NAME(sys_clock_settime)
-       .long SYMBOL_NAME(sys_clock_gettime)    /* 265 */
-       .long SYMBOL_NAME(sys_clock_getres)
-       .long SYMBOL_NAME(sys_clock_nanosleep)
-       .long SYMBOL_NAME(sys_statfs64)
-       .long SYMBOL_NAME(sys_fstatfs64)        
-       .long SYMBOL_NAME(sys_tgkill)           /* 270 */
-       .long SYMBOL_NAME(sys_utimes)
-       .long SYMBOL_NAME(sys_fadvise64_64)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_vserver */
-       .long SYMBOL_NAME(sys_ni_syscall)
-       .long SYMBOL_NAME(sys_get_mempolicy)    /* 275 */
-       .long SYMBOL_NAME(sys_set_mempolicy)
-       .long SYMBOL_NAME(sys_mq_open)
-       .long SYMBOL_NAME(sys_mq_unlink)
-       .long SYMBOL_NAME(sys_mq_timedsend)
-       .long SYMBOL_NAME(sys_mq_timedreceive)  /* 280 */
-       .long SYMBOL_NAME(sys_mq_notify)
-       .long SYMBOL_NAME(sys_mq_getsetattr)
-       .long SYMBOL_NAME(sys_waitid)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_kexec_load */
-       .long SYMBOL_NAME(sys_add_key)          /* 285 */
-       .long SYMBOL_NAME(sys_request_key)
-       .long SYMBOL_NAME(sys_keyctl)
-       .long SYMBOL_NAME(sys_ioprio_set)
-       .long SYMBOL_NAME(sys_ioprio_get)       /* 290 */
-       .long SYMBOL_NAME(sys_inotify_init)
-       .long SYMBOL_NAME(sys_inotify_add_watch)
-       .long SYMBOL_NAME(sys_inotify_rm_watch)
-       .long SYMBOL_NAME(sys_migrate_pages)
-       .long SYMBOL_NAME(sys_openat)           /* 295 */
-       .long SYMBOL_NAME(sys_mkdirat)
-       .long SYMBOL_NAME(sys_mknodat)
-       .long SYMBOL_NAME(sys_fchownat)
-       .long SYMBOL_NAME(sys_futimesat)
-       .long SYMBOL_NAME(sys_fstatat64)        /* 300 */
-       .long SYMBOL_NAME(sys_unlinkat)
-       .long SYMBOL_NAME(sys_renameat)
-       .long SYMBOL_NAME(sys_linkat)
-       .long SYMBOL_NAME(sys_symlinkat)
-       .long SYMBOL_NAME(sys_readlinkat)       /* 305 */
-       .long SYMBOL_NAME(sys_fchmodat)
-       .long SYMBOL_NAME(sys_faccessat)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_pselect6 */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_ppoll */
-       .long SYMBOL_NAME(sys_unshare)          /* 310 */
-       .long SYMBOL_NAME(sys_set_robust_list)
-       .long SYMBOL_NAME(sys_get_robust_list)
-       .long SYMBOL_NAME(sys_splice)
-       .long SYMBOL_NAME(sys_sync_file_range)
-       .long SYMBOL_NAME(sys_tee)              /* 315 */
-       .long SYMBOL_NAME(sys_vmsplice)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_move_pages */
-       .long SYMBOL_NAME(sys_getcpu)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_epoll_pwait */
-       .long SYMBOL_NAME(sys_setns)            /* 320 */
+_sys_call_table:
+       CALL(sys_ni_syscall)            /* 0  -  old "setup()" system call*/
+       CALL(sys_exit)
+       CALL(sys_fork)
+       CALL(sys_read)
+       CALL(sys_write)
+       CALL(sys_open)                  /* 5 */
+       CALL(sys_close)
+       CALL(sys_waitpid)
+       CALL(sys_creat)
+       CALL(sys_link)
+       CALL(sys_unlink)                /* 10 */
+       CALL(sys_execve)
+       CALL(sys_chdir)
+       CALL(sys_time)
+       CALL(sys_mknod)
+       CALL(sys_chmod)                 /* 15 */
+       CALL(sys_chown16)
+       CALL(sys_ni_syscall)            /* old break syscall holder */
+       CALL(sys_stat)
+       CALL(sys_lseek)
+       CALL(sys_getpid)                /* 20 */
+       CALL(sys_mount)
+       CALL(sys_oldumount)
+       CALL(sys_setuid16)
+       CALL(sys_getuid16)
+       CALL(sys_stime)                 /* 25 */
+       CALL(sys_ptrace)
+       CALL(sys_alarm)
+       CALL(sys_fstat)
+       CALL(sys_pause)
+       CALL(sys_utime)                 /* 30 */
+       CALL(sys_ni_syscall)            /* old stty syscall holder */
+       CALL(sys_ni_syscall)            /* old gtty syscall holder */
+       CALL(sys_access)
+       CALL(sys_nice)
+       CALL(sys_ni_syscall)            /* 35 old ftime syscall holder */
+       CALL(sys_sync)
+       CALL(sys_kill)
+       CALL(sys_rename)
+       CALL(sys_mkdir)
+       CALL(sys_rmdir)                 /* 40 */
+       CALL(sys_dup)
+       CALL(sys_pipe)
+       CALL(sys_times)
+       CALL(sys_ni_syscall)            /* old prof syscall holder */
+       CALL(sys_brk)                   /* 45 */
+       CALL(sys_setgid16)
+       CALL(sys_getgid16)
+       CALL(sys_signal)
+       CALL(sys_geteuid16)
+       CALL(sys_getegid16)             /* 50 */
+       CALL(sys_acct)
+       CALL(sys_umount)                /* recycled never used phys() */
+       CALL(sys_ni_syscall)            /* old lock syscall holder */
+       CALL(sys_ioctl)
+       CALL(sys_fcntl)                 /* 55 */
+       CALL(sys_ni_syscall)            /* old mpx syscall holder */
+       CALL(sys_setpgid)
+       CALL(sys_ni_syscall)            /* old ulimit syscall holder */
+       CALL(sys_ni_syscall)
+       CALL(sys_umask)                 /* 60 */
+       CALL(sys_chroot)
+       CALL(sys_ustat)
+       CALL(sys_dup2)
+       CALL(sys_getppid)
+       CALL(sys_getpgrp)               /* 65 */
+       CALL(sys_setsid)
+       CALL(sys_sigaction)
+       CALL(sys_sgetmask)
+       CALL(sys_ssetmask)
+       CALL(sys_setreuid16)            /* 70 */
+       CALL(sys_setregid16)
+       CALL(sys_sigsuspend)
+       CALL(sys_sigpending)
+       CALL(sys_sethostname)
+       CALL(sys_setrlimit)             /* 75 */
+       CALL(sys_old_getrlimit)
+       CALL(sys_getrusage)
+       CALL(sys_gettimeofday)
+       CALL(sys_settimeofday)
+       CALL(sys_getgroups16)           /* 80 */
+       CALL(sys_setgroups16)
+       CALL(sys_old_select)
+       CALL(sys_symlink)
+       CALL(sys_lstat)
+       CALL(sys_readlink)              /* 85 */
+       CALL(sys_uselib)
+       CALL(sys_swapon)
+       CALL(sys_reboot)
+       CALL(sys_old_readdir)
+       CALL(sys_old_mmap)              /* 90 */
+       CALL(sys_munmap)
+       CALL(sys_truncate)
+       CALL(sys_ftruncate)
+       CALL(sys_fchmod)
+       CALL(sys_fchown16)              /* 95 */
+       CALL(sys_getpriority)
+       CALL(sys_setpriority)
+       CALL(sys_ni_syscall)            /* old profil syscall holder */
+       CALL(sys_statfs)
+       CALL(sys_fstatfs)               /* 100 */
+       CALL(sys_ni_syscall)            /* ioperm for i386 */
+       CALL(sys_socketcall)
+       CALL(sys_syslog)
+       CALL(sys_setitimer)
+       CALL(sys_getitimer)             /* 105 */
+       CALL(sys_newstat)
+       CALL(sys_newlstat)
+       CALL(sys_newfstat)
+       CALL(sys_ni_syscall)
+       CALL(sys_ni_syscall)            /* iopl for i386 */ /* 110 */
+       CALL(sys_vhangup)
+       CALL(sys_ni_syscall)            /* obsolete idle() syscall */
+       CALL(sys_ni_syscall)            /* vm86old for i386 */
+       CALL(sys_wait4)
+       CALL(sys_swapoff)               /* 115 */
+       CALL(sys_sysinfo)
+       CALL(sys_ipc)
+       CALL(sys_fsync)
+       CALL(sys_sigreturn)
+       CALL(sys_clone)                 /* 120 */
+       CALL(sys_setdomainname)
+       CALL(sys_newuname)
+       CALL(sys_cacheflush)            /* modify_ldt for i386 */
+       CALL(sys_adjtimex)
+       CALL(sys_ni_syscall)            /* 125 sys_mprotect */
+       CALL(sys_sigprocmask)
+       CALL(sys_ni_syscall)            /* sys_create_module */
+       CALL(sys_init_module)
+       CALL(sys_delete_module)
+       CALL(sys_ni_syscall)            /* 130 sys_get_kernel_syms */
+       CALL(sys_quotactl)
+       CALL(sys_getpgid)
+       CALL(sys_fchdir)
+       CALL(sys_bdflush)
+       CALL(sys_sysfs)                 /* 135 */
+       CALL(sys_personality)
+       CALL(sys_ni_syscall)            /* for afs_syscall */
+       CALL(sys_setfsuid16)
+       CALL(sys_setfsgid16)
+       CALL(sys_llseek)                /* 140 */
+       CALL(sys_getdents)
+       CALL(sys_select)
+       CALL(sys_flock)
+       CALL(sys_ni_syscall)            /* sys_msync */
+       CALL(sys_readv)                 /* 145 */
+       CALL(sys_writev)
+       CALL(sys_getsid)
+       CALL(sys_fdatasync)
+       CALL(sys_sysctl)
+       CALL(sys_ni_syscall)            /* 150 sys_mlock */
+       CALL(sys_ni_syscall)            /* sys_munlock */
+       CALL(sys_ni_syscall)            /* sys_mlockall */
+       CALL(sys_ni_syscall)            /* sys_munlockall */
+       CALL(sys_sched_setparam)
+       CALL(sys_sched_getparam)        /* 155 */
+       CALL(sys_sched_setscheduler)
+       CALL(sys_sched_getscheduler)
+       CALL(sys_sched_yield)
+       CALL(sys_sched_get_priority_max)
+       CALL(sys_sched_get_priority_min)  /* 160 */
+       CALL(sys_sched_rr_get_interval)
+       CALL(sys_nanosleep)
+       CALL(sys_ni_syscall)            /* sys_mremap */
+       CALL(sys_setresuid16)
+       CALL(sys_getresuid16)           /* 165 */
+       CALL(sys_ni_syscall)            /* for vm86 */
+       CALL(sys_ni_syscall)            /* sys_query_module */
+       CALL(sys_poll)
+       CALL(sys_ni_syscall)            /* old nfsservctl */
+       CALL(sys_setresgid16)           /* 170 */
+       CALL(sys_getresgid16)
+       CALL(sys_prctl)
+       CALL(sys_rt_sigreturn)
+       CALL(sys_rt_sigaction)
+       CALL(sys_rt_sigprocmask)        /* 175 */
+       CALL(sys_rt_sigpending)
+       CALL(sys_rt_sigtimedwait)
+       CALL(sys_rt_sigqueueinfo)
+       CALL(sys_rt_sigsuspend)
+       CALL(sys_pread64)               /* 180 */
+       CALL(sys_pwrite64)
+       CALL(sys_lchown16);
+       CALL(sys_getcwd)
+       CALL(sys_capget)
+       CALL(sys_capset)                /* 185 */
+       CALL(sys_sigaltstack)
+       CALL(sys_sendfile)
+       CALL(sys_ni_syscall)            /* streams1 */
+       CALL(sys_ni_syscall)            /* streams2 */
+       CALL(sys_vfork)                 /* 190 */
+       CALL(sys_getrlimit)
+       CALL(sys_mmap_pgoff)
+       CALL(sys_truncate64)
+       CALL(sys_ftruncate64)
+       CALL(sys_stat64)                /* 195 */
+       CALL(sys_lstat64)
+       CALL(sys_fstat64)
+       CALL(sys_chown)
+       CALL(sys_getuid)
+       CALL(sys_getgid)                /* 200 */
+       CALL(sys_geteuid)
+       CALL(sys_getegid)
+       CALL(sys_setreuid)
+       CALL(sys_setregid)
+       CALL(sys_getgroups)             /* 205 */
+       CALL(sys_setgroups)
+       CALL(sys_fchown)
+       CALL(sys_setresuid)
+       CALL(sys_getresuid)
+       CALL(sys_setresgid)             /* 210 */
+       CALL(sys_getresgid)
+       CALL(sys_lchown)
+       CALL(sys_setuid)
+       CALL(sys_setgid)
+       CALL(sys_setfsuid)              /* 215 */
+       CALL(sys_setfsgid)
+       CALL(sys_pivot_root)
+       CALL(sys_ni_syscall)
+       CALL(sys_ni_syscall)
+       CALL(sys_getdents64)            /* 220 */
+       CALL(sys_fcntl64)
+       CALL(sys_ni_syscall)            /* reserved TUX */
+       CALL(sys_ni_syscall)            /* reserved Security */
+       CALL(sys_gettid)
+       CALL(sys_readahead)             /* 225 */
+       CALL(sys_setxattr)
+       CALL(sys_lsetxattr)
+       CALL(sys_fsetxattr)
+       CALL(sys_getxattr)
+       CALL(sys_lgetxattr)             /* 230 */
+       CALL(sys_fgetxattr)
+       CALL(sys_listxattr)
+       CALL(sys_llistxattr)
+       CALL(sys_flistxattr)
+       CALL(sys_removexattr)           /* 235 */
+       CALL(sys_lremovexattr)
+       CALL(sys_fremovexattr)
+       CALL(sys_tkill)
+       CALL(sys_sendfile64)
+       CALL(sys_futex)                 /* 240 */
+       CALL(sys_sched_setaffinity)
+       CALL(sys_sched_getaffinity)
+       CALL(sys_ni_syscall)
+       CALL(sys_ni_syscall)
+       CALL(sys_io_setup)              /* 245 */
+       CALL(sys_io_destroy)
+       CALL(sys_io_getevents)
+       CALL(sys_io_submit)
+       CALL(sys_io_cancel)
+       CALL(sys_fadvise64)             /* 250 */
+       CALL(sys_ni_syscall)
+       CALL(sys_exit_group)
+       CALL(sys_lookup_dcookie)
+       CALL(sys_epoll_create)
+       CALL(sys_epoll_ctl)             /* 255 */
+       CALL(sys_epoll_wait)
+       CALL(sys_ni_syscall)            /* sys_remap_file_pages */
+       CALL(sys_set_tid_address)
+       CALL(sys_timer_create)
+       CALL(sys_timer_settime)         /* 260 */
+       CALL(sys_timer_gettime)
+       CALL(sys_timer_getoverrun)
+       CALL(sys_timer_delete)
+       CALL(sys_clock_settime)
+       CALL(sys_clock_gettime)         /* 265 */
+       CALL(sys_clock_getres)
+       CALL(sys_clock_nanosleep)
+       CALL(sys_statfs64)
+       CALL(sys_fstatfs64)
+       CALL(sys_tgkill)                /* 270 */
+       CALL(sys_utimes)
+       CALL(sys_fadvise64_64)
+       CALL(sys_ni_syscall)            /* sys_vserver */
+       CALL(sys_ni_syscall)
+       CALL(sys_get_mempolicy)         /* 275 */
+       CALL(sys_set_mempolicy)
+       CALL(sys_mq_open)
+       CALL(sys_mq_unlink)
+       CALL(sys_mq_timedsend)
+       CALL(sys_mq_timedreceive)       /* 280 */
+       CALL(sys_mq_notify)
+       CALL(sys_mq_getsetattr)
+       CALL(sys_waitid)
+       CALL(sys_ni_syscall)            /* sys_kexec_load */
+       CALL(sys_add_key)               /* 285 */
+       CALL(sys_request_key)
+       CALL(sys_keyctl)
+       CALL(sys_ioprio_set)
+       CALL(sys_ioprio_get)            /* 290 */
+       CALL(sys_inotify_init)
+       CALL(sys_inotify_add_watch)
+       CALL(sys_inotify_rm_watch)
+       CALL(sys_migrate_pages)
+       CALL(sys_openat)                /* 295 */
+       CALL(sys_mkdirat)
+       CALL(sys_mknodat)
+       CALL(sys_fchownat)
+       CALL(sys_futimesat)
+       CALL(sys_fstatat64)             /* 300 */
+       CALL(sys_unlinkat)
+       CALL(sys_renameat)
+       CALL(sys_linkat)
+       CALL(sys_symlinkat)
+       CALL(sys_readlinkat)            /* 305 */
+       CALL(sys_fchmodat)
+       CALL(sys_faccessat)
+       CALL(sys_ni_syscall)            /* sys_pselect6 */
+       CALL(sys_ni_syscall)            /* sys_ppoll */
+       CALL(sys_unshare)               /* 310 */
+       CALL(sys_set_robust_list)
+       CALL(sys_get_robust_list)
+       CALL(sys_splice)
+       CALL(sys_sync_file_range)
+       CALL(sys_tee)                   /* 315 */
+       CALL(sys_vmsplice)
+       CALL(sys_ni_syscall)            /* sys_move_pages */
+       CALL(sys_getcpu)
+       CALL(sys_ni_syscall)            /* sys_epoll_pwait */
+       CALL(sys_setns)                 /* 320 */
index 03d356d96e5d30b066480ad8db2358f21dbccee5..3253fed42ac1b433fcd35f8073fed8dd080f1d39 100644 (file)
@@ -132,10 +132,12 @@ SECTIONS
         {
        . = ALIGN(0x4) ;
        __sbss = . ;
+       ___bss_start = . ;
                *(.bss*)
        . = ALIGN(0x4) ;
                *(COMMON)
        . = ALIGN(0x4) ;
+       ___bss_stop = . ;
        __ebss = . ;
        __end = . ;
        __ramstart = .;
index cabdd46b41dbe28d125b66a4a6a9236ede9420c3..ddd1fb3d01add0a66ae37af85f63179e3e786c3f 100644 (file)
@@ -9,10 +9,10 @@
        .h8300s
 #endif
        .text
-.global SYMBOL_NAME(abs)
+.global _abs
 
 ;;; int abs(int n)
-SYMBOL_NAME_LABEL(abs)
+_abs:
        mov.l   er0,er0
        bpl     1f
        neg.l   er0
index fdcbc1ee673c92e883ec408212e610d81eeea1e5..cad325e2c0e866e6b0594ab1b78f418d84458131 100644 (file)
 #endif
 
        .text
-.global SYMBOL_NAME(memcpy)
+.global _memcpy
 
 ;;; void *memcpy(void *to, void *from, size_t n)
-SYMBOL_NAME_LABEL(memcpy)
+_memcpy:
        mov.l   er2,er2
        bne     1f
        rts     
index 59abdf9485a5af7f73591c0f076a61f9e3907517..4549a64c5b79655a5991ec77db03cbd2c96ac5c6 100644 (file)
 #endif
        .text
 
-.global        SYMBOL_NAME(memset)
+.global        _memset
 
 ;;void *memset(*ptr, int c, size_t count)
 ;; ptr = er0
 ;; c   = er1(r1l)
 ;; count = er2
-SYMBOL_NAME_LABEL(memset)
+_memset:
        btst    #0,r0l
        beq     2f
 
index ff349d70a29b6860b007f7583d747ff448f2ef8c..6c1251e491af4edcd3665cf3e8ff74997830db34 100644 (file)
@@ -121,47 +121,27 @@ void __init paging_init(void)
 
 void __init mem_init(void)
 {
-       int codek = 0, datak = 0, initk = 0;
-       /* DAVIDM look at setup memory map generically with reserved area */
-       unsigned long tmp;
-       extern unsigned long  _ramend, _ramstart;
-       unsigned long len = &_ramend - &_ramstart;
-       unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */
-       unsigned long end_mem   = memory_end; /* DAVIDM - this must not include kernel stack at top */
+       unsigned long codesize = _etext - _stext;
 
-#ifdef DEBUG
-       printk(KERN_DEBUG "Mem_init: start=%lx, end=%lx\n", start_mem, end_mem);
-#endif
+       pr_devel("Mem_init: start=%lx, end=%lx\n", memory_start, memory_end);
 
-       end_mem &= PAGE_MASK;
-       high_memory = (void *) end_mem;
-
-       start_mem = PAGE_ALIGN(start_mem);
-       max_mapnr = num_physpages = MAP_NR(high_memory);
+       high_memory = (void *) (memory_end & PAGE_MASK);
+       max_mapnr = MAP_NR(high_memory);
 
        /* this will put all low memory onto the freelists */
-       totalram_pages = free_all_bootmem();
-
-       codek = (_etext - _stext) >> 10;
-       datak = (__bss_stop - _sdata) >> 10;
-       initk = (__init_begin - __init_end) >> 10;
-
-       tmp = nr_free_pages() << PAGE_SHIFT;
-       printk(KERN_INFO "Memory available: %luk/%luk RAM, %luk/%luk ROM (%dk kernel code, %dk data)\n",
-              tmp >> 10,
-              len >> 10,
-              (rom_length > 0) ? ((rom_length >> 10) - codek) : 0,
-              rom_length >> 10,
-              codek,
-              datak
-              );
+       free_all_bootmem();
+
+       mem_init_print_info(NULL);
+       if (rom_length > 0 && rom_length > codesize)
+               pr_info("Memory available: %luK/%luK ROM\n",
+                       (rom_length - codesize) >> 10, rom_length >> 10);
 }
 
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
 
@@ -169,7 +149,7 @@ void
 free_initmem(void)
 {
 #ifdef CONFIG_RAMKERNEL
-       free_initmem_default(0);
+       free_initmem_default(-1);
 #endif
 }
 
index ecaeb31ae9a44060a7c64c5ddc5d4c270688afac..b2ad0f2d0417cd3fc243f692177047c6b807df45 100644 (file)
 #define RAMEND CONFIG_BLKDEV_RESERVE_ADDRESS
 #endif
        
-       .global SYMBOL_NAME(_start)
-       .global SYMBOL_NAME(command_line)
-       .global SYMBOL_NAME(_platform_gpio_table)
-       .global SYMBOL_NAME(_target_name)
+       .global __start
+       .global _command_line
+       .global __platform_gpio_table
+       .global __target_name
        
        .h8300h
 
@@ -33,7 +33,7 @@
        .file   "crt0_ram.S"
 
        /* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
        mov.l   #RAMEND,sp
        ldc     #0x80,ccr
 
@@ -59,13 +59,13 @@ SYMBOL_NAME_LABEL(_start)
 
        /* copy kernel commandline */
        mov.l   #COMMAND_START,er5
-       mov.l   #SYMBOL_NAME(command_line),er6
+       mov.l   #_command_line,er6
        mov.w   #512,r4
        eepmov.w
 
        /* uClinux kernel start */
        ldc     #0x90,ccr       /* running kernel */
-       mov.l   #SYMBOL_NAME(init_thread_union),sp
+       mov.l   #_init_thread_union,sp
        add.l   #0x2000,sp
        jsr     @_start_kernel
 _exit:
@@ -107,4 +107,4 @@ __target_name:
        .asciz  "AE-3068"
        
        .section .bootvec,"ax"
-       jmp     @SYMBOL_NAME(_start)
+       jmp     @__start
index 80d0e16a44995b3671dd7df5d6f1374d7febf7da..5ab7d9c1291044124b8b53d6248f21d99c264506 100644 (file)
 #define RAMEND CONFIG_BLKDEV_RESERVE_ADDRESS
 #endif
        
-       .global SYMBOL_NAME(_start)
-       .global SYMBOL_NAME(command_line)
-       .global SYMBOL_NAME(_platform_gpio_table)
-       .global SYMBOL_NAME(_target_name)
+       .global __start
+       .global _command_line
+       .global __platform_gpio_table
+       .global __target_name
        
        .h8300h
 
@@ -33,7 +33,7 @@
        .file   "crt0_ram.S"
 
        /* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
        mov.l   #RAMEND,sp
        ldc     #0x80,ccr
 
@@ -59,13 +59,13 @@ SYMBOL_NAME_LABEL(_start)
 
        /* copy kernel commandline */
        mov.l   #COMMAND_START,er5
-       mov.l   #SYMBOL_NAME(command_line),er6
+       mov.l   #_command_line,er6
        mov.w   #512,r4
        eepmov.w
 
        /* uClinux kernel start */
        ldc     #0x90,ccr       /* running kernel */
-       mov.l   #SYMBOL_NAME(init_thread_union),sp
+       mov.l   #_init_thread_union,sp
        add.l   #0x2000,sp
        jsr     @_start_kernel
 _exit:
index 120add7ca83216f7d3b0091ba8bc9f5321d13a7d..dda1dfa15a5e624e1c568c1a36377aed95e6b117 100644 (file)
 
 #include <asm/linkage.h>
        
-       .global SYMBOL_NAME(_start)
-       .global SYMBOL_NAME(_command_line)
-       .global SYMBOL_NAME(_platform_gpio_table)
-       .global SYMBOL_NAME(_target_name)
+       .global __start
+       .global __command_line
+       .global __platform_gpio_table
+       .global __target_name
        
        .h8300h
        .section .text
        .file   "crt0_rom.S"
 
        /* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
        mov.l   #__ramend,sp
        ldc     #0x80,ccr
 
@@ -60,13 +60,13 @@ SYMBOL_NAME_LABEL(_start)
 
        /* copy kernel commandline */
        mov.l   #COMMAND_START,er5
-       mov.l   #SYMBOL_NAME(_command_line),er6
+       mov.l   #__command_line,er6
        mov.w   #512,r4
        eepmov.w
 
        /* linux kernel start */
        ldc     #0x90,ccr       /* running kernel */
-       mov.l   #SYMBOL_NAME(init_thread_union),sp
+       mov.l   #_init_thread_union,sp
        add.l   #0x2000,sp
        jsr     @_start_kernel
 _exit:
index efcbefb91b6713961b83575643d44d7f7a8c8b7b..6a0d4e2d9ec69cfa8719ec7b992e1dbbb1960809 100644 (file)
 #define RAMEND CONFIG_BLKDEV_RESERVE_ADDRESS
 #endif
        
-       .global SYMBOL_NAME(_start)
-       .global SYMBOL_NAME(command_line)
-       .global SYMBOL_NAME(_platform_gpio_table)
-       .global SYMBOL_NAME(_target_name)
+       .global __start
+       .global _command_line
+       .global __platform_gpio_table
+       .global __target_name
        
        .h8300h
 
@@ -33,7 +33,7 @@
        .file   "crt0_ram.S"
 
        /* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
        mov.l   #RAMEND,sp
        ldc     #0x80,ccr
 
@@ -59,13 +59,13 @@ SYMBOL_NAME_LABEL(_start)
 
        /* copy kernel commandline */
        mov.l   #COMMAND_START,er5
-       mov.l   #SYMBOL_NAME(command_line),er6
+       mov.l   #_command_line,er6
        mov.w   #512,r4
        eepmov.w
 
        /* uClinux kernel start */
        ldc     #0x90,ccr       /* running kernel */
-       mov.l   #SYMBOL_NAME(init_thread_union),sp
+       mov.l   #_init_thread_union,sp
        add.l   #0x2000,sp
        jsr     @_start_kernel
 _exit:
@@ -107,4 +107,4 @@ __target_name:
        .asciz  "H8MAX"
        
        .section .bootvec,"ax"
-       jmp     @SYMBOL_NAME(_start)
+       jmp     @__start
index d12b0debe478808f149906469d83b7c0a062da1c..5ed191b37cdeda836ddeab2881b63ae59f5b5eed 100644 (file)
 #define RAMEND CONFIG_BLKDEV_RESERVE_ADDRESS
 #endif
        
-       .global SYMBOL_NAME(_start)
-       .global SYMBOL_NAME(_command_line)
-       .global SYMBOL_NAME(_platform_gpio_table)
-       .global SYMBOL_NAME(_target_name)
+       .global __start
+       .global __command_line
+       .global __platform_gpio_table
+       .global __target_name
        
        .h8300s
 
@@ -34,7 +34,7 @@
        .file   "crt0_ram.S"
 
        /* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
        mov.l   #RAMEND,sp
        ldc     #0x80,ccr
        ldc     #0x00,exr
@@ -66,13 +66,13 @@ SYMBOL_NAME_LABEL(_start)
 
        /* copy kernel commandline */
        mov.l   #COMMAND_START,er5
-       mov.l   #SYMBOL_NAME(command_line),er6
+       mov.l   #_command_line,er6
        mov.w   #512,r4
        eepmov.w
 
        /* uClinux kernel start */
        ldc     #0x90,ccr       /* running kernel */
-       mov.l   #SYMBOL_NAME(init_thread_union),sp
+       mov.l   #_init_thread_union,sp
        add.l   #0x2000,sp
        jsr     @_start_kernel
 _exit:
@@ -127,4 +127,4 @@ __target_name:
        .asciz  "EDOSK-2674"
        
        .section .bootvec,"ax"
-       jmp     @SYMBOL_NAME(_start)
+       jmp     @__start
index c03d23c6fe12631f2ec2fae475fe9fbdc4e43c5f..06d1d7f324ca3e32885d100021aeccd2e887b712 100644 (file)
 #include <asm/linkage.h>
 #include <asm/regs267x.h>
                
-       .global SYMBOL_NAME(_start)
-       .global SYMBOL_NAME(_command_line)
-       .global SYMBOL_NAME(_platform_gpio_table)
-       .global SYMBOL_NAME(_target_name)
+       .global __start
+       .global __command_line
+       .global __platform_gpio_table
+       .global __target_name
        
        .h8300s
        .section .text
        .file   "crt0_rom.S"
 
        /* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
        mov.l   #__ramend,sp
        ldc     #0x80,ccr
        ldc     #0,exr
@@ -82,13 +82,13 @@ SYMBOL_NAME_LABEL(_start)
 
        /* copy kernel commandline */
        mov.l   #COMMAND_START,er5
-       mov.l   #SYMBOL_NAME(_command_line),er6
+       mov.l   #__command_line,er6
        mov.w   #512,r4
        eepmov.w
 
        /* linux kernel start */
        ldc     #0x90,ccr       /* running kernel */
-       mov.l   #SYMBOL_NAME(init_thread_union),sp
+       mov.l   #_init_thread_union,sp
        add.l   #0x2000,sp
        jsr     @_start_kernel
 _exit:
index b04541069976cbdc8ca82ea045344a72cc81f6f9..7018915de74feed7566b36ed1ce97cf025200c80 100644 (file)
 #define RAMEND CONFIG_BLKDEV_RESERVE_ADDRESS
 #endif
        
-       .global SYMBOL_NAME(_start)
-       .global SYMBOL_NAME(_command_line)
-       .global SYMBOL_NAME(_platform_gpio_table)
-       .global SYMBOL_NAME(_target_name)
+       .global __start
+       .global __command_line
+       .global __platform_gpio_table
+       .global __target_name
        
        .h8300s
 
@@ -34,7 +34,7 @@
        .file   "crt0_ram.S"
 
        /* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
        mov.l   #RAMEND,sp
        ldc     #0x80,ccr
        ldc     #0x00,exr
@@ -63,13 +63,13 @@ SYMBOL_NAME_LABEL(_start)
 
        /* copy kernel commandline */
        mov.l   #COMMAND_START,er5
-       mov.l   #SYMBOL_NAME(command_line),er6
+       mov.l   #_command_line,er6
        mov.w   #512,r4
        eepmov.w
 
        /* uClinux kernel start */
        ldc     #0x90,ccr       /* running kernel */
-       mov.l   #SYMBOL_NAME(init_thread_union),sp
+       mov.l   #_init_thread_union,sp
        add.l   #0x2000,sp
        jsr     @_start_kernel
 _exit:
@@ -124,4 +124,4 @@ __target_name:
        .asciz  "generic"
        
        .section .bootvec,"ax"
-       jmp     @SYMBOL_NAME(_start)
+       jmp     @__start
index 95b6f2898f52c753be7ef2c511e1861936f8fe60..623ba78281932a43a5c643dc3e03395721eb1d33 100644 (file)
 #include <asm/linkage.h>
 #include <asm/regs267x.h>
        
-       .global SYMBOL_NAME(_start)
-       .global SYMBOL_NAME(_command_line)
-       .global SYMBOL_NAME(_platform_gpio_table)
-       .global SYMBOL_NAME(_target_name)
+       .global __start
+       .global __command_line
+       .global __platform_gpio_table
+       .global __target_name
        
        .h8300s
        .section .text
        .file   "crt0_rom.S"
 
        /* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
        mov.l   #__ramend,sp
        ldc     #0x80,ccr
        ldc     #0,exr
@@ -61,7 +61,7 @@ SYMBOL_NAME_LABEL(_start)
 
        /* linux kernel start */
        ldc     #0x90,ccr       /* running kernel */
-       mov.l   #SYMBOL_NAME(init_thread_union),sp
+       mov.l   #_init_thread_union,sp
        add.l   #0x2000,sp
        jsr     @_start_kernel
 _exit:
index 2561d259a2967f296130ea0393e71f5edabec2d1..88977e42af0ac22d91bff69bd71d74d9f5529348 100644 (file)
@@ -70,10 +70,8 @@ unsigned long long kmap_generation;
 void __init mem_init(void)
 {
        /*  No idea where this is actually declared.  Seems to evade LXR.  */
-       totalram_pages += free_all_bootmem();
-       num_physpages = bootmem_lastpg-ARCH_PFN_OFFSET;
-
-       printk(KERN_INFO "totalram_pages = %ld\n", totalram_pages);
+       free_all_bootmem();
+       mem_init_print_info(NULL);
 
        /*
         *  To-Do:  someone somewhere should wipe out the bootmem map
index bcda5b2d121a624ee784f81843a13c155b7865a8..d43daf192b21d54df034e52c809a4ac4b2178161 100644 (file)
@@ -2042,7 +2042,8 @@ sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle)
 #endif
 
 static int __init
-acpi_sba_ioc_add(struct acpi_device *device)
+acpi_sba_ioc_add(struct acpi_device *device,
+                const struct acpi_device_id *not_used)
 {
        struct ioc *ioc;
        acpi_status status;
@@ -2090,14 +2091,18 @@ static const struct acpi_device_id hp_ioc_iommu_device_ids[] = {
        {"HWP0004", 0},
        {"", 0},
 };
-static struct acpi_driver acpi_sba_ioc_driver = {
-       .name           = "IOC IOMMU Driver",
-       .ids            = hp_ioc_iommu_device_ids,
-       .ops            = {
-               .add    = acpi_sba_ioc_add,
-       },
+static struct acpi_scan_handler acpi_sba_ioc_handler = {
+       .ids    = hp_ioc_iommu_device_ids,
+       .attach = acpi_sba_ioc_add,
 };
 
+static int __init acpi_sba_ioc_init_acpi(void)
+{
+       return acpi_scan_add_handler(&acpi_sba_ioc_handler);
+}
+/* This has to run before acpi_scan_init(). */
+arch_initcall(acpi_sba_ioc_init_acpi);
+
 extern struct dma_map_ops swiotlb_dma_ops;
 
 static int __init
@@ -2122,7 +2127,10 @@ sba_init(void)
        }
 #endif
 
-       acpi_bus_register_driver(&acpi_sba_ioc_driver);
+       /*
+        * ioc_list should be populated by the acpi_sba_ioc_handler's .attach()
+        * routine, but that only happens if acpi_scan_init() has already run.
+        */
        if (!ioc_list) {
 #ifdef CONFIG_IA64_GENERIC
                /*
index 331de723c6767f264e8ee682fcb73aa44d4a7bf7..3a428f19a00116ad963f7cdae2ddf469ec21a054 100644 (file)
@@ -88,8 +88,8 @@ simscsi_setup (char *s)
        if (strlen(s) > MAX_ROOT_LEN) {
                printk(KERN_ERR "simscsi_setup: prefix too long---using default %s\n",
                       simscsi_root);
-       }
-       simscsi_root = s;
+       } else
+               simscsi_root = s;
        return 1;
 }
 
index bed73a643a56e3c0169a4fd43b705fcba491f5c8..f41e66d65e31c4b6c1eb15e9bdb0ee71d2018378 100644 (file)
@@ -29,17 +29,15 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
  *                                 from 1 to a 0 value
  *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 1
  *
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns.
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
  */
 static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count)
 {
        if (unlikely(ia64_fetchadd4_acq(count, -1) != 1))
-               return fail_fn(count);
+               return -1;
        return 0;
 }
 
index 5e04b591e423d09e21f5899523565aec2fa6771d..80775f55f03f9293c2d05d2598e349f08ef9b56e 100644 (file)
@@ -89,9 +89,9 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
 #define pci_legacy_read platform_pci_legacy_read
 #define pci_legacy_write platform_pci_legacy_write
 
-struct pci_window {
-       struct resource resource;
-       u64 offset;
+struct iospace_resource {
+       struct list_head list;
+       struct resource res;
 };
 
 struct pci_controller {
@@ -100,12 +100,10 @@ struct pci_controller {
        int segment;
        int node;               /* nearest node with memory or -1 for global allocation */
 
-       unsigned int windows;
-       struct pci_window *window;
-
        void *platform_data;
 };
 
+
 #define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata)
 #define pci_domain_nr(busdev)    (PCI_CONTROLLER(busdev)->segment)
 
index 335eb07480fe9a89545c48d3ed273e50cfee9cb8..5eb71d22c3d5901030eec5c9ead78dc1279d815e 100644 (file)
@@ -807,7 +807,7 @@ int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
  *  ACPI based hotplug CPU support
  */
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
-static __cpuinit
+static
 int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
 {
 #ifdef CONFIG_ACPI_NUMA
@@ -882,7 +882,7 @@ __init void prefill_possible_map(void)
                set_cpu_possible(i, true);
 }
 
-static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
+static int _acpi_map_lsapic(acpi_handle handle, int *pcpu)
 {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *obj;
index f034563aeae547c44b0e3a2a99b4ab535917cee1..51bce594eb83582daac87f3853235db70bce3b85 100644 (file)
@@ -1116,11 +1116,6 @@ efi_memmap_init(u64 *s, u64 *e)
                if (!is_memory_available(md))
                        continue;
 
-#ifdef CONFIG_CRASH_DUMP
-               /* saved_max_pfn should ignore max_addr= command line arg */
-               if (saved_max_pfn < (efi_md_end(md) >> PAGE_SHIFT))
-                       saved_max_pfn = (efi_md_end(md) >> PAGE_SHIFT);
-#endif
                /*
                 * Round ends inward to granule boundaries
                 * Give trimmings to uncached allocator
index 2d67317a1ec206c824eb754becfcd919f7ee9700..f59c0b844e8855ea55989ad6b814fad125b45879 100644 (file)
@@ -225,17 +225,17 @@ static struct attribute_group err_inject_attr_group = {
        .name = "err_inject"
 };
 /* Add/Remove err_inject interface for CPU device */
-static int __cpuinit err_inject_add_dev(struct device * sys_dev)
+static int err_inject_add_dev(struct device *sys_dev)
 {
        return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group);
 }
 
-static int __cpuinit err_inject_remove_dev(struct device * sys_dev)
+static int err_inject_remove_dev(struct device *sys_dev)
 {
        sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
        return 0;
 }
-static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
+static int err_inject_cpu_callback(struct notifier_block *nfb,
                unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
@@ -256,7 +256,7 @@ static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata err_inject_cpu_notifier =
+static struct notifier_block err_inject_cpu_notifier =
 {
        .notifier_call = err_inject_cpu_callback,
 };
index 9be4e497f3d3c253aa36c87459cdb4830a9e4fa7..991ca336b8a2971ccddbc12c3f5be1ca96ecceb6 100644 (file)
@@ -1035,7 +1035,7 @@ END(ia64_delay_loop)
  * Return a CPU-local timestamp in nano-seconds.  This timestamp is
  * NOT synchronized across CPUs its return value must never be
  * compared against the values returned on another CPU.  The usage in
- * kernel/sched.c ensures that.
+ * kernel/sched/core.c ensures that.
  *
  * The return-value of sched_clock() is NOT supposed to wrap-around.
  * If it did, it would cause some scheduling hiccups (at the worst).
index d7396dbb07bb40598c2a7de3b26ffc34bf5de8ca..b8edfa75a83f9cd8bce4469d1d1c97b93b02d371 100644 (file)
@@ -631,7 +631,7 @@ ia64_mca_register_cpev (int cpev)
  * Outputs
  *     None
  */
-void __cpuinit
+void
 ia64_mca_cmc_vector_setup (void)
 {
        cmcv_reg_t      cmcv;
@@ -1814,7 +1814,7 @@ static struct irqaction mca_cpep_irqaction = {
  * format most of the fields.
  */
 
-static void __cpuinit
+static void
 format_mca_init_stack(void *mca_data, unsigned long offset,
                const char *type, int cpu)
 {
@@ -1844,7 +1844,7 @@ static void * __init_refok mca_bootmem(void)
 }
 
 /* Do per-CPU MCA-related initialization.  */
-void __cpuinit
+void
 ia64_mca_cpu_init(void *cpu_data)
 {
        void *pal_vaddr;
@@ -1896,7 +1896,7 @@ ia64_mca_cpu_init(void *cpu_data)
                                                              PAGE_KERNEL));
 }
 
-static void __cpuinit ia64_mca_cmc_vector_adjust(void *dummy)
+static void ia64_mca_cmc_vector_adjust(void *dummy)
 {
        unsigned long flags;
 
@@ -1906,7 +1906,7 @@ static void __cpuinit ia64_mca_cmc_vector_adjust(void *dummy)
        local_irq_restore(flags);
 }
 
-static int __cpuinit mca_cpu_callback(struct notifier_block *nfb,
+static int mca_cpu_callback(struct notifier_block *nfb,
                                      unsigned long action,
                                      void *hcpu)
 {
@@ -1922,7 +1922,7 @@ static int __cpuinit mca_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block mca_cpu_notifier __cpuinitdata = {
+static struct notifier_block mca_cpu_notifier = {
        .notifier_call = mca_cpu_callback
 };
 
index c93420c97409dc2c97c41417279f7395e411b6f6..d288cde9360666b510e65c9a2a24171edf35ac77 100644 (file)
@@ -30,7 +30,7 @@ EXPORT_SYMBOL(cpu_to_node_map);
 cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
 EXPORT_SYMBOL(node_to_cpu_mask);
 
-void __cpuinit map_cpu_to_node(int cpu, int nid)
+void map_cpu_to_node(int cpu, int nid)
 {
        int oldnid;
        if (nid < 0) { /* just initialize by zero */
@@ -51,7 +51,7 @@ void __cpuinit map_cpu_to_node(int cpu, int nid)
        return;
 }
 
-void __cpuinit unmap_cpu_from_node(int cpu, int nid)
+void unmap_cpu_from_node(int cpu, int nid)
 {
        WARN_ON(!cpu_isset(cpu, node_to_cpu_mask[nid]));
        WARN_ON(cpu_to_node_map[cpu] != nid);
index 2b3c2d79256f9343469ad0428ef4eb1f9434028c..ab333284f4b2eb45ce2294b337d8e3196a081721 100644 (file)
@@ -932,7 +932,7 @@ static const struct file_operations proc_palinfo_fops = {
        .release        = single_release,
 };
 
-static void __cpuinit
+static void
 create_palinfo_proc_entries(unsigned int cpu)
 {
        pal_func_cpu_u_t f;
@@ -962,7 +962,7 @@ remove_palinfo_proc_entries(unsigned int hcpu)
        remove_proc_subtree(cpustr, palinfo_dir);
 }
 
-static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
+static int palinfo_cpu_callback(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
        unsigned int hotcpu = (unsigned long)hcpu;
index 1ddcfe5ef353cc0e8827d11affa6219331204cfa..992c1098c522c2eecf6dacbef4a3b96f2ecf2de1 100644 (file)
@@ -33,15 +33,6 @@ int force_iommu __read_mostly;
 
 int iommu_pass_through;
 
-/* Dummy device used for NULL arguments (normally ISA). Better would
-   be probably a smaller DMA mask, but this is bug-to-bug compatible
-   to i386. */
-struct device fallback_dev = {
-       .init_name = "fallback device",
-       .coherent_dma_mask = DMA_BIT_MASK(32),
-       .dma_mask = &fallback_dev.coherent_dma_mask,
-};
-
 extern struct dma_map_ops intel_dma_ops;
 
 static int __init pci_iommu_init(void)
index 9ea25fce06d5e6d42de5e3188b36dd1ee30f454a..5a9ff1c3c3e912c5d0435ea86900a664e525fa16 100644 (file)
@@ -5647,24 +5647,8 @@ pfm_proc_show_header(struct seq_file *m)
 
        list_for_each(pos, &pfm_buffer_fmt_list) {
                entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list);
-               seq_printf(m, "format                    : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x %s\n",
-                       entry->fmt_uuid[0],
-                       entry->fmt_uuid[1],
-                       entry->fmt_uuid[2],
-                       entry->fmt_uuid[3],
-                       entry->fmt_uuid[4],
-                       entry->fmt_uuid[5],
-                       entry->fmt_uuid[6],
-                       entry->fmt_uuid[7],
-                       entry->fmt_uuid[8],
-                       entry->fmt_uuid[9],
-                       entry->fmt_uuid[10],
-                       entry->fmt_uuid[11],
-                       entry->fmt_uuid[12],
-                       entry->fmt_uuid[13],
-                       entry->fmt_uuid[14],
-                       entry->fmt_uuid[15],
-                       entry->fmt_name);
+               seq_printf(m, "format                    : %16phD %s\n",
+                          entry->fmt_uuid, entry->fmt_name);
        }
        spin_unlock(&pfm_buffer_fmt_lock);
 
index 4bc580af67b3995dbfb4772adfc7336807032197..960a396f5929667162bf0bb867ac03d7aa85e302 100644 (file)
@@ -568,7 +568,7 @@ static const struct file_operations salinfo_data_fops = {
        .llseek  = default_llseek,
 };
 
-static int __cpuinit
+static int
 salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
 {
        unsigned int i, cpu = (unsigned long)hcpu;
@@ -609,7 +609,7 @@ salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu
        return NOTIFY_OK;
 }
 
-static struct notifier_block salinfo_cpu_notifier __cpuinitdata =
+static struct notifier_block salinfo_cpu_notifier =
 {
        .notifier_call = salinfo_cpu_callback,
        .priority = 0,
index 13bfdd22afc8e77fb8ae3975e2478ecb6847eea7..4fc2e9569bb23c29e4735844bec93934e7080dc2 100644 (file)
@@ -748,7 +748,7 @@ const struct seq_operations cpuinfo_op = {
 #define MAX_BRANDS     8
 static char brandname[MAX_BRANDS][128];
 
-static char * __cpuinit
+static char *
 get_model_name(__u8 family, __u8 model)
 {
        static int overflow;
@@ -778,7 +778,7 @@ get_model_name(__u8 family, __u8 model)
        return "Unknown";
 }
 
-static void __cpuinit
+static void
 identify_cpu (struct cpuinfo_ia64 *c)
 {
        union {
@@ -850,7 +850,7 @@ identify_cpu (struct cpuinfo_ia64 *c)
  * 2. the minimum of the i-cache stride sizes for "flush_icache_range()".
  * 3. the minimum of the cache stride sizes for "clflush_cache_range()".
  */
-static void __cpuinit
+static void
 get_cache_info(void)
 {
        unsigned long line_size, max = 1;
@@ -915,10 +915,10 @@ get_cache_info(void)
  * cpu_init() initializes state that is per-CPU.  This function acts
  * as a 'CPU state barrier', nothing should get across.
  */
-void __cpuinit
+void
 cpu_init (void)
 {
-       extern void __cpuinit ia64_mmu_init (void *);
+       extern void ia64_mmu_init(void *);
        static unsigned long max_num_phys_stacked = IA64_NUM_PHYS_STACK_REG;
        unsigned long num_phys_stacked;
        pal_vm_info_2_u_t vmi;
index 8d87168d218df8e87e3392a56e13b72e853e137f..547a48d78bd7f4c76eb84e551aa9ec776c1dde40 100644 (file)
@@ -351,7 +351,7 @@ static inline void smp_setup_percpu_timer(void)
 {
 }
 
-static void __cpuinit
+static void
 smp_callin (void)
 {
        int cpuid, phys_id, itc_master;
@@ -442,7 +442,7 @@ smp_callin (void)
 /*
  * Activate a secondary processor.  head.S calls this.
  */
-int __cpuinit
+int
 start_secondary (void *unused)
 {
        /* Early console may use I/O ports */
@@ -459,7 +459,7 @@ start_secondary (void *unused)
        return 0;
 }
 
-static int __cpuinit
+static int
 do_boot_cpu (int sapicid, int cpu, struct task_struct *idle)
 {
        int timeout;
@@ -728,7 +728,7 @@ static inline void set_cpu_sibling_map(int cpu)
        }
 }
 
-int __cpuinit
+int
 __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
        int ret;
index dc00b2c1b42ab39d6bae4abbc1ed27396dd3d73d..ca69a5a96dcc07bb760eabd43ff6a03dfc2d6db2 100644 (file)
@@ -135,11 +135,11 @@ struct cpu_cache_info {
        struct kobject kobj;
 };
 
-static struct cpu_cache_info   all_cpu_cache_info[NR_CPUS] __cpuinitdata;
+static struct cpu_cache_info   all_cpu_cache_info[NR_CPUS];
 #define LEAF_KOBJECT_PTR(x,y)    (&all_cpu_cache_info[x].cache_leaves[y])
 
 #ifdef CONFIG_SMP
-static void __cpuinit cache_shared_cpu_map_setup( unsigned int cpu,
+static void cache_shared_cpu_map_setup(unsigned int cpu,
                struct cache_info * this_leaf)
 {
        pal_cache_shared_info_t csi;
@@ -174,7 +174,7 @@ static void __cpuinit cache_shared_cpu_map_setup( unsigned int cpu,
                                &csi) == PAL_STATUS_SUCCESS);
 }
 #else
-static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu,
+static void cache_shared_cpu_map_setup(unsigned int cpu,
                struct cache_info * this_leaf)
 {
        cpu_set(cpu, this_leaf->shared_cpu_map);
@@ -298,7 +298,7 @@ static struct kobj_type cache_ktype_percpu_entry = {
        .sysfs_ops      = &cache_sysfs_ops,
 };
 
-static void __cpuinit cpu_cache_sysfs_exit(unsigned int cpu)
+static void cpu_cache_sysfs_exit(unsigned int cpu)
 {
        kfree(all_cpu_cache_info[cpu].cache_leaves);
        all_cpu_cache_info[cpu].cache_leaves = NULL;
@@ -307,7 +307,7 @@ static void __cpuinit cpu_cache_sysfs_exit(unsigned int cpu)
        return;
 }
 
-static int __cpuinit cpu_cache_sysfs_init(unsigned int cpu)
+static int cpu_cache_sysfs_init(unsigned int cpu)
 {
        unsigned long i, levels, unique_caches;
        pal_cache_config_info_t cci;
@@ -351,7 +351,7 @@ static int __cpuinit cpu_cache_sysfs_init(unsigned int cpu)
 }
 
 /* Add cache interface for CPU device */
-static int __cpuinit cache_add_dev(struct device * sys_dev)
+static int cache_add_dev(struct device *sys_dev)
 {
        unsigned int cpu = sys_dev->id;
        unsigned long i, j;
@@ -401,7 +401,7 @@ static int __cpuinit cache_add_dev(struct device * sys_dev)
 }
 
 /* Remove cache interface for CPU device */
-static int __cpuinit cache_remove_dev(struct device * sys_dev)
+static int cache_remove_dev(struct device *sys_dev)
 {
        unsigned int cpu = sys_dev->id;
        unsigned long i;
@@ -425,7 +425,7 @@ static int __cpuinit cache_remove_dev(struct device * sys_dev)
  * When a cpu is hot-plugged, do a check and initiate
  * cache kobject if necessary
  */
-static int __cpuinit cache_cpu_callback(struct notifier_block *nfb,
+static int cache_cpu_callback(struct notifier_block *nfb,
                unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
@@ -445,7 +445,7 @@ static int __cpuinit cache_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata cache_cpu_notifier =
+static struct notifier_block cache_cpu_notifier =
 {
        .notifier_call = cache_cpu_callback
 };
index f7f9f9c6caf03b19e6dfd89f754146d8412421a7..d3636e67a98e8281f44c0038c762838e942b723f 100644 (file)
@@ -630,7 +630,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
                printk(KERN_ERR "  iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n",
                       iip, ifa, isr);
                force_sig(SIGSEGV, current);
-               break;
+               return;
 
              case 46:
                printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n");
index 1a4053789d0167ad6cb70dcb60a09e56020eaeb3..18e45ec49bbfdbb3bd25627eba31b79d22b9ad5a 100644 (file)
@@ -47,12 +47,13 @@ FORCE : $(obj)/$(offsets-file)
 
 ccflags-y := -Ivirt/kvm -Iarch/ia64/kvm/
 asflags-y := -Ivirt/kvm -Iarch/ia64/kvm/
+KVM := ../../../virt/kvm
 
-common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
-               coalesced_mmio.o irq_comm.o)
+common-objs = $(KVM)/kvm_main.o $(KVM)/ioapic.o \
+               $(KVM)/coalesced_mmio.o $(KVM)/irq_comm.o
 
 ifeq ($(CONFIG_KVM_DEVICE_ASSIGNMENT),y)
-common-objs += $(addprefix ../../../virt/kvm/, assigned-dev.o iommu.o)
+common-objs += $(KVM)/assigned-dev.o $(KVM)/iommu.o
 endif
 
 kvm-objs := $(common-objs) kvm-ia64.o kvm_fw.o
index 67c59ebec899c30ee4533880f3acb2bbc141ff02..da5237d636d650ec5f58dc9ff5f046473a60b679 100644 (file)
@@ -156,8 +156,7 @@ static void *cpu_data;
  *
  * Allocate and setup per-cpu data areas.
  */
-void * __cpuinit
-per_cpu_init (void)
+void *per_cpu_init(void)
 {
        static bool first_time = true;
        void *cpu0_data = __cpu0_per_cpu;
@@ -295,14 +294,6 @@ find_memory (void)
        alloc_per_cpu_data();
 }
 
-static int count_pages(u64 start, u64 end, void *arg)
-{
-       unsigned long *count = arg;
-
-       *count += (end - start) >> PAGE_SHIFT;
-       return 0;
-}
-
 /*
  * Set up the page tables.
  */
@@ -313,9 +304,6 @@ paging_init (void)
        unsigned long max_dma;
        unsigned long max_zone_pfns[MAX_NR_ZONES];
 
-       num_physpages = 0;
-       efi_memmap_walk(count_pages, &num_physpages);
-
        memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
 #ifdef CONFIG_ZONE_DMA
        max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
index ae4db4bd6d97d77aebae5c7677e6803500770904..2de08f4d99305fa42aafe573da4cbbd5ad3892ca 100644 (file)
@@ -37,7 +37,6 @@ struct early_node_data {
        struct ia64_node_data *node_data;
        unsigned long pernode_addr;
        unsigned long pernode_size;
-       unsigned long num_physpages;
 #ifdef CONFIG_ZONE_DMA
        unsigned long num_dma_physpages;
 #endif
@@ -593,7 +592,7 @@ void __init find_memory(void)
  * find_pernode_space() does most of this already, we just need to set
  * local_per_cpu_offset
  */
-void __cpuinit *per_cpu_init(void)
+void *per_cpu_init(void)
 {
        int cpu;
        static int first_time = 1;
@@ -732,7 +731,6 @@ static __init int count_node_pages(unsigned long start, unsigned long len, int n
 {
        unsigned long end = start + len;
 
-       mem_data[node].num_physpages += len >> PAGE_SHIFT;
 #ifdef CONFIG_ZONE_DMA
        if (start <= __pa(MAX_DMA_ADDRESS))
                mem_data[node].num_dma_physpages +=
@@ -778,7 +776,6 @@ void __init paging_init(void)
 #endif
 
        for_each_online_node(node) {
-               num_physpages += mem_data[node].num_physpages;
                pfn_offset = mem_data[node].min_pfn;
 
 #ifdef CONFIG_VIRTUAL_MEM_MAP
index d1fe4b402601f9b1b416346aecbe8b90d74b7b88..b6f7f43424ec492187f558b163b525d2d4583395 100644 (file)
@@ -154,9 +154,8 @@ ia64_init_addr_space (void)
 void
 free_initmem (void)
 {
-       free_reserved_area((unsigned long)ia64_imva(__init_begin),
-                          (unsigned long)ia64_imva(__init_end),
-                          0, "unused kernel");
+       free_reserved_area(ia64_imva(__init_begin), ia64_imva(__init_end),
+                          -1, "unused kernel");
 }
 
 void __init
@@ -546,19 +545,6 @@ int __init register_active_ranges(u64 start, u64 len, int nid)
        return 0;
 }
 
-static int __init
-count_reserved_pages(u64 start, u64 end, void *arg)
-{
-       unsigned long num_reserved = 0;
-       unsigned long *count = arg;
-
-       for (; start < end; start += PAGE_SIZE)
-               if (PageReserved(virt_to_page(start)))
-                       ++num_reserved;
-       *count += num_reserved;
-       return 0;
-}
-
 int
 find_max_min_low_pfn (u64 start, u64 end, void *arg)
 {
@@ -597,8 +583,6 @@ __setup("nolwsys", nolwsys_setup);
 void __init
 mem_init (void)
 {
-       long reserved_pages, codesize, datasize, initsize;
-       pg_data_t *pgdat;
        int i;
 
        BUG_ON(PTRS_PER_PGD * sizeof(pgd_t) != PAGE_SIZE);
@@ -616,27 +600,12 @@ mem_init (void)
 
 #ifdef CONFIG_FLATMEM
        BUG_ON(!mem_map);
-       max_mapnr = max_low_pfn;
 #endif
 
+       set_max_mapnr(max_low_pfn);
        high_memory = __va(max_low_pfn * PAGE_SIZE);
-
-       for_each_online_pgdat(pgdat)
-               if (pgdat->bdata->node_bootmem_map)
-                       totalram_pages += free_all_bootmem_node(pgdat);
-
-       reserved_pages = 0;
-       efi_memmap_walk(count_reserved_pages, &reserved_pages);
-
-       codesize =  (unsigned long) _etext - (unsigned long) _stext;
-       datasize =  (unsigned long) _edata - (unsigned long) _etext;
-       initsize =  (unsigned long) __init_end - (unsigned long) __init_begin;
-
-       printk(KERN_INFO "Memory: %luk/%luk available (%luk code, %luk reserved, "
-              "%luk data, %luk init)\n", nr_free_pages() << (PAGE_SHIFT - 10),
-              num_physpages << (PAGE_SHIFT - 10), codesize >> 10,
-              reserved_pages << (PAGE_SHIFT - 10), datasize >> 10, initsize >> 10);
-
+       free_all_bootmem();
+       mem_init_print_info(NULL);
 
        /*
         * For fsyscall entrpoints with no light-weight handler, use the ordinary
index 4248492b9321b2eb5f7c3079d532982011a907ef..ea21d4cad540eb8207f29d19fb01dd5517843f4a 100644 (file)
@@ -86,7 +86,7 @@ int __meminit __early_pfn_to_nid(unsigned long pfn)
        return -1;
 }
 
-void __cpuinit numa_clear_node(int cpu)
+void numa_clear_node(int cpu)
 {
        unmap_cpu_from_node(cpu, NUMA_NO_NODE);
 }
index de1474ff0bc59fb26d2822c6793da608bb3194fb..2326790b7d8be4f9e6cffbea4c4a22fc1ab91f3e 100644 (file)
@@ -134,6 +134,10 @@ struct pci_root_info {
        struct acpi_device *bridge;
        struct pci_controller *controller;
        struct list_head resources;
+       struct resource *res;
+       resource_size_t *res_offset;
+       unsigned int res_num;
+       struct list_head io_resources;
        char *name;
 };
 
@@ -153,7 +157,7 @@ new_space (u64 phys_base, int sparse)
                        return i;
 
        if (num_io_spaces == MAX_IO_SPACES) {
-               printk(KERN_ERR "PCI: Too many IO port spaces "
+               pr_err("PCI: Too many IO port spaces "
                        "(MAX_IO_SPACES=%lu)\n", MAX_IO_SPACES);
                return ~0;
        }
@@ -168,25 +172,22 @@ new_space (u64 phys_base, int sparse)
 static u64 add_io_space(struct pci_root_info *info,
                        struct acpi_resource_address64 *addr)
 {
+       struct iospace_resource *iospace;
        struct resource *resource;
        char *name;
        unsigned long base, min, max, base_port;
        unsigned int sparse = 0, space_nr, len;
 
-       resource = kzalloc(sizeof(*resource), GFP_KERNEL);
-       if (!resource) {
-               printk(KERN_ERR "PCI: No memory for %s I/O port space\n",
-                       info->name);
+       len = strlen(info->name) + 32;
+       iospace = kzalloc(sizeof(*iospace) + len, GFP_KERNEL);
+       if (!iospace) {
+               dev_err(&info->bridge->dev,
+                               "PCI: No memory for %s I/O port space\n",
+                               info->name);
                goto out;
        }
 
-       len = strlen(info->name) + 32;
-       name = kzalloc(len, GFP_KERNEL);
-       if (!name) {
-               printk(KERN_ERR "PCI: No memory for %s I/O port space name\n",
-                       info->name);
-               goto free_resource;
-       }
+       name = (char *)(iospace + 1);
 
        min = addr->minimum;
        max = min + addr->address_length - 1;
@@ -195,7 +196,7 @@ static u64 add_io_space(struct pci_root_info *info,
 
        space_nr = new_space(addr->translation_offset, sparse);
        if (space_nr == ~0)
-               goto free_name;
+               goto free_resource;
 
        base = __pa(io_space[space_nr].mmio_base);
        base_port = IO_SPACE_BASE(space_nr);
@@ -210,18 +211,23 @@ static u64 add_io_space(struct pci_root_info *info,
        if (space_nr == 0)
                sparse = 1;
 
+       resource = &iospace->res;
        resource->name  = name;
        resource->flags = IORESOURCE_MEM;
        resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min);
        resource->end   = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max);
-       insert_resource(&iomem_resource, resource);
+       if (insert_resource(&iomem_resource, resource)) {
+               dev_err(&info->bridge->dev,
+                               "can't allocate host bridge io space resource  %pR\n",
+                               resource);
+               goto free_resource;
+       }
 
+       list_add_tail(&iospace->list, &info->io_resources);
        return base_port;
 
-free_name:
-       kfree(name);
 free_resource:
-       kfree(resource);
+       kfree(iospace);
 out:
        return ~0;
 }
@@ -265,7 +271,7 @@ static acpi_status count_window(struct acpi_resource *resource, void *data)
 static acpi_status add_window(struct acpi_resource *res, void *data)
 {
        struct pci_root_info *info = data;
-       struct pci_window *window;
+       struct resource *resource;
        struct acpi_resource_address64 addr;
        acpi_status status;
        unsigned long flags, offset = 0;
@@ -289,55 +295,146 @@ static acpi_status add_window(struct acpi_resource *res, void *data)
        } else
                return AE_OK;
 
-       window = &info->controller->window[info->controller->windows++];
-       window->resource.name = info->name;
-       window->resource.flags = flags;
-       window->resource.start = addr.minimum + offset;
-       window->resource.end = window->resource.start + addr.address_length - 1;
-       window->offset = offset;
+       resource = &info->res[info->res_num];
+       resource->name = info->name;
+       resource->flags = flags;
+       resource->start = addr.minimum + offset;
+       resource->end = resource->start + addr.address_length - 1;
+       info->res_offset[info->res_num] = offset;
 
-       if (insert_resource(root, &window->resource)) {
+       if (insert_resource(root, resource)) {
                dev_err(&info->bridge->dev,
                        "can't allocate host bridge window %pR\n",
-                       &window->resource);
+                       resource);
        } else {
                if (offset)
                        dev_info(&info->bridge->dev, "host bridge window %pR "
                                 "(PCI address [%#llx-%#llx])\n",
-                                &window->resource,
-                                window->resource.start - offset,
-                                window->resource.end - offset);
+                                resource,
+                                resource->start - offset,
+                                resource->end - offset);
                else
                        dev_info(&info->bridge->dev,
-                                "host bridge window %pR\n",
-                                &window->resource);
+                                "host bridge window %pR\n", resource);
        }
-
        /* HP's firmware has a hack to work around a Windows bug.
         * Ignore these tiny memory ranges */
-       if (!((window->resource.flags & IORESOURCE_MEM) &&
-             (window->resource.end - window->resource.start < 16)))
-               pci_add_resource_offset(&info->resources, &window->resource,
-                                       window->offset);
+       if (!((resource->flags & IORESOURCE_MEM) &&
+             (resource->end - resource->start < 16)))
+               pci_add_resource_offset(&info->resources, resource,
+                                       info->res_offset[info->res_num]);
 
+       info->res_num++;
        return AE_OK;
 }
 
+static void free_pci_root_info_res(struct pci_root_info *info)
+{
+       struct iospace_resource *iospace, *tmp;
+
+       list_for_each_entry_safe(iospace, tmp, &info->io_resources, list)
+               kfree(iospace);
+
+       kfree(info->name);
+       kfree(info->res);
+       info->res = NULL;
+       kfree(info->res_offset);
+       info->res_offset = NULL;
+       info->res_num = 0;
+       kfree(info->controller);
+       info->controller = NULL;
+}
+
+static void __release_pci_root_info(struct pci_root_info *info)
+{
+       int i;
+       struct resource *res;
+       struct iospace_resource *iospace;
+
+       list_for_each_entry(iospace, &info->io_resources, list)
+               release_resource(&iospace->res);
+
+       for (i = 0; i < info->res_num; i++) {
+               res = &info->res[i];
+
+               if (!res->parent)
+                       continue;
+
+               if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+                       continue;
+
+               release_resource(res);
+       }
+
+       free_pci_root_info_res(info);
+       kfree(info);
+}
+
+static void release_pci_root_info(struct pci_host_bridge *bridge)
+{
+       struct pci_root_info *info = bridge->release_data;
+
+       __release_pci_root_info(info);
+}
+
+static int
+probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
+               int busnum, int domain)
+{
+       char *name;
+
+       name = kmalloc(16, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
+       sprintf(name, "PCI Bus %04x:%02x", domain, busnum);
+       info->bridge = device;
+       info->name = name;
+
+       acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
+                       &info->res_num);
+       if (info->res_num) {
+               info->res =
+                       kzalloc_node(sizeof(*info->res) * info->res_num,
+                                    GFP_KERNEL, info->controller->node);
+               if (!info->res) {
+                       kfree(name);
+                       return -ENOMEM;
+               }
+
+               info->res_offset =
+                       kzalloc_node(sizeof(*info->res_offset) * info->res_num,
+                                       GFP_KERNEL, info->controller->node);
+               if (!info->res_offset) {
+                       kfree(name);
+                       kfree(info->res);
+                       info->res = NULL;
+                       return -ENOMEM;
+               }
+
+               info->res_num = 0;
+               acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+                       add_window, info);
+       } else
+               kfree(name);
+
+       return 0;
+}
+
 struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
        struct acpi_device *device = root->device;
        int domain = root->segment;
        int bus = root->secondary.start;
        struct pci_controller *controller;
-       unsigned int windows = 0;
-       struct pci_root_info info;
+       struct pci_root_info *info = NULL;
+       int busnum = root->secondary.start;
        struct pci_bus *pbus;
-       char *name;
-       int pxm;
+       int pxm, ret;
 
        controller = alloc_pci_controller(domain);
        if (!controller)
-               goto out1;
+               return NULL;
 
        controller->acpi_handle = device->handle;
 
@@ -347,29 +444,27 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
                controller->node = pxm_to_node(pxm);
 #endif
 
-       INIT_LIST_HEAD(&info.resources);
-       /* insert busn resource at first */
-       pci_add_resource(&info.resources, &root->secondary);
-       acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
-                       &windows);
-       if (windows) {
-               controller->window =
-                       kzalloc_node(sizeof(*controller->window) * windows,
-                                    GFP_KERNEL, controller->node);
-               if (!controller->window)
-                       goto out2;
-
-               name = kmalloc(16, GFP_KERNEL);
-               if (!name)
-                       goto out3;
-
-               sprintf(name, "PCI Bus %04x:%02x", domain, bus);
-               info.bridge = device;
-               info.controller = controller;
-               info.name = name;
-               acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-                       add_window, &info);
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               dev_err(&device->dev,
+                               "pci_bus %04x:%02x: ignored (out of memory)\n",
+                               domain, busnum);
+               kfree(controller);
+               return NULL;
        }
+
+       info->controller = controller;
+       INIT_LIST_HEAD(&info->io_resources);
+       INIT_LIST_HEAD(&info->resources);
+
+       ret = probe_pci_root_info(info, device, busnum, domain);
+       if (ret) {
+               kfree(info->controller);
+               kfree(info);
+               return NULL;
+       }
+       /* insert busn resource at first */
+       pci_add_resource(&info->resources, &root->secondary);
        /*
         * See arch/x86/pci/acpi.c.
         * The desired pci bus might already be scanned in a quirk. We
@@ -377,21 +472,17 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
         * such quirk. So we just ignore the case now.
         */
        pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller,
-                                  &info.resources);
+                                  &info->resources);
        if (!pbus) {
-               pci_free_resource_list(&info.resources);
+               pci_free_resource_list(&info->resources);
+               __release_pci_root_info(info);
                return NULL;
        }
 
+       pci_set_host_bridge_release(to_pci_host_bridge(pbus->bridge),
+                       release_pci_root_info, info);
        pci_scan_child_bus(pbus);
        return pbus;
-
-out3:
-       kfree(controller->window);
-out2:
-       kfree(controller);
-out1:
-       return NULL;
 }
 
 int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
@@ -691,7 +782,7 @@ static void __init set_pci_dfl_cacheline_size(void)
 
        status = ia64_pal_cache_summary(&levels, &unique_caches);
        if (status != 0) {
-               printk(KERN_ERR "%s: ia64_pal_cache_summary() failed "
+               pr_err("%s: ia64_pal_cache_summary() failed "
                        "(status=%ld)\n", __func__, status);
                return;
        }
@@ -699,7 +790,7 @@ static void __init set_pci_dfl_cacheline_size(void)
        status = ia64_pal_cache_config_info(levels - 1,
                                /* cache_type (data_or_unified)= */ 2, &cci);
        if (status != 0) {
-               printk(KERN_ERR "%s: ia64_pal_cache_config_info() failed "
+               pr_err("%s: ia64_pal_cache_config_info() failed "
                        "(status=%ld)\n", __func__, status);
                return;
        }
index 238e2c511d94e735fb823cb612d30a7333a28510..0b5ce82d203dd5a908d01609b6f7377d2053161d 100644 (file)
@@ -118,76 +118,26 @@ static void __init sn_fixup_ionodes(void)
 }
 
 /*
- * sn_pci_legacy_window_fixup - Create PCI controller windows for
+ * sn_pci_legacy_window_fixup - Setup PCI resources for
  *                             legacy IO and MEM space. This needs to
  *                             be done here, as the PROM does not have
  *                             ACPI support defining the root buses
  *                             and their resources (_CRS),
  */
 static void
-sn_legacy_pci_window_fixup(struct pci_controller *controller,
-                          u64 legacy_io, u64 legacy_mem)
+sn_legacy_pci_window_fixup(struct resource *res,
+               u64 legacy_io, u64 legacy_mem)
 {
-               controller->window = kcalloc(2, sizeof(struct pci_window),
-                                            GFP_KERNEL);
-               BUG_ON(controller->window == NULL);
-               controller->window[0].offset = legacy_io;
-               controller->window[0].resource.name = "legacy_io";
-               controller->window[0].resource.flags = IORESOURCE_IO;
-               controller->window[0].resource.start = legacy_io;
-               controller->window[0].resource.end =
-                               controller->window[0].resource.start + 0xffff;
-               controller->window[0].resource.parent = &ioport_resource;
-               controller->window[1].offset = legacy_mem;
-               controller->window[1].resource.name = "legacy_mem";
-               controller->window[1].resource.flags = IORESOURCE_MEM;
-               controller->window[1].resource.start = legacy_mem;
-               controller->window[1].resource.end =
-                      controller->window[1].resource.start + (1024 * 1024) - 1;
-               controller->window[1].resource.parent = &iomem_resource;
-               controller->windows = 2;
-}
-
-/*
- * sn_pci_window_fixup() - Create a pci_window for each device resource.
- *                        It will setup pci_windows for use by
- *                        pcibios_bus_to_resource(), pcibios_resource_to_bus(),
- *                        etc.
- */
-static void
-sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
-                   s64 * pci_addrs)
-{
-       struct pci_controller *controller = PCI_CONTROLLER(dev->bus);
-       unsigned int i;
-       unsigned int idx;
-       unsigned int new_count;
-       struct pci_window *new_window;
-
-       if (count == 0)
-               return;
-       idx = controller->windows;
-       new_count = controller->windows + count;
-       new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL);
-       BUG_ON(new_window == NULL);
-       if (controller->window) {
-               memcpy(new_window, controller->window,
-                      sizeof(struct pci_window) * controller->windows);
-               kfree(controller->window);
-       }
-
-       /* Setup a pci_window for each device resource. */
-       for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
-               if (pci_addrs[i] == -1)
-                       continue;
-
-               new_window[idx].offset = dev->resource[i].start - pci_addrs[i];
-               new_window[idx].resource = dev->resource[i];
-               idx++;
-       }
-
-       controller->windows = new_count;
-       controller->window = new_window;
+               res[0].name = "legacy_io";
+               res[0].flags = IORESOURCE_IO;
+               res[0].start = legacy_io;
+               res[0].end = res[0].start + 0xffff;
+               res[0].parent = &ioport_resource;
+               res[1].name = "legacy_mem";
+               res[1].flags = IORESOURCE_MEM;
+               res[1].start = legacy_mem;
+               res[1].end = res[1].start + (1024 * 1024) - 1;
+               res[1].parent = &iomem_resource;
 }
 
 /*
@@ -199,9 +149,7 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
 void
 sn_io_slot_fixup(struct pci_dev *dev)
 {
-       unsigned int count = 0;
        int idx;
-       s64 pci_addrs[PCI_ROM_RESOURCE + 1];
        unsigned long addr, end, size, start;
        struct pcidev_info *pcidev_info;
        struct sn_irq_info *sn_irq_info;
@@ -229,7 +177,6 @@ sn_io_slot_fixup(struct pci_dev *dev)
        for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
 
                if (!pcidev_info->pdi_pio_mapped_addr[idx]) {
-                       pci_addrs[idx] = -1;
                        continue;
                }
 
@@ -237,11 +184,8 @@ sn_io_slot_fixup(struct pci_dev *dev)
                end = dev->resource[idx].end;
                size = end - start;
                if (size == 0) {
-                       pci_addrs[idx] = -1;
                        continue;
                }
-               pci_addrs[idx] = start;
-               count++;
                addr = pcidev_info->pdi_pio_mapped_addr[idx];
                addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET;
                dev->resource[idx].start = addr;
@@ -276,11 +220,6 @@ sn_io_slot_fixup(struct pci_dev *dev)
                                                 IORESOURCE_ROM_BIOS_COPY;
                }
        }
-       /* Create a pci_window in the pci_controller struct for
-        * each device resource.
-        */
-       if (count > 0)
-               sn_pci_window_fixup(dev, count, pci_addrs);
 
        sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
 }
@@ -297,8 +236,8 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        s64 status = 0;
        struct pci_controller *controller;
        struct pcibus_bussoft *prom_bussoft_ptr;
+       struct resource *res;
        LIST_HEAD(resources);
-       int i;
 
        status = sal_get_pcibus_info((u64) segment, (u64) busnum,
                                     (u64) ia64_tpa(&prom_bussoft_ptr));
@@ -310,32 +249,29 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
        BUG_ON(!controller);
        controller->segment = segment;
 
+       res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
+       BUG_ON(!res);
+
        /*
         * Temporarily save the prom_bussoft_ptr for use by sn_bus_fixup().
         * (platform_data will be overwritten later in sn_common_bus_fixup())
         */
        controller->platform_data = prom_bussoft_ptr;
 
-       sn_legacy_pci_window_fixup(controller,
-                                  prom_bussoft_ptr->bs_legacy_io,
-                                  prom_bussoft_ptr->bs_legacy_mem);
-       for (i = 0; i < controller->windows; i++)
-               pci_add_resource_offset(&resources,
-                                       &controller->window[i].resource,
-                                       controller->window[i].offset);
+       sn_legacy_pci_window_fixup(res,
+                       prom_bussoft_ptr->bs_legacy_io,
+                       prom_bussoft_ptr->bs_legacy_mem);
+       pci_add_resource_offset(&resources,     &res[0],
+                       prom_bussoft_ptr->bs_legacy_io);
+       pci_add_resource_offset(&resources,     &res[1],
+                       prom_bussoft_ptr->bs_legacy_mem);
+
        bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller,
                                &resources);
-       if (bus == NULL)
-               goto error_return; /* error, or bus already scanned */
-
-       bus->sysdata = controller;
-
-       return;
-
-error_return:
-
-       kfree(controller);
-       return;
+       if (bus == NULL) {
+               kfree(res);
+               kfree(controller);
+       }
 }
 
 /*
index f82e7b462b7b1e3774dc8fe7d195a9426df23e3f..53b01b8e2f197129819c4a8f937073556a9690c0 100644 (file)
@@ -192,7 +192,7 @@ void __init early_sn_setup(void)
 }
 
 extern int platform_intr_list[];
-static int __cpuinitdata shub_1_1_found;
+static int shub_1_1_found;
 
 /*
  * sn_check_for_wars
@@ -200,7 +200,7 @@ static int __cpuinitdata shub_1_1_found;
  * Set flag for enabling shub specific wars
  */
 
-static inline int __cpuinit is_shub_1_1(int nasid)
+static inline int is_shub_1_1(int nasid)
 {
        unsigned long id;
        int rev;
@@ -212,7 +212,7 @@ static inline int __cpuinit is_shub_1_1(int nasid)
        return rev <= 2;
 }
 
-static void __cpuinit sn_check_for_wars(void)
+static void sn_check_for_wars(void)
 {
        int cnode;
 
@@ -558,7 +558,7 @@ static void __init sn_init_pdas(char **cmdline_p)
  * Also sets up a few fields in the nodepda.  Also known as
  * platform_cpu_init() by the ia64 machvec code.
  */
-void __cpuinit sn_cpu_init(void)
+void sn_cpu_init(void)
 {
        int cpuid;
        int cpuphyid;
index 52172eee85913055d11bc1b0a33834d73cb45aae..fab62528a80b4245e2a66a711f732912189e13cc 100644 (file)
@@ -74,7 +74,7 @@ void __init xen_setup_vcpu_info_placement(void)
                xen_vcpu_setup(cpu);
 }
 
-void __cpuinit
+void
 xen_cpu_init(void)
 {
        xen_smp_intr_init();
index 1c7047bea2002b013ab779a8c752654b9a2a9c23..84fe7ba53035dd3ec5b72c417fcab940b0427106 100644 (file)
@@ -216,7 +216,7 @@ extern int fixup_exception(struct pt_regs *regs);
 ({                                                                     \
        long __gu_err = 0;                                              \
        unsigned long __gu_val;                                         \
-       might_sleep();                                                  \
+       might_fault();                                                  \
        __get_user_size(__gu_val,(ptr),(size),__gu_err);                \
        (x) = (__typeof__(*(ptr)))__gu_val;                             \
        __gu_err;                                                       \
@@ -227,7 +227,7 @@ extern int fixup_exception(struct pt_regs *regs);
        long __gu_err = -EFAULT;                                        \
        unsigned long __gu_val = 0;                                     \
        const __typeof__(*(ptr)) __user *__gu_addr = (ptr);             \
-       might_sleep();                                                  \
+       might_fault();                                                  \
        if (access_ok(VERIFY_READ,__gu_addr,size))                      \
                __get_user_size(__gu_val,__gu_addr,(size),__gu_err);    \
        (x) = (__typeof__(*(ptr)))__gu_val;                             \
@@ -295,7 +295,7 @@ do {                                                                        \
 #define __put_user_nocheck(x,ptr,size)                                 \
 ({                                                                     \
        long __pu_err;                                                  \
-       might_sleep();                                                  \
+       might_fault();                                                  \
        __put_user_size((x),(ptr),(size),__pu_err);                     \
        __pu_err;                                                       \
 })
@@ -305,7 +305,7 @@ do {                                                                        \
 ({                                                                     \
        long __pu_err = -EFAULT;                                        \
        __typeof__(*(ptr)) __user *__pu_addr = (ptr);                   \
-       might_sleep();                                                  \
+       might_fault();                                                  \
        if (access_ok(VERIFY_WRITE,__pu_addr,size))                     \
                __put_user_size((x),__pu_addr,(size),__pu_err);         \
        __pu_err;                                                       \
@@ -597,7 +597,7 @@ unsigned long __generic_copy_from_user(void *, const void __user *, unsigned lon
  */
 #define copy_to_user(to,from,n)                                \
 ({                                                     \
-       might_sleep();                                  \
+       might_fault();                                  \
        __generic_copy_to_user((to),(from),(n));        \
 })
 
@@ -638,7 +638,7 @@ unsigned long __generic_copy_from_user(void *, const void __user *, unsigned lon
  */
 #define copy_from_user(to,from,n)                      \
 ({                                                     \
-       might_sleep();                                  \
+       might_fault();                                  \
        __generic_copy_from_user((to),(from),(n));      \
 })
 
index 2c468e8b5853203099f2125c081d81fd9b6b665e..27196303ce36e3ba9c83e8574a99f2d0a36717b2 100644 (file)
@@ -129,11 +129,10 @@ unsigned long __init setup_memory(void)
 #define START_PFN(nid)         (NODE_DATA(nid)->bdata->node_min_pfn)
 #define MAX_LOW_PFN(nid)       (NODE_DATA(nid)->bdata->node_low_pfn)
 
-unsigned long __init zone_sizes_init(void)
+void __init zone_sizes_init(void)
 {
        unsigned long zones_size[MAX_NR_ZONES], zholes_size[MAX_NR_ZONES];
        unsigned long low, start_pfn;
-       unsigned long holes = 0;
        int nid, i;
        mem_prof_t *mp;
 
@@ -147,7 +146,6 @@ unsigned long __init zone_sizes_init(void)
                low = MAX_LOW_PFN(nid);
                zones_size[ZONE_DMA] = low - start_pfn;
                zholes_size[ZONE_DMA] = mp->holes;
-               holes += zholes_size[ZONE_DMA];
 
                node_set_state(nid, N_NORMAL_MEMORY);
                free_area_init_node(nid, zones_size, start_pfn, zholes_size);
@@ -161,6 +159,4 @@ unsigned long __init zone_sizes_init(void)
        NODE_DATA(1)->node_zones->watermark[WMARK_MIN] = 0;
        NODE_DATA(1)->node_zones->watermark[WMARK_LOW] = 0;
        NODE_DATA(1)->node_zones->watermark[WMARK_HIGH] = 0;
-
-       return holes;
 }
index ab4cbce91a9bfa40acabdc13776b7bbef5fc21c2..0d4146f644dc01fe3323bb35b6f654e61016b671 100644 (file)
@@ -40,7 +40,6 @@ unsigned long mmu_context_cache_dat;
 #else
 unsigned long mmu_context_cache_dat[NR_CPUS];
 #endif
-static unsigned long hole_pages;
 
 /*
  * function prototype
@@ -57,7 +56,7 @@ void free_initrd_mem(unsigned long, unsigned long);
 #define MAX_LOW_PFN(nid)       (NODE_DATA(nid)->bdata->node_low_pfn)
 
 #ifndef CONFIG_DISCONTIGMEM
-unsigned long __init zone_sizes_init(void)
+void __init zone_sizes_init(void)
 {
        unsigned long  zones_size[MAX_NR_ZONES] = {0, };
        unsigned long  max_dma;
@@ -83,11 +82,9 @@ unsigned long __init zone_sizes_init(void)
 #endif /* CONFIG_MMU */
 
        free_area_init_node(0, zones_size, start_pfn, 0);
-
-       return 0;
 }
 #else  /* CONFIG_DISCONTIGMEM */
-extern unsigned long zone_sizes_init(void);
+extern void zone_sizes_init(void);
 #endif /* CONFIG_DISCONTIGMEM */
 
 /*======================================================================*
@@ -105,24 +102,7 @@ void __init paging_init(void)
        for (i = 0 ; i < USER_PTRS_PER_PGD * 2 ; i++)
                pgd_val(pg_dir[i]) = 0;
 #endif /* CONFIG_MMU */
-       hole_pages = zone_sizes_init();
-}
-
-int __init reservedpages_count(void)
-{
-       int reservedpages, nid, i;
-
-       reservedpages = 0;
-       for_each_online_node(nid) {
-               unsigned long flags;
-               pgdat_resize_lock(NODE_DATA(nid), &flags);
-               for (i = 0 ; i < MAX_LOW_PFN(nid) - START_PFN(nid) ; i++)
-                       if (PageReserved(nid_page_nr(nid, i)))
-                               reservedpages++;
-               pgdat_resize_unlock(NODE_DATA(nid), &flags);
-       }
-
-       return reservedpages;
+       zone_sizes_init();
 }
 
 /*======================================================================*
@@ -131,48 +111,20 @@ int __init reservedpages_count(void)
  *======================================================================*/
 void __init mem_init(void)
 {
-       int codesize, reservedpages, datasize, initsize;
-       int nid;
 #ifndef CONFIG_MMU
        extern unsigned long memory_end;
-#endif
-
-       num_physpages = 0;
-       for_each_online_node(nid)
-               num_physpages += MAX_LOW_PFN(nid) - START_PFN(nid) + 1;
-
-       num_physpages -= hole_pages;
 
-#ifndef CONFIG_DISCONTIGMEM
-       max_mapnr = num_physpages;
-#endif /* CONFIG_DISCONTIGMEM */
-
-#ifdef CONFIG_MMU
-       high_memory = (void *)__va(PFN_PHYS(MAX_LOW_PFN(0)));
-#else
        high_memory = (void *)(memory_end & PAGE_MASK);
+#else
+       high_memory = (void *)__va(PFN_PHYS(MAX_LOW_PFN(0)));
 #endif /* CONFIG_MMU */
 
        /* clear the zero-page */
        memset(empty_zero_page, 0, PAGE_SIZE);
 
-       /* this will put all low memory onto the freelists */
-       for_each_online_node(nid)
-               totalram_pages += free_all_bootmem_node(NODE_DATA(nid));
-
-       reservedpages = reservedpages_count() - hole_pages;
-       codesize = (unsigned long) &_etext - (unsigned long)&_text;
-       datasize = (unsigned long) &_edata - (unsigned long)&_etext;
-       initsize = (unsigned long) &__init_end - (unsigned long)&__init_begin;
-
-       printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
-               "%dk reserved, %dk data, %dk init)\n",
-               nr_free_pages() << (PAGE_SHIFT-10),
-               num_physpages << (PAGE_SHIFT-10),
-               codesize >> 10,
-               reservedpages << (PAGE_SHIFT-10),
-               datasize >> 10,
-               initsize >> 10);
+       set_max_mapnr(get_num_physpages());
+       free_all_bootmem();
+       mem_init_print_info(NULL);
 }
 
 /*======================================================================*
@@ -181,7 +133,7 @@ void __init mem_init(void)
  *======================================================================*/
 void free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -191,6 +143,6 @@ void free_initmem(void)
  *======================================================================*/
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
index fa12283d58fccdd0f92638ff75996bf8debc845a..229682721240a8a4193d3308335b611660722e3a 100644 (file)
@@ -11,9 +11,8 @@ config BOOTPARAM_STRING
        depends on BOOTPARAM
 
 config EARLY_PRINTK
-       bool "Early printk" if EMBEDDED
+       bool "Early printk"
        depends on MVME16x || MAC
-       default y
        help
           Write kernel log output directly to a serial port.
 
index 0f795d8e65fafbc28b9d765911ac2416db5f3c6c..b17a8837f0e1016b273e5f74c6f75803a1e372b8 100644 (file)
@@ -214,6 +214,7 @@ CONFIG_DEVTMPFS=y
 # CONFIG_FW_LOADER_USER_HELPER is not set
 CONFIG_CONNECTOR=m
 CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
 CONFIG_PARPORT_AMIGA=m
 CONFIG_PARPORT_MFC3=m
 CONFIG_PARPORT_ATARI=m
@@ -325,6 +326,7 @@ CONFIG_ZORRO8390=y
 # CONFIG_NET_VENDOR_SEEQ is not set
 # CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PLIP=m
 CONFIG_PPP=m
 CONFIG_PPP_BSDCOMP=m
 CONFIG_PPP_DEFLATE=m
index 8982370e8b42166a96637687c0aa9bbe0ddc5731..be1496ed9b66028655205c48a36b69a365ed203b 100644 (file)
@@ -199,6 +199,9 @@ CONFIG_DEVTMPFS=y
 # CONFIG_FIRMWARE_IN_KERNEL is not set
 # CONFIG_FW_LOADER_USER_HELPER is not set
 CONFIG_CONNECTOR=m
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_1284=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_DRBD=m
@@ -267,6 +270,7 @@ CONFIG_NE2000=m
 # CONFIG_NET_VENDOR_SMSC is not set
 # CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PLIP=m
 CONFIG_PPP=m
 CONFIG_PPP_BSDCOMP=m
 CONFIG_PPP_DEFLATE=m
@@ -292,9 +296,11 @@ CONFIG_SERIO_Q40KBD=y
 CONFIG_VT_HW_CONSOLE_BINDING=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
+CONFIG_PRINTER=m
 # CONFIG_HW_RANDOM is not set
 CONFIG_NTP_PPS=y
 CONFIG_PPS_CLIENT_LDISC=m
+CONFIG_PPS_CLIENT_PARPORT=m
 CONFIG_PTP_1588_CLOCK=m
 # CONFIG_HWMON is not set
 CONFIG_FB=y
index 5ea75e6a7399a3a58b7837177af6cc7c2c6120f1..c85cece778e8fdefc7c697a4704c9b1cb00b713f 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef _ASM_M68K_PARPORT_H
 #define _ASM_M68K_PARPORT_H 1
 
+#undef insl
+#undef outsl
 #define insl(port,buf,len)   isa_insb(port,buf,(len)<<2)
 #define outsl(port,buf,len)  isa_outsb(port,buf,(len)<<2)
 
index 9aea9f11fa25e60b5cf28267440b0a873087945b..c30c03d985815a83978cd583c07e7bd3b1bb76ad 100644 (file)
@@ -4,20 +4,6 @@
 #include <linux/types.h>
 #include <linux/compiler.h>
 
-static inline char *__kernel_strcpy(char *dest, const char *src)
-{
-       char *xdest = dest;
-
-       asm volatile ("\n"
-               "1:     move.b  (%1)+,(%0)+\n"
-               "       jne     1b"
-               : "+a" (dest), "+a" (src)
-               : : "memory");
-       return xdest;
-}
-
-#ifndef __IN_STRING_C
-
 #define __HAVE_ARCH_STRNLEN
 static inline size_t strnlen(const char *s, size_t count)
 {
@@ -34,16 +20,6 @@ static inline size_t strnlen(const char *s, size_t count)
        return sc - s;
 }
 
-#define __HAVE_ARCH_STRCPY
-#if __GNUC__ >= 4
-#define strcpy(d, s)   (__builtin_constant_p(s) &&     \
-                        __builtin_strlen(s) <= 32 ?    \
-                        __builtin_strcpy(d, s) :       \
-                        __kernel_strcpy(d, s))
-#else
-#define strcpy(d, s)   __kernel_strcpy(d, s)
-#endif
-
 #define __HAVE_ARCH_STRNCPY
 static inline char *strncpy(char *dest, const char *src, size_t n)
 {
@@ -61,12 +37,6 @@ static inline char *strncpy(char *dest, const char *src, size_t n)
        return xdest;
 }
 
-#define __HAVE_ARCH_STRCAT
-#define strcat(d, s)   ({                      \
-       char *__d = (d);                        \
-       strcpy(__d + strlen(__d), (s));         \
-})
-
 #ifndef CONFIG_COLDFIRE
 #define __HAVE_ARCH_STRCMP
 static inline int strcmp(const char *cs, const char *ct)
@@ -100,6 +70,4 @@ extern void *memset(void *, int, __kernel_size_t);
 extern void *memcpy(void *, const void *, __kernel_size_t);
 #define memcpy(d, s, n) __builtin_memcpy(d, s, n)
 
-#endif
-
 #endif /* _M68K_STRING_H_ */
index 472c891a4aeee4c1f1bc095b2e33b08840c5a6c2..15901db435b90675dd5ab9f931dc331632c04705 100644 (file)
@@ -90,7 +90,7 @@ asm volatile ("\n"                                    \
                __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \
                break;                                                  \
        case 2:                                                         \
-               __put_user_asm(__pu_err, __pu_val, ptr, w, d, -EFAULT); \
+               __put_user_asm(__pu_err, __pu_val, ptr, w, r, -EFAULT); \
                break;                                                  \
        case 4:                                                         \
                __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
@@ -158,7 +158,7 @@ asm volatile ("\n"                                  \
                __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT);    \
                break;                                                  \
        case 2:                                                         \
-               __get_user_asm(__gu_err, x, ptr, u16, w, d, -EFAULT);   \
+               __get_user_asm(__gu_err, x, ptr, u16, w, r, -EFAULT);   \
                break;                                                  \
        case 4:                                                         \
                __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT);   \
@@ -245,7 +245,7 @@ __constant_copy_from_user(void *to, const void __user *from, unsigned long n)
                __get_user_asm(res, *(u8 *)to, (u8 __user *)from, u8, b, d, 1);
                break;
        case 2:
-               __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, d, 2);
+               __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, r, 2);
                break;
        case 3:
                __constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,);
@@ -326,7 +326,7 @@ __constant_copy_to_user(void __user *to, const void *from, unsigned long n)
                __put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1);
                break;
        case 2:
-               __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, d, 2);
+               __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, r, 2);
                break;
        case 3:
                __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
index a972b00cd77d7e699ae0c0fcb5f053bfac19f78c..8b7b228463667da0145f9d7e821172553822d20d 100644 (file)
@@ -77,7 +77,7 @@ int main(void)
        DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
        DEFINE(BIR_DATA, offsetof(struct bi_record, data));
 
-       /* offsets into font_desc (drivers/video/console/font.h) */
+       /* offsets into the font_desc struct */
        DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
        DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
        DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
index 6b32b64bac35ffb7022d1a1cebcd7b971fc2fd3e..4d7da384eea03d5a1101859a5814c7dccce53a9e 100644 (file)
@@ -101,7 +101,7 @@ void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt)
        BUG_ON(IRQ_USER + cnt > NR_IRQS);
        m68k_first_user_vec = vec;
        for (i = 0; i < cnt; i++)
-               irq_set_chip(IRQ_USER + i, &user_irq_chip);
+               irq_set_chip_and_handler(i, &user_irq_chip, handle_simple_irq);
        *user_irqvec_fixup = vec - IRQ_USER;
        flush_icache();
 }
index a9d782d34276c427cac22538cccefa47d8d24d11..fcd8eb1d7c7d268a4a30978d0923a14544b4d4e8 100644 (file)
@@ -6,7 +6,7 @@
 lib-y  := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
           memcpy.o memset.o memmove.o
 
-lib-$(CONFIG_MMU) += string.o uaccess.o
+lib-$(CONFIG_MMU) += uaccess.o
 lib-$(CONFIG_CPU_HAS_NO_MULDIV64) += mulsi3.o divsi3.o udivsi3.o
 lib-$(CONFIG_CPU_HAS_NO_MULDIV64) += modsi3.o umodsi3.o
 
diff --git a/arch/m68k/lib/string.c b/arch/m68k/lib/string.c
deleted file mode 100644 (file)
index 4d61fa8..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#define __IN_STRING_C
-
-#include <linux/module.h>
-#include <linux/string.h>
-
-char *strcpy(char *dest, const char *src)
-{
-       return __kernel_strcpy(dest, src);
-}
-EXPORT_SYMBOL(strcpy);
-
-char *strcat(char *dest, const char *src)
-{
-       return __kernel_strcpy(dest + strlen(dest), src);
-}
-EXPORT_SYMBOL(strcat);
index 5e97f2ee7c1197feaf1fb79ec07cd10566466026..35d1442dee899af023a2e801401f8dc319272779 100644 (file)
@@ -52,7 +52,7 @@ unsigned long __generic_copy_from_user(void *to, const void __user *from,
                "       .long   3b,30b\n"
                "       .long   5b,50b\n"
                "       .previous"
-               : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp)
+               : "=d" (res), "+a" (from), "+a" (to), "=&d" (tmp)
                : "0" (n / 4), "d" (n & 3));
 
        return res;
@@ -96,7 +96,7 @@ unsigned long __generic_copy_to_user(void __user *to, const void *from,
                "       .long   7b,50b\n"
                "       .long   8b,50b\n"
                "       .previous"
-               : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp)
+               : "=d" (res), "+a" (from), "+a" (to), "=&d" (tmp)
                : "0" (n / 4), "d" (n & 3));
 
        return res;
@@ -141,7 +141,7 @@ unsigned long __clear_user(void __user *to, unsigned long n)
                "       .long   7b,40b\n"
                "       .previous"
                : "=d" (res), "+a" (to)
-               : "r" (0), "0" (n / 4), "d" (n & 3));
+               : "d" (0), "0" (n / 4), "d" (n & 3));
 
     return res;
 }
index 08f286db3c5af889f87e6a19c2aae24719f58c5c..239eb1990184721df8e748045f7640c76fc2ab59 100644 (file)
@@ -519,7 +519,7 @@ static void fp_roundint(struct fp_ext *dest, int mode)
                                return;
                        break;
                case 0x401e:
-                       if (!(oldmant.m32[1] >= 0))
+                       if (oldmant.m32[1] & 0x80000000)
                                return;
                        if (oldmant.m32[0] & 1)
                                break;
index 1af2ca3411f6dbb8cd6fc23323951f6f979af168..6b4baa6e4d31d8f24e09950d581f6ae9ab1cc6dd 100644 (file)
@@ -110,7 +110,7 @@ void __init paging_init(void)
 void free_initmem(void)
 {
 #ifndef CONFIG_MMU_SUN3
-       free_initmem_default(0);
+       free_initmem_default(-1);
 #endif /* CONFIG_MMU_SUN3 */
 }
 
@@ -146,38 +146,11 @@ void __init print_memmap(void)
                MLK_ROUNDUP(__bss_start, __bss_stop));
 }
 
-void __init mem_init(void)
+static inline void init_pointer_tables(void)
 {
-       pg_data_t *pgdat;
-       int codepages = 0;
-       int datapages = 0;
-       int initpages = 0;
+#if defined(CONFIG_MMU) && !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE)
        int i;
 
-       /* this will put all memory onto the freelists */
-       totalram_pages = num_physpages = 0;
-       for_each_online_pgdat(pgdat) {
-               num_physpages += pgdat->node_present_pages;
-
-               totalram_pages += free_all_bootmem_node(pgdat);
-               for (i = 0; i < pgdat->node_spanned_pages; i++) {
-                       struct page *page = pgdat->node_mem_map + i;
-                       char *addr = page_to_virt(page);
-
-                       if (!PageReserved(page))
-                               continue;
-                       if (addr >= _text &&
-                           addr < _etext)
-                               codepages++;
-                       else if (addr >= __init_begin &&
-                                addr < __init_end)
-                               initpages++;
-                       else
-                               datapages++;
-               }
-       }
-
-#if defined(CONFIG_MMU) && !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE)
        /* insert pointer tables allocated so far into the tablelist */
        init_pointer_table((unsigned long)kernel_pg_dir);
        for (i = 0; i < PTRS_PER_PGD; i++) {
@@ -189,19 +162,20 @@ void __init mem_init(void)
        if (zero_pgtable)
                init_pointer_table((unsigned long)zero_pgtable);
 #endif
+}
 
-       pr_info("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
-              nr_free_pages() << (PAGE_SHIFT-10),
-              totalram_pages << (PAGE_SHIFT-10),
-              codepages << (PAGE_SHIFT-10),
-              datapages << (PAGE_SHIFT-10),
-              initpages << (PAGE_SHIFT-10));
+void __init mem_init(void)
+{
+       /* this will put all memory onto the freelists */
+       free_all_bootmem();
+       init_pointer_tables();
+       mem_init_print_info(NULL);
        print_memmap();
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
index 8572246db84d3fe35d9075a5157e42a3e0eb1e2e..b33f97a13e6d11650db6f5a183511356884ae51e 100644 (file)
@@ -320,7 +320,6 @@ static int __init mcf_pci_init(void)
        pci_bus_size_bridges(rootbus);
        pci_bus_assign_resources(rootbus);
        pci_enable_bridges(rootbus);
-       pci_bus_add_devices(rootbus);
        return 0;
 }
 
index ca0966cac72adfe68cf6eef8b680c395ee7eea5d..cab54482ca34b97fa4412eaaaa4a0ee31d173833 100644 (file)
@@ -275,7 +275,7 @@ void dvma_init(void)
 
 }
 
-inline unsigned long dvma_map_align(unsigned long kaddr, int len, int align)
+unsigned long dvma_map_align(unsigned long kaddr, int len, int align)
 {
 
        unsigned long baddr;
index 366569425c52a5febc1a7256cf68137365b85227..5b18888ee3648d5575e911499c3fd14c07260e99 100644 (file)
@@ -882,7 +882,7 @@ static int __init init_hw_perf_events(void)
        }
 
        register_cpu_notifier(&metag_pmu_notifier);
-       ret = perf_pmu_register(&pmu, (char *)metag_pmu->name, PERF_TYPE_RAW);
+       ret = perf_pmu_register(&pmu, metag_pmu->name, PERF_TYPE_RAW);
 out:
        return ret;
 }
index d05b8455c44cb9ac356c33da7473478c7047c44d..28813f164730f7110ccf470d6ef610932f166580 100644 (file)
@@ -376,34 +376,21 @@ void __init paging_init(unsigned long mem_end)
 
 void __init mem_init(void)
 {
-       int nid;
-
 #ifdef CONFIG_HIGHMEM
        unsigned long tmp;
+
+       /*
+        * Explicitly reset zone->managed_pages because highmem pages are
+        * freed before calling free_all_bootmem();
+        */
+       reset_all_zones_managed_pages();
        for (tmp = highstart_pfn; tmp < highend_pfn; tmp++)
                free_highmem_page(pfn_to_page(tmp));
-       num_physpages += totalhigh_pages;
 #endif /* CONFIG_HIGHMEM */
 
-       for_each_online_node(nid) {
-               pg_data_t *pgdat = NODE_DATA(nid);
-               unsigned long node_pages = 0;
-
-               num_physpages += pgdat->node_present_pages;
-
-               if (pgdat->node_spanned_pages)
-                       node_pages = free_all_bootmem_node(pgdat);
-
-               totalram_pages += node_pages;
-       }
-
-       pr_info("Memory: %luk/%luk available\n",
-               (unsigned long)nr_free_pages() << (PAGE_SHIFT - 10),
-               num_physpages << (PAGE_SHIFT - 10));
-
+       free_all_bootmem();
+       mem_init_print_info(NULL);
        show_mem(0);
-
-       return;
 }
 
 void free_initmem(void)
@@ -414,7 +401,8 @@ void free_initmem(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
+       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+                          "initrd");
 }
 #endif
 
index 85a5ae8e9bd04f5f3360b562ea03875c15e5e31a..fd850879854dff3f79a73effd5fc782e9bd203d8 100644 (file)
@@ -168,7 +168,6 @@ extern int page_is_ram(unsigned long pfn);
 #  else /* CONFIG_MMU */
 #  define ARCH_PFN_OFFSET      (memory_start >> PAGE_SHIFT)
 #  define pfn_valid(pfn)       ((pfn) < (max_mapnr + ARCH_PFN_OFFSET))
-#  define VALID_PAGE(page)     ((page - mem_map) < max_mapnr)
 #  endif /* CONFIG_MMU */
 
 # endif /* __ASSEMBLY__ */
index 04e49553bdf978c534519550382a5dca8e98e6ed..0aa005703a0b5f348848afb5936f650d18f28322 100644 (file)
@@ -145,7 +145,7 @@ static inline unsigned long __must_check __clear_user(void __user *to,
 static inline unsigned long __must_check clear_user(void __user *to,
                                                        unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (unlikely(!access_ok(VERIFY_WRITE, to, n)))
                return n;
 
@@ -371,7 +371,7 @@ extern long __user_bad(void);
 static inline long copy_from_user(void *to,
                const void __user *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (access_ok(VERIFY_READ, from, n))
                return __copy_from_user(to, from, n);
        return n;
@@ -385,7 +385,7 @@ static inline long copy_from_user(void *to,
 static inline long copy_to_user(void __user *to,
                const void *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (access_ok(VERIFY_WRITE, to, n))
                return __copy_to_user(to, from, n);
        return n;
index b38ae3acfeb45adbe98f95c05c9c52e42721a215..74c7bcc1e82d8da05b6775274f572fe17114d5f0 100644 (file)
@@ -71,24 +71,17 @@ static void __init highmem_init(void)
        kmap_prot = PAGE_KERNEL;
 }
 
-static unsigned long highmem_setup(void)
+static void highmem_setup(void)
 {
        unsigned long pfn;
-       unsigned long reservedpages = 0;
 
        for (pfn = max_low_pfn; pfn < max_pfn; ++pfn) {
                struct page *page = pfn_to_page(pfn);
 
                /* FIXME not sure about */
-               if (memblock_is_reserved(pfn << PAGE_SHIFT))
-                       continue;
-               free_highmem_page(page);
-               reservedpages++;
+               if (!memblock_is_reserved(pfn << PAGE_SHIFT))
+                       free_highmem_page(page);
        }
-       pr_info("High memory: %luk\n",
-                                       totalhigh_pages << (PAGE_SHIFT-10));
-
-       return reservedpages;
 }
 #endif /* CONFIG_HIGHMEM */
 
@@ -167,13 +160,12 @@ void __init setup_memory(void)
         * min_low_pfn - the first page (mm/bootmem.c - node_boot_start)
         * max_low_pfn
         * max_mapnr - the first unused page (mm/bootmem.c - node_low_pfn)
-        * num_physpages - number of all pages
         */
 
        /* memory start is from the kernel end (aligned) to higher addr */
        min_low_pfn = memory_start >> PAGE_SHIFT; /* minimum for allocation */
        /* RAM is assumed contiguous */
-       num_physpages = max_mapnr = memory_size >> PAGE_SHIFT;
+       max_mapnr = memory_size >> PAGE_SHIFT;
        max_low_pfn = ((u64)memory_start + (u64)lowmem_size) >> PAGE_SHIFT;
        max_pfn = ((u64)memory_start + (u64)memory_size) >> PAGE_SHIFT;
 
@@ -235,57 +227,26 @@ void __init setup_memory(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
 
 void free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
 
 void __init mem_init(void)
 {
-       pg_data_t *pgdat;
-       unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
-
        high_memory = (void *)__va(memory_start + lowmem_size - 1);
 
        /* this will put all memory onto the freelists */
-       totalram_pages += free_all_bootmem();
-
-       for_each_online_pgdat(pgdat) {
-               unsigned long i;
-               struct page *page;
-
-               for (i = 0; i < pgdat->node_spanned_pages; i++) {
-                       if (!pfn_valid(pgdat->node_start_pfn + i))
-                               continue;
-                       page = pgdat_page_nr(pgdat, i);
-                       if (PageReserved(page))
-                               reservedpages++;
-               }
-       }
-
+       free_all_bootmem();
 #ifdef CONFIG_HIGHMEM
-       reservedpages -= highmem_setup();
+       highmem_setup();
 #endif
 
-       codesize = (unsigned long)&_sdata - (unsigned long)&_stext;
-       datasize = (unsigned long)&_edata - (unsigned long)&_sdata;
-       initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
-       bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;
-
-       pr_info("Memory: %luk/%luk available (%luk kernel code, ",
-               nr_free_pages() << (PAGE_SHIFT-10),
-               num_physpages << (PAGE_SHIFT-10),
-               codesize >> 10);
-       pr_cont("%luk reserved, %luk data, %luk bss, %luk init)\n",
-               reservedpages << (PAGE_SHIFT-10),
-               datasize >> 10,
-               bsssize >> 10,
-               initsize >> 10);
-
+       mem_init_print_info(NULL);
 #ifdef CONFIG_MMU
        pr_info("Kernel virtual memory layout:\n");
        pr_info("  * 0x%08lx..0x%08lx  : fixmap\n", FIXADDR_START, FIXADDR_TOP);
index a22f06a6f7cac31e3506619371615b8f4e1c8d4b..7181def6037a174a80880502f3e3fb75565516ca 100644 (file)
@@ -607,7 +607,7 @@ static void octeon_irq_ciu_gpio_ack(struct irq_data *data)
 
 static void octeon_irq_handle_gpio(unsigned int irq, struct irq_desc *desc)
 {
-       if (irqd_get_trigger_type(irq_desc_get_irq_data(desc)) & IRQ_TYPE_EDGE_BOTH)
+       if (irq_get_trigger_type(irq) & IRQ_TYPE_EDGE_BOTH)
                handle_edge_irq(irq, desc);
        else
                handle_level_irq(irq, desc);
index 3be9e7bb30ff05dbfa1c4866d3decba0a69a8715..f291cf99b03ae30e550ce73ab2784690460102c0 100644 (file)
@@ -4,16 +4,6 @@
 #include <asm/uaccess.h>
 #include <linux/slab.h>
 
-static int __init parse_savemaxmem(char *p)
-{
-       if (p)
-               saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1;
-
-       return 1;
-}
-__setup("savemaxmem=", parse_savemaxmem);
-
-
 static void *kdump_buf_page;
 
 /**
index fd814e08c945da41ad10f0582d7ccd7b7a8ab94f..cb098628aee89905e08a8be26154f0ddb75b7451 100644 (file)
@@ -27,12 +27,12 @@ unsigned long mt_fpemul_threshold;
  * FPU affinity with the user's requested processor affinity.
  * This code is 98% identical with the sys_sched_setaffinity()
  * and sys_sched_getaffinity() system calls, and should be
- * updated when kernel/sched.c changes.
+ * updated when kernel/sched/core.c changes.
  */
 
 /*
  * find_process_by_pid - find a process with a matching PID value.
- * used in sys_sched_set/getaffinity() in kernel/sched.c, so
+ * used in sys_sched_set/getaffinity() in kernel/sched/core.c, so
  * cloned here.
  */
 static inline struct task_struct *find_process_by_pid(pid_t pid)
index 9b36424b03c5f41aa48312c770f90e69a43f6fae..e9127ec612ef64cfef179cdd390412a20b43240e 100644 (file)
@@ -476,8 +476,9 @@ einval: li  v0, -ENOSYS
        /*
         * For FPU affinity scheduling on MIPS MT processors, we need to
         * intercept sys_sched_xxxaffinity() calls until we get a proper hook
-        * in kernel/sched.c.  Considered only temporary we only support these
-        * hooks for the 32-bit kernel - there is no MIPS64 MT processor atm.
+        * in kernel/sched/core.c.  Considered only temporary we only support
+        * these hooks for the 32-bit kernel - there is no MIPS64 MT processor
+        * atm.
         */
        sys     mipsmt_sys_sched_setaffinity    3
        sys     mipsmt_sys_sched_getaffinity    3
index bc739d4bab2eee62c2860b777415dffc80a83f4a..4dc2f5fa3f6737f940103216558b2310867f4e7e 100644 (file)
@@ -121,7 +121,8 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        clk->rate = rate;
 
        regval = LOONGSON_CHIPCFG0;
-       regval = (regval & ~0x7) | (loongson2_clockmod_table[i].index - 1);
+       regval = (regval & ~0x7) |
+               (loongson2_clockmod_table[i].driver_data - 1);
        LOONGSON_CHIPCFG0 = regval;
 
        return ret;
index 9b973e0af9cbbd2ba7c164fcfea8d9ac93265d36..4e73f10a751957b677da6ca8186f6294777ad709 100644 (file)
@@ -359,11 +359,24 @@ void __init paging_init(void)
 static struct kcore_list kcore_kseg0;
 #endif
 
-void __init mem_init(void)
+static inline void mem_init_free_highmem(void)
 {
-       unsigned long codesize, reservedpages, datasize, initsize;
-       unsigned long tmp, ram;
+#ifdef CONFIG_HIGHMEM
+       unsigned long tmp;
 
+       for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
+               struct page *page = pfn_to_page(tmp);
+
+               if (!page_is_ram(tmp))
+                       SetPageReserved(page);
+               else
+                       free_highmem_page(page);
+       }
+#endif
+}
+
+void __init mem_init(void)
+{
 #ifdef CONFIG_HIGHMEM
 #ifdef CONFIG_DISCONTIGMEM
 #error "CONFIG_HIGHMEM and CONFIG_DISCONTIGMEM dont work together yet"
@@ -374,34 +387,10 @@ void __init mem_init(void)
 #endif
        high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
 
-       totalram_pages += free_all_bootmem();
+       free_all_bootmem();
        setup_zero_pages();     /* Setup zeroed pages.  */
-
-       reservedpages = ram = 0;
-       for (tmp = 0; tmp < max_low_pfn; tmp++)
-               if (page_is_ram(tmp) && pfn_valid(tmp)) {
-                       ram++;
-                       if (PageReserved(pfn_to_page(tmp)))
-                               reservedpages++;
-               }
-       num_physpages = ram;
-
-#ifdef CONFIG_HIGHMEM
-       for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
-               struct page *page = pfn_to_page(tmp);
-
-               if (!page_is_ram(tmp)) {
-                       SetPageReserved(page);
-                       continue;
-               }
-               free_highmem_page(page);
-       }
-       num_physpages += totalhigh_pages;
-#endif
-
-       codesize =  (unsigned long) &_etext - (unsigned long) &_text;
-       datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
-       initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
+       mem_init_free_highmem();
+       mem_init_print_info(NULL);
 
 #ifdef CONFIG_64BIT
        if ((unsigned long) &_text > (unsigned long) CKSEG0)
@@ -410,16 +399,6 @@ void __init mem_init(void)
                kclist_add(&kcore_kseg0, (void *) CKSEG0,
                                0x80000000 - 4, KCORE_TEXT);
 #endif
-
-       printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
-              "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
-              nr_free_pages() << (PAGE_SHIFT-10),
-              ram << (PAGE_SHIFT-10),
-              codesize >> 10,
-              reservedpages << (PAGE_SHIFT-10),
-              datasize >> 10,
-              initsize >> 10,
-              totalhigh_pages << (PAGE_SHIFT-10));
 }
 #endif /* !CONFIG_NEED_MULTIPLE_NODES */
 
@@ -440,7 +419,8 @@ void free_init_pages(const char *what, unsigned long begin, unsigned long end)
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
+       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+                          "initrd");
 }
 #endif
 
index 879077b0115518a289de1d20fb148ec28de01517..cb1ef9984069306dc8814f748581edca229f2c47 100644 (file)
@@ -89,7 +89,7 @@ static inline u32 ltq_calc_bar11mask(void)
        u32 mem, bar11mask;
 
        /* BAR11MASK value depends on available memory on system. */
-       mem = num_physpages * PAGE_SIZE;
+       mem = get_num_physpages() * PAGE_SIZE;
        bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8;
 
        return bar11mask;
index 1230f56429d7334ea418f41921e709a9b737586a..a95c00f5fb9697ed90fa79d44ec887b498f680fc 100644 (file)
@@ -357,8 +357,6 @@ static void __init szmem(void)
        int slot;
        cnodeid_t node;
 
-       num_physpages = 0;
-
        for_each_online_node(node) {
                nodebytes = 0;
                for (slot = 0; slot < MAX_MEM_SLOTS; slot++) {
@@ -381,7 +379,6 @@ static void __init szmem(void)
                                slot = MAX_MEM_SLOTS;
                                continue;
                        }
-                       num_physpages += slot_psize;
                        memblock_add_node(PFN_PHYS(slot_getbasepfn(node, slot)),
                                          PFN_PHYS(slot_psize), node);
                }
@@ -480,32 +477,8 @@ void __init paging_init(void)
 
 void __init mem_init(void)
 {
-       unsigned long codesize, datasize, initsize, tmp;
-       unsigned node;
-
-       high_memory = (void *) __va(num_physpages << PAGE_SHIFT);
-
-       for_each_online_node(node) {
-               /*
-                * This will free up the bootmem, ie, slot 0 memory.
-                */
-               totalram_pages += free_all_bootmem_node(NODE_DATA(node));
-       }
-
+       high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
+       free_all_bootmem();
        setup_zero_pages();     /* This comes from node 0 */
-
-       codesize =  (unsigned long) &_etext - (unsigned long) &_text;
-       datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
-       initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
-       tmp = nr_free_pages();
-       printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
-              "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
-              tmp << (PAGE_SHIFT-10),
-              num_physpages << (PAGE_SHIFT-10),
-              codesize >> 10,
-              (num_physpages - tmp) << (PAGE_SHIFT-10),
-              datasize >> 10,
-              initsize >> 10,
-              totalhigh_pages << (PAGE_SHIFT-10));
+       mem_init_print_info(NULL);
 }
index d7966e0f76988cfb2d36d0b480277961dcef7e3a..537278746a1534cead71e487aea7f13533e60b97 100644 (file)
@@ -471,13 +471,13 @@ extern unsigned long __generic_copy_from_user(void *, const void __user *,
 
 #define __copy_to_user(to, from, n)                    \
 ({                                                     \
-       might_sleep();                                  \
+       might_fault();                                  \
        __copy_to_user_inatomic((to), (from), (n));     \
 })
 
 #define __copy_from_user(to, from, n)                  \
 ({                                                     \
-       might_sleep();                                  \
+       might_fault();                                  \
        __copy_from_user_inatomic((to), (from), (n));   \
 })
 
index 5a8ace63a6b48188a6efbdc852f1d6c530d4913f..97a1ec0beeecf2fd5dd538eda613b3bbcfa5346b 100644 (file)
@@ -99,43 +99,21 @@ void __init paging_init(void)
  */
 void __init mem_init(void)
 {
-       int codesize, reservedpages, datasize, initsize;
-       int tmp;
-
        BUG_ON(!mem_map);
 
 #define START_PFN      (contig_page_data.bdata->node_min_pfn)
 #define MAX_LOW_PFN    (contig_page_data.bdata->node_low_pfn)
 
-       max_mapnr = num_physpages = MAX_LOW_PFN - START_PFN;
+       max_mapnr = MAX_LOW_PFN - START_PFN;
        high_memory = (void *) __va(MAX_LOW_PFN * PAGE_SIZE);
 
        /* clear the zero-page */
        memset(empty_zero_page, 0, PAGE_SIZE);
 
        /* this will put all low memory onto the freelists */
-       totalram_pages += free_all_bootmem();
-
-       reservedpages = 0;
-       for (tmp = 0; tmp < num_physpages; tmp++)
-               if (PageReserved(&mem_map[tmp]))
-                       reservedpages++;
-
-       codesize =  (unsigned long) &_etext - (unsigned long) &_stext;
-       datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
-       initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
-       printk(KERN_INFO
-              "Memory: %luk/%luk available"
-              " (%dk kernel code, %dk reserved, %dk data, %dk init,"
-              " %ldk highmem)\n",
-              nr_free_pages() << (PAGE_SHIFT - 10),
-              max_mapnr << (PAGE_SHIFT - 10),
-              codesize >> 10,
-              reservedpages << (PAGE_SHIFT - 10),
-              datasize >> 10,
-              initsize >> 10,
-              totalhigh_pages << (PAGE_SHIFT - 10));
+       free_all_bootmem();
+
+       mem_init_print_info(NULL);
 }
 
 /*
@@ -152,6 +130,7 @@ void free_initmem(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
+       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+                          "initrd");
 }
 #endif
index f20d01d9aaf973bec2f0affd4cfb4a2117267d47..195653e851da2a460fcafeca692af220bcef58d1 100644 (file)
@@ -66,3 +66,4 @@ generic-y += types.h
 generic-y += ucontext.h
 generic-y += user.h
 generic-y += word-at-a-time.h
+generic-y += xor.h
index b3cbc670383789461bf29c61531e8c76679aa964..7f94652311d74524b9d76d9498b4d84c24177d9b 100644 (file)
@@ -202,56 +202,20 @@ void __init paging_init(void)
 
 /* References to section boundaries */
 
-static int __init free_pages_init(void)
-{
-       int reservedpages, pfn;
-
-       /* this will put all low memory onto the freelists */
-       totalram_pages = free_all_bootmem();
-
-       reservedpages = 0;
-       for (pfn = 0; pfn < max_low_pfn; pfn++) {
-               /*
-                * Only count reserved RAM pages
-                */
-               if (PageReserved(mem_map + pfn))
-                       reservedpages++;
-       }
-
-       return reservedpages;
-}
-
-static void __init set_max_mapnr_init(void)
-{
-       max_mapnr = num_physpages = max_low_pfn;
-}
-
 void __init mem_init(void)
 {
-       int codesize, reservedpages, datasize, initsize;
-
        BUG_ON(!mem_map);
 
-       set_max_mapnr_init();
-
+       max_mapnr = max_low_pfn;
        high_memory = (void *)__va(max_low_pfn * PAGE_SIZE);
 
        /* clear the zero-page */
        memset((void *)empty_zero_page, 0, PAGE_SIZE);
 
-       reservedpages = free_pages_init();
-
-       codesize = (unsigned long)&_etext - (unsigned long)&_stext;
-       datasize = (unsigned long)&_edata - (unsigned long)&_etext;
-       initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
+       /* this will put all low memory onto the freelists */
+       free_all_bootmem();
 
-       printk(KERN_INFO
-              "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
-              (unsigned long)nr_free_pages() << (PAGE_SHIFT - 10),
-              max_mapnr << (PAGE_SHIFT - 10), codesize >> 10,
-              reservedpages << (PAGE_SHIFT - 10), datasize >> 10,
-              initsize >> 10, (unsigned long)(0 << (PAGE_SHIFT - 10))
-           );
+       mem_init_print_info(NULL);
 
        printk("mem_init_done ...........................................\n");
        mem_init_done = 1;
@@ -261,11 +225,11 @@ void __init mem_init(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
 
 void free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
index 0304b92ccfeaf245f2f403b7163c70a8ec037b6c..cc61c475f2779198e45e72dc16dcc4f51e691dec 100644 (file)
@@ -20,6 +20,7 @@
 #define O_INVISIBLE    004000000 /* invisible I/O, for DMAPI/XDSM */
 
 #define O_PATH         020000000
+#define O_TMPFILE      040000000
 
 #define F_GETLK64      8
 #define F_SETLK64      9
index 505b56c6b9b9c6dafa9df67b775c44eb1ebf1867..b0f96c0e6316f15531afb2a5a2a0e4684d1892a8 100644 (file)
@@ -214,7 +214,6 @@ static void __init setup_bootmem(void)
        mem_limit_func();       /* check for "mem=" argument */
 
        mem_max = 0;
-       num_physpages = 0;
        for (i = 0; i < npmem_ranges; i++) {
                unsigned long rsize;
 
@@ -229,10 +228,8 @@ static void __init setup_bootmem(void)
                                npmem_ranges = i + 1;
                                mem_max = mem_limit;
                        }
-               num_physpages += pmem_ranges[i].pages;
                        break;
                }
-           num_physpages += pmem_ranges[i].pages;
                mem_max += rsize;
        }
 
@@ -532,7 +529,7 @@ void free_initmem(void)
         * pages are no-longer executable */
        flush_icache_range(init_begin, init_end);
        
-       num_physpages += free_initmem_default(0);
+       free_initmem_default(-1);
 
        /* set up a new led state on systems shipped LED State panel */
        pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
@@ -580,8 +577,6 @@ unsigned long pcxl_dma_start __read_mostly;
 
 void __init mem_init(void)
 {
-       int codesize, reservedpages, datasize, initsize;
-
        /* Do sanity checks on page table constants */
        BUILD_BUG_ON(PTE_ENTRY_SIZE != sizeof(pte_t));
        BUILD_BUG_ON(PMD_ENTRY_SIZE != sizeof(pmd_t));
@@ -590,45 +585,8 @@ void __init mem_init(void)
                        > BITS_PER_LONG);
 
        high_memory = __va((max_pfn << PAGE_SHIFT));
-
-#ifndef CONFIG_DISCONTIGMEM
-       max_mapnr = page_to_pfn(virt_to_page(high_memory - 1)) + 1;
-       totalram_pages += free_all_bootmem();
-#else
-       {
-               int i;
-
-               for (i = 0; i < npmem_ranges; i++)
-                       totalram_pages += free_all_bootmem_node(NODE_DATA(i));
-       }
-#endif
-
-       codesize = (unsigned long)_etext - (unsigned long)_text;
-       datasize = (unsigned long)_edata - (unsigned long)_etext;
-       initsize = (unsigned long)__init_end - (unsigned long)__init_begin;
-
-       reservedpages = 0;
-{
-       unsigned long pfn;
-#ifdef CONFIG_DISCONTIGMEM
-       int i;
-
-       for (i = 0; i < npmem_ranges; i++) {
-               for (pfn = node_start_pfn(i); pfn < node_end_pfn(i); pfn++) {
-                       if (PageReserved(pfn_to_page(pfn)))
-                               reservedpages++;
-               }
-       }
-#else /* !CONFIG_DISCONTIGMEM */
-       for (pfn = 0; pfn < max_pfn; pfn++) {
-               /*
-                * Only count reserved RAM pages
-                */
-               if (PageReserved(pfn_to_page(pfn)))
-                       reservedpages++;
-       }
-#endif
-}
+       set_max_mapnr(page_to_pfn(virt_to_page(high_memory - 1)) + 1);
+       free_all_bootmem();
 
 #ifdef CONFIG_PA11
        if (hppa_dma_ops == &pcxl_dma_ops) {
@@ -643,15 +601,7 @@ void __init mem_init(void)
        parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START);
 #endif
 
-       printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
-               nr_free_pages() << (PAGE_SHIFT-10),
-               num_physpages << (PAGE_SHIFT-10),
-               codesize >> 10,
-               reservedpages << (PAGE_SHIFT-10),
-               datasize >> 10,
-               initsize >> 10
-       );
-
+       mem_init_print_info(NULL);
 #ifdef CONFIG_DEBUG_KERNEL /* double-sanity-check paranoia */
        printk("virtual kernel memory layout:\n"
               "    vmalloc : 0x%p - 0x%p   (%4ld MB)\n"
@@ -1101,6 +1051,6 @@ void flush_tlb_all(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       num_physpages += free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
index 349ed85c7d61e00dff7358e70933197704f9b9db..08891d07aeb656e891633d96cd8b2ab09b7dc6d4 100644 (file)
@@ -107,8 +107,9 @@ struct kvmppc_vcpu_book3s {
 #define CONTEXT_GUEST          1
 #define CONTEXT_GUEST_END      2
 
-#define VSID_REAL      0x1fffffffffc00000ULL
-#define VSID_BAT       0x1fffffffffb00000ULL
+#define VSID_REAL      0x0fffffffffc00000ULL
+#define VSID_BAT       0x0fffffffffb00000ULL
+#define VSID_1T                0x1000000000000000ULL
 #define VSID_REAL_DR   0x2000000000000000ULL
 #define VSID_REAL_IR   0x4000000000000000ULL
 #define VSID_PR                0x8000000000000000ULL
@@ -123,6 +124,7 @@ extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu);
 extern void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu);
 extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte);
 extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr);
+extern void kvmppc_mmu_flush_segment(struct kvm_vcpu *vcpu, ulong eaddr, ulong seg_size);
 extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu);
 extern int kvmppc_book3s_hv_page_fault(struct kvm_run *run,
                        struct kvm_vcpu *vcpu, unsigned long addr,
index a73668a5f30d339a5b0513ac234536d1206caaa7..b467530e248583cb7d3736bcfd7a4095f7b75693 100644 (file)
@@ -38,7 +38,7 @@ extern void drop_cop(unsigned long acop, struct mm_struct *mm);
 
 /*
  * switch_mm is the entry point called from the architecture independent
- * code in kernel/sched.c
+ * code in kernel/sched/core.c
  */
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                             struct task_struct *tsk)
index 5399f7e18102f7144bcb1464ff5f13c2fac4468c..127ab23e1f6ccdbe038b6cfdd84c569742968e27 100644 (file)
@@ -82,17 +82,15 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
  *                                 from 1 to a 0 value
  *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 1
  *
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns.
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
  */
 static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count)
 {
        if (unlikely(__mutex_dec_return_lock(count) < 0))
-               return fail_fn(count);
+               return -1;
        return 0;
 }
 
index 4db49590acf5d797af733fd15d7f3141a465a839..9485b43a7c00ec52d2c8be21738d6b53878babc6 100644 (file)
@@ -178,7 +178,7 @@ do {                                                                \
        long __pu_err;                                          \
        __typeof__(*(ptr)) __user *__pu_addr = (ptr);           \
        if (!is_kernel_addr((unsigned long)__pu_addr))          \
-               might_sleep();                                  \
+               might_fault();                                  \
        __chk_user_ptr(ptr);                                    \
        __put_user_size((x), __pu_addr, (size), __pu_err);      \
        __pu_err;                                               \
@@ -188,7 +188,7 @@ do {                                                                \
 ({                                                                     \
        long __pu_err = -EFAULT;                                        \
        __typeof__(*(ptr)) __user *__pu_addr = (ptr);                   \
-       might_sleep();                                                  \
+       might_fault();                                                  \
        if (access_ok(VERIFY_WRITE, __pu_addr, size))                   \
                __put_user_size((x), __pu_addr, (size), __pu_err);      \
        __pu_err;                                                       \
@@ -268,7 +268,7 @@ do {                                                                \
        const __typeof__(*(ptr)) __user *__gu_addr = (ptr);     \
        __chk_user_ptr(ptr);                                    \
        if (!is_kernel_addr((unsigned long)__gu_addr))          \
-               might_sleep();                                  \
+               might_fault();                                  \
        __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
        (x) = (__typeof__(*(ptr)))__gu_val;                     \
        __gu_err;                                               \
@@ -282,7 +282,7 @@ do {                                                                \
        const __typeof__(*(ptr)) __user *__gu_addr = (ptr);     \
        __chk_user_ptr(ptr);                                    \
        if (!is_kernel_addr((unsigned long)__gu_addr))          \
-               might_sleep();                                  \
+               might_fault();                                  \
        __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
        (x) = (__typeof__(*(ptr)))__gu_val;                     \
        __gu_err;                                               \
@@ -294,7 +294,7 @@ do {                                                                \
        long __gu_err = -EFAULT;                                        \
        unsigned long  __gu_val = 0;                                    \
        const __typeof__(*(ptr)) __user *__gu_addr = (ptr);             \
-       might_sleep();                                                  \
+       might_fault();                                                  \
        if (access_ok(VERIFY_READ, __gu_addr, (size)))                  \
                __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
        (x) = (__typeof__(*(ptr)))__gu_val;                             \
@@ -419,14 +419,14 @@ static inline unsigned long __copy_to_user_inatomic(void __user *to,
 static inline unsigned long __copy_from_user(void *to,
                const void __user *from, unsigned long size)
 {
-       might_sleep();
+       might_fault();
        return __copy_from_user_inatomic(to, from, size);
 }
 
 static inline unsigned long __copy_to_user(void __user *to,
                const void *from, unsigned long size)
 {
-       might_sleep();
+       might_fault();
        return __copy_to_user_inatomic(to, from, size);
 }
 
@@ -434,7 +434,7 @@ extern unsigned long __clear_user(void __user *addr, unsigned long size);
 
 static inline unsigned long clear_user(void __user *addr, unsigned long size)
 {
-       might_sleep();
+       might_fault();
        if (likely(access_ok(VERIFY_WRITE, addr, size)))
                return __clear_user(addr, size);
        if ((unsigned long)addr < TASK_SIZE) {
index 9ec3fe174cba7c0ec859bcbb665aeba2b1cc1cb7..779a78c2643502a4414af7d646f4dce810deba72 100644 (file)
@@ -69,16 +69,6 @@ void __init setup_kdump_trampoline(void)
 }
 #endif /* CONFIG_NONSTATIC_KERNEL */
 
-static int __init parse_savemaxmem(char *p)
-{
-       if (p)
-               saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1;
-
-       return 1;
-}
-__setup("savemaxmem=", parse_savemaxmem);
-
-
 static size_t copy_oldmem_vaddr(void *vaddr, char *buf, size_t csize,
                                unsigned long offset, int userbuf)
 {
index 6782221d49bde4d5b2074fba47e5bae8fab33d84..db28032e320e3e5332b6e60d77d1b56d29cea7d9 100644 (file)
@@ -750,13 +750,8 @@ EXPORT_SYMBOL_GPL(kvm_hypercall);
 
 static __init void kvm_free_tmp(void)
 {
-       unsigned long start, end;
-
-       start = (ulong)&kvm_tmp[kvm_tmp_index + (PAGE_SIZE - 1)] & PAGE_MASK;
-       end = (ulong)&kvm_tmp[ARRAY_SIZE(kvm_tmp)] & PAGE_MASK;
-
-       /* Free the tmp space we don't need */
-       free_reserved_area(start, end, 0, NULL);
+       free_reserved_area(&kvm_tmp[kvm_tmp_index],
+                          &kvm_tmp[ARRAY_SIZE(kvm_tmp)], -1, NULL);
 }
 
 static int __init kvm_guest_init(void)
index 2a67e9baa59f80200f4a25b5a75471c04f04c776..6b0ba5854d9960aff03bbd01b810543c9e369588 100644 (file)
@@ -128,7 +128,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
        const char *type;
        struct pci_slot *slot;
 
-       dev = alloc_pci_dev();
+       dev = pci_alloc_dev(bus);
        if (!dev)
                return NULL;
        type = of_get_property(node, "device_type", NULL);
@@ -137,7 +137,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
 
        pr_debug("    create device, devfn: %x, type: %s\n", devfn, type);
 
-       dev->bus = bus;
        dev->dev.of_node = of_node_get(node);
        dev->dev.parent = bus->bridge;
        dev->dev.bus = &pci_bus_type;
@@ -165,7 +164,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
        pr_debug("    class: 0x%x\n", dev->class);
        pr_debug("    revision: 0x%x\n", dev->revision);
 
-       dev->current_state = 4;         /* unknown power state */
+       dev->current_state = PCI_UNKNOWN;       /* unknown power state */
        dev->error_state = pci_channel_io_normal;
        dev->dma_mask = 0xffffffff;
 
index feb8580fdc843acc485df310ed1c072907dc7159..c30612aad68ebd5f239776a3b4c6cf66ea94bf1e 100644 (file)
 
 #ifdef CONFIG_PPC64
 
-static loff_t page_map_seek( struct file *file, loff_t off, int whence)
+static loff_t page_map_seek(struct file *file, loff_t off, int whence)
 {
-       loff_t new;
-       switch(whence) {
-       case 0:
-               new = off;
-               break;
-       case 1:
-               new = file->f_pos + off;
-               break;
-       case 2:
-               new = PAGE_SIZE + off;
-               break;
-       default:
-               return -EINVAL;
-       }
-       if ( new < 0 || new > PAGE_SIZE )
-               return -EINVAL;
-       return (file->f_pos = new);
+       return fixed_size_llseek(file, off, whence, PAGE_SIZE);
 }
 
 static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes,
index 422de3f4d46cd129dd14c06dd1852dab9bf12463..008cd856c5b52942c7be2d1e136650ea9aca8922 100644 (file)
@@ -5,9 +5,10 @@
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
 ccflags-y := -Ivirt/kvm -Iarch/powerpc/kvm
+KVM := ../../../virt/kvm
 
-common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o \
-                                               eventfd.o)
+common-objs-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o \
+               $(KVM)/eventfd.o
 
 CFLAGS_44x_tlb.o  := -I.
 CFLAGS_e500_mmu.o := -I.
@@ -53,7 +54,7 @@ kvm-e500mc-objs := \
 kvm-objs-$(CONFIG_KVM_E500MC) := $(kvm-e500mc-objs)
 
 kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_PR) := \
-       ../../../virt/kvm/coalesced_mmio.o \
+       $(KVM)/coalesced_mmio.o \
        fpu.o \
        book3s_paired_singles.o \
        book3s_pr.o \
@@ -86,8 +87,8 @@ kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
        book3s_xics.o
 
 kvm-book3s_64-module-objs := \
-       ../../../virt/kvm/kvm_main.o \
-       ../../../virt/kvm/eventfd.o \
+       $(KVM)/kvm_main.o \
+       $(KVM)/eventfd.o \
        powerpc.o \
        emulate.o \
        book3s.o \
@@ -111,7 +112,7 @@ kvm-book3s_32-objs := \
 kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs)
 
 kvm-objs-$(CONFIG_KVM_MPIC) += mpic.o
-kvm-objs-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(addprefix ../../../virt/kvm/, irqchip.o)
+kvm-objs-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(KVM)/irqchip.o
 
 kvm-objs := $(kvm-objs-m) $(kvm-objs-y)
 
index b871721c0050e8e3f04353f80c925f63c89afded..739bfbadb85e3218bf39a293af377d7fe99eb218 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/tlbflush.h>
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
+#include <asm/mmu-hash64.h>
 
 /* #define DEBUG_MMU */
 
@@ -76,6 +77,24 @@ static struct kvmppc_slb *kvmppc_mmu_book3s_64_find_slbe(
        return NULL;
 }
 
+static int kvmppc_slb_sid_shift(struct kvmppc_slb *slbe)
+{
+       return slbe->tb ? SID_SHIFT_1T : SID_SHIFT;
+}
+
+static u64 kvmppc_slb_offset_mask(struct kvmppc_slb *slbe)
+{
+       return (1ul << kvmppc_slb_sid_shift(slbe)) - 1;
+}
+
+static u64 kvmppc_slb_calc_vpn(struct kvmppc_slb *slb, gva_t eaddr)
+{
+       eaddr &= kvmppc_slb_offset_mask(slb);
+
+       return (eaddr >> VPN_SHIFT) |
+               ((slb->vsid) << (kvmppc_slb_sid_shift(slb) - VPN_SHIFT));
+}
+
 static u64 kvmppc_mmu_book3s_64_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
                                         bool data)
 {
@@ -85,11 +104,7 @@ static u64 kvmppc_mmu_book3s_64_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
        if (!slb)
                return 0;
 
-       if (slb->tb)
-               return (((u64)eaddr >> 12) & 0xfffffff) |
-                      (((u64)slb->vsid) << 28);
-
-       return (((u64)eaddr >> 12) & 0xffff) | (((u64)slb->vsid) << 16);
+       return kvmppc_slb_calc_vpn(slb, eaddr);
 }
 
 static int kvmppc_mmu_book3s_64_get_pagesize(struct kvmppc_slb *slbe)
@@ -100,7 +115,8 @@ static int kvmppc_mmu_book3s_64_get_pagesize(struct kvmppc_slb *slbe)
 static u32 kvmppc_mmu_book3s_64_get_page(struct kvmppc_slb *slbe, gva_t eaddr)
 {
        int p = kvmppc_mmu_book3s_64_get_pagesize(slbe);
-       return ((eaddr & 0xfffffff) >> p);
+
+       return ((eaddr & kvmppc_slb_offset_mask(slbe)) >> p);
 }
 
 static hva_t kvmppc_mmu_book3s_64_get_pteg(
@@ -109,13 +125,15 @@ static hva_t kvmppc_mmu_book3s_64_get_pteg(
                                bool second)
 {
        u64 hash, pteg, htabsize;
-       u32 page;
+       u32 ssize;
        hva_t r;
+       u64 vpn;
 
-       page = kvmppc_mmu_book3s_64_get_page(slbe, eaddr);
        htabsize = ((1 << ((vcpu_book3s->sdr1 & 0x1f) + 11)) - 1);
 
-       hash = slbe->vsid ^ page;
+       vpn = kvmppc_slb_calc_vpn(slbe, eaddr);
+       ssize = slbe->tb ? MMU_SEGSIZE_1T : MMU_SEGSIZE_256M;
+       hash = hpt_hash(vpn, kvmppc_mmu_book3s_64_get_pagesize(slbe), ssize);
        if (second)
                hash = ~hash;
        hash &= ((1ULL << 39ULL) - 1ULL);
@@ -146,7 +164,7 @@ static u64 kvmppc_mmu_book3s_64_get_avpn(struct kvmppc_slb *slbe, gva_t eaddr)
        u64 avpn;
 
        avpn = kvmppc_mmu_book3s_64_get_page(slbe, eaddr);
-       avpn |= slbe->vsid << (28 - p);
+       avpn |= slbe->vsid << (kvmppc_slb_sid_shift(slbe) - p);
 
        if (p < 24)
                avpn >>= ((80 - p) - 56) - 8;
@@ -167,7 +185,6 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
        int i;
        u8 key = 0;
        bool found = false;
-       bool perm_err = false;
        int second = 0;
        ulong mp_ea = vcpu->arch.magic_page_ea;
 
@@ -190,13 +207,15 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
        if (!slbe)
                goto no_seg_found;
 
+       avpn = kvmppc_mmu_book3s_64_get_avpn(slbe, eaddr);
+       if (slbe->tb)
+               avpn |= SLB_VSID_B_1T;
+
 do_second:
        ptegp = kvmppc_mmu_book3s_64_get_pteg(vcpu_book3s, slbe, eaddr, second);
        if (kvm_is_error_hva(ptegp))
                goto no_page_found;
 
-       avpn = kvmppc_mmu_book3s_64_get_avpn(slbe, eaddr);
-
        if(copy_from_user(pteg, (void __user *)ptegp, sizeof(pteg))) {
                printk(KERN_ERR "KVM can't copy data from 0x%lx!\n", ptegp);
                goto no_page_found;
@@ -219,7 +238,7 @@ do_second:
                        continue;
 
                /* AVPN compare */
-               if (HPTE_V_AVPN_VAL(avpn) == HPTE_V_AVPN_VAL(v)) {
+               if (HPTE_V_COMPARE(avpn, v)) {
                        u8 pp = (r & HPTE_R_PP) | key;
                        int eaddr_mask = 0xFFF;
 
@@ -248,11 +267,6 @@ do_second:
                                break;
                        }
 
-                       if (!gpte->may_read) {
-                               perm_err = true;
-                               continue;
-                       }
-
                        dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx "
                                "-> 0x%lx\n",
                                eaddr, avpn, gpte->vpage, gpte->raddr);
@@ -281,6 +295,8 @@ do_second:
                if (pteg[i+1] != oldr)
                        copy_to_user((void __user *)ptegp, pteg, sizeof(pteg));
 
+               if (!gpte->may_read)
+                       return -EPERM;
                return 0;
        } else {
                dprintk("KVM MMU: No PTE found (ea=0x%lx sdr1=0x%llx "
@@ -296,13 +312,7 @@ do_second:
                }
        }
 
-
 no_page_found:
-
-
-       if (perm_err)
-               return -EPERM;
-
        return -ENOENT;
 
 no_seg_found:
@@ -334,7 +344,7 @@ static void kvmppc_mmu_book3s_64_slbmte(struct kvm_vcpu *vcpu, u64 rs, u64 rb)
        slbe->large = (rs & SLB_VSID_L) ? 1 : 0;
        slbe->tb    = (rs & SLB_VSID_B_1T) ? 1 : 0;
        slbe->esid  = slbe->tb ? esid_1t : esid;
-       slbe->vsid  = rs >> 12;
+       slbe->vsid  = (rs & ~SLB_VSID_B) >> (kvmppc_slb_sid_shift(slbe) - 16);
        slbe->valid = (rb & SLB_ESID_V) ? 1 : 0;
        slbe->Ks    = (rs & SLB_VSID_KS) ? 1 : 0;
        slbe->Kp    = (rs & SLB_VSID_KP) ? 1 : 0;
@@ -375,6 +385,7 @@ static u64 kvmppc_mmu_book3s_64_slbmfev(struct kvm_vcpu *vcpu, u64 slb_nr)
 static void kvmppc_mmu_book3s_64_slbie(struct kvm_vcpu *vcpu, u64 ea)
 {
        struct kvmppc_slb *slbe;
+       u64 seg_size;
 
        dprintk("KVM MMU: slbie(0x%llx)\n", ea);
 
@@ -386,8 +397,11 @@ static void kvmppc_mmu_book3s_64_slbie(struct kvm_vcpu *vcpu, u64 ea)
        dprintk("KVM MMU: slbie(0x%llx, 0x%llx)\n", ea, slbe->esid);
 
        slbe->valid = false;
+       slbe->orige = 0;
+       slbe->origv = 0;
 
-       kvmppc_mmu_map_segment(vcpu, ea);
+       seg_size = 1ull << kvmppc_slb_sid_shift(slbe);
+       kvmppc_mmu_flush_segment(vcpu, ea & ~(seg_size - 1), seg_size);
 }
 
 static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu)
@@ -396,8 +410,11 @@ static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu)
 
        dprintk("KVM MMU: slbia()\n");
 
-       for (i = 1; i < vcpu->arch.slb_nr; i++)
+       for (i = 1; i < vcpu->arch.slb_nr; i++) {
                vcpu->arch.slb[i].valid = false;
+               vcpu->arch.slb[i].orige = 0;
+               vcpu->arch.slb[i].origv = 0;
+       }
 
        if (vcpu->arch.shared->msr & MSR_IR) {
                kvmppc_mmu_flush_segments(vcpu);
@@ -467,8 +484,14 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
 
        if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
                slb = kvmppc_mmu_book3s_64_find_slbe(vcpu, ea);
-               if (slb)
+               if (slb) {
                        gvsid = slb->vsid;
+                       if (slb->tb) {
+                               gvsid <<= SID_SHIFT_1T - SID_SHIFT;
+                               gvsid |= esid & ((1ul << (SID_SHIFT_1T - SID_SHIFT)) - 1);
+                               gvsid |= VSID_1T;
+                       }
+               }
        }
 
        switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
index 3a9a1aceb14f576e8201164343b7d2b220cf553a..b350d9494b26d7ae0201445c1fb98e04e61c332f 100644 (file)
@@ -301,6 +301,23 @@ out:
        return r;
 }
 
+void kvmppc_mmu_flush_segment(struct kvm_vcpu *vcpu, ulong ea, ulong seg_size)
+{
+       struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+       ulong seg_mask = -seg_size;
+       int i;
+
+       for (i = 1; i < svcpu->slb_max; i++) {
+               if ((svcpu->slb[i].esid & SLB_ESID_V) &&
+                   (svcpu->slb[i].esid & seg_mask) == ea) {
+                       /* Invalidate this entry */
+                       svcpu->slb[i].esid = 0;
+               }
+       }
+
+       svcpu_put(svcpu);
+}
+
 void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
@@ -325,9 +342,9 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
                return -1;
        vcpu3s->context_id[0] = err;
 
-       vcpu3s->proto_vsid_max = ((vcpu3s->context_id[0] + 1)
+       vcpu3s->proto_vsid_max = ((u64)(vcpu3s->context_id[0] + 1)
                                  << ESID_BITS) - 1;
-       vcpu3s->proto_vsid_first = vcpu3s->context_id[0] << ESID_BITS;
+       vcpu3s->proto_vsid_first = (u64)vcpu3s->context_id[0] << ESID_BITS;
        vcpu3s->proto_vsid_next = vcpu3s->proto_vsid_first;
 
        kvmppc_mmu_hpte_init(vcpu);
index 56b983e7b7380c88a4199d68dc97fb2a6a0ec985..4f0caecc0f9dea4a72d3c548a0e1ac58b7ae754b 100644 (file)
@@ -66,10 +66,6 @@ slb_exit_skip_ ## num:
 
        ld      r12, PACA_SLBSHADOWPTR(r13)
 
-       /* Save off the first entry so we can slbie it later */
-       ld      r10, SHADOW_SLB_ESID(0)(r12)
-       ld      r11, SHADOW_SLB_VSID(0)(r12)
-
        /* Remove bolted entries */
        UNBOLT_SLB_ENTRY(0)
        UNBOLT_SLB_ENTRY(1)
@@ -81,15 +77,10 @@ slb_exit_skip_ ## num:
 
        /* Flush SLB */
 
+       li      r10, 0
+       slbmte  r10, r10
        slbia
 
-       /* r0 = esid & ESID_MASK */
-       rldicr  r10, r10, 0, 35
-       /* r0 |= CLASS_BIT(VSID) */
-       rldic   r12, r11, 56 - 36, 36
-       or      r10, r10, r12
-       slbie   r10
-
        /* Fill SLB with our shadow */
 
        lbz     r12, SVCPU_SLB_MAX(r3)
index 550f5928b394f6cb4c1da71978031a1ce1f96b79..2efa9dde741a1aad3ed206481e9c272a94eb7cdf 100644 (file)
@@ -1864,7 +1864,7 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
 
  up_out:
        up_read(&current->mm->mmap_sem);
-       goto out;
+       goto out_srcu;
 }
 
 int kvmppc_core_init_vm(struct kvm *kvm)
index bdc40b8e77d9ecc6c5da88e076a53e97ffe52277..19498a567a81f25c67c7f1b3f010182fcb680e2b 100644 (file)
@@ -1239,8 +1239,7 @@ out:
 #ifdef CONFIG_PPC64
 int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm, struct kvm_ppc_smmu_info *info)
 {
-       /* No flags */
-       info->flags = 0;
+       info->flags = KVM_PPC_1T_SEGMENTS;
 
        /* SLB is always 64 entries */
        info->slb_size = 64;
index 1a1b511897733da58ec1a1b79d6c9a66ffdedea2..dcc94f016007f485e769f189cce610c77734f56f 100644 (file)
@@ -796,7 +796,7 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
                kvmppc_fill_pt_regs(&regs);
                timer_interrupt(&regs);
                break;
-#if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3E_64)
+#if defined(CONFIG_PPC_DOORBELL)
        case BOOKE_INTERRUPT_DOORBELL:
                kvmppc_fill_pt_regs(&regs);
                doorbell_exception(&regs);
index 631a2650e4e42c0038524b0940a9ae91bcdcd3a4..2c52ada3077536c04e145b63d243859f8d32cab0 100644 (file)
@@ -169,6 +169,9 @@ static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
                vcpu->arch.shared->sprg3 = spr_val;
                break;
 
+       /* PIR can legally be written, but we ignore it */
+       case SPRN_PIR: break;
+
        default:
                emulated = kvmppc_core_emulate_mtspr(vcpu, sprn,
                                                     spr_val);
index 77fdd2cef33b5a2c18ac40c442645d9dc38365ad..4210549ac95e6cb0fd0127664ac175df50067307 100644 (file)
@@ -357,7 +357,7 @@ void add_gpage(u64 addr, u64 page_size, unsigned long number_of_pages)
 int alloc_bootmem_huge_page(struct hstate *hstate)
 {
        struct huge_bootmem_page *m;
-       int idx = shift_to_mmu_psize(hstate->order + PAGE_SHIFT);
+       int idx = shift_to_mmu_psize(huge_page_shift(hstate));
        int nr_gpages = gpage_freearray[idx].nr_gpages;
 
        if (nr_gpages == 0)
index 0988a26e04131e5408f8f1f3a16627b21699ad4a..1cb1ea133a2cc6f37dc1b6e0419d7a0b8bdfe9bb 100644 (file)
@@ -299,47 +299,13 @@ void __init paging_init(void)
 
 void __init mem_init(void)
 {
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-       int nid;
-#endif
-       pg_data_t *pgdat;
-       unsigned long i;
-       struct page *page;
-       unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
-
 #ifdef CONFIG_SWIOTLB
        swiotlb_init(0);
 #endif
 
-       num_physpages = memblock_phys_mem_size() >> PAGE_SHIFT;
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
-
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-        for_each_online_node(nid) {
-               if (NODE_DATA(nid)->node_spanned_pages != 0) {
-                       printk("freeing bootmem node %d\n", nid);
-                       totalram_pages +=
-                               free_all_bootmem_node(NODE_DATA(nid));
-               }
-       }
-#else
-       max_mapnr = max_pfn;
-       totalram_pages += free_all_bootmem();
-#endif
-       for_each_online_pgdat(pgdat) {
-               for (i = 0; i < pgdat->node_spanned_pages; i++) {
-                       if (!pfn_valid(pgdat->node_start_pfn + i))
-                               continue;
-                       page = pgdat_page_nr(pgdat, i);
-                       if (PageReserved(page))
-                               reservedpages++;
-               }
-       }
-
-       codesize = (unsigned long)&_sdata - (unsigned long)&_stext;
-       datasize = (unsigned long)&_edata - (unsigned long)&_sdata;
-       initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
-       bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;
+       set_max_mapnr(max_pfn);
+       free_all_bootmem();
 
 #ifdef CONFIG_HIGHMEM
        {
@@ -349,13 +315,9 @@ void __init mem_init(void)
                for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) {
                        phys_addr_t paddr = (phys_addr_t)pfn << PAGE_SHIFT;
                        struct page *page = pfn_to_page(pfn);
-                       if (memblock_is_reserved(paddr))
-                               continue;
-                       free_highmem_page(page);
-                       reservedpages--;
+                       if (!memblock_is_reserved(paddr))
+                               free_highmem_page(page);
                }
-               printk(KERN_DEBUG "High memory: %luk\n",
-                      totalhigh_pages << (PAGE_SHIFT-10));
        }
 #endif /* CONFIG_HIGHMEM */
 
@@ -368,16 +330,7 @@ void __init mem_init(void)
                (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) - 1;
 #endif
 
-       printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, "
-              "%luk reserved, %luk data, %luk bss, %luk init)\n",
-               nr_free_pages() << (PAGE_SHIFT-10),
-               num_physpages << (PAGE_SHIFT-10),
-               codesize >> 10,
-               reservedpages << (PAGE_SHIFT-10),
-               datasize >> 10,
-               bsssize >> 10,
-               initsize >> 10);
-
+       mem_init_print_info(NULL);
 #ifdef CONFIG_PPC32
        pr_info("Kernel virtual memory layout:\n");
        pr_info("  * 0x%08lx..0x%08lx  : fixmap\n", FIXADDR_START, FIXADDR_TOP);
@@ -407,7 +360,7 @@ void free_initmem(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
 
index 3c475d6267c75b0db98584b0f4c7cd0379fd19d1..13c3f0e547a201947029c7f0096b2caeba03f30a 100644 (file)
 #define        PME_PM_BRU_FIN                  0x10068
 #define        PME_PM_BRU_MPRED                0x400f6
 
+#define PME_PM_CMPLU_STALL_FXU                 0x20014
+#define PME_PM_CMPLU_STALL_DIV                 0x40014
+#define PME_PM_CMPLU_STALL_SCALAR              0x40012
+#define PME_PM_CMPLU_STALL_SCALAR_LONG         0x20018
+#define PME_PM_CMPLU_STALL_VECTOR              0x2001c
+#define PME_PM_CMPLU_STALL_VECTOR_LONG         0x4004a
+#define PME_PM_CMPLU_STALL_LSU                 0x20012
+#define PME_PM_CMPLU_STALL_REJECT              0x40016
+#define PME_PM_CMPLU_STALL_ERAT_MISS           0x40018
+#define PME_PM_CMPLU_STALL_DCACHE_MISS         0x20016
+#define PME_PM_CMPLU_STALL_STORE               0x2004a
+#define PME_PM_CMPLU_STALL_THRD                        0x1001c
+#define PME_PM_CMPLU_STALL_IFU                 0x4004c
+#define PME_PM_CMPLU_STALL_BRU                 0x4004e
+#define PME_PM_GCT_NOSLOT_IC_MISS              0x2001a
+#define PME_PM_GCT_NOSLOT_BR_MPRED             0x4001a
+#define PME_PM_GCT_NOSLOT_BR_MPRED_IC_MISS     0x4001c
+#define PME_PM_GRP_CMPL                                0x30004
+#define PME_PM_1PLUS_PPC_CMPL                  0x100f2
+#define PME_PM_CMPLU_STALL_DFU                 0x2003c
+#define PME_PM_RUN_CYC                         0x200f4
+#define PME_PM_RUN_INST_CMPL                   0x400fa
+
 /*
  * Layout of constraint bits:
  * 6666555555555544444444443333333333222222222211111111110000000000
@@ -393,6 +416,31 @@ POWER_EVENT_ATTR(LD_MISS_L1,                       LD_MISS_L1);
 POWER_EVENT_ATTR(BRU_FIN,                      BRU_FIN)
 POWER_EVENT_ATTR(BRU_MPRED,                    BRU_MPRED);
 
+POWER_EVENT_ATTR(CMPLU_STALL_FXU,              CMPLU_STALL_FXU);
+POWER_EVENT_ATTR(CMPLU_STALL_DIV,              CMPLU_STALL_DIV);
+POWER_EVENT_ATTR(CMPLU_STALL_SCALAR,           CMPLU_STALL_SCALAR);
+POWER_EVENT_ATTR(CMPLU_STALL_SCALAR_LONG,      CMPLU_STALL_SCALAR_LONG);
+POWER_EVENT_ATTR(CMPLU_STALL_VECTOR,           CMPLU_STALL_VECTOR);
+POWER_EVENT_ATTR(CMPLU_STALL_VECTOR_LONG,      CMPLU_STALL_VECTOR_LONG);
+POWER_EVENT_ATTR(CMPLU_STALL_LSU,              CMPLU_STALL_LSU);
+POWER_EVENT_ATTR(CMPLU_STALL_REJECT,           CMPLU_STALL_REJECT);
+
+POWER_EVENT_ATTR(CMPLU_STALL_ERAT_MISS,                CMPLU_STALL_ERAT_MISS);
+POWER_EVENT_ATTR(CMPLU_STALL_DCACHE_MISS,      CMPLU_STALL_DCACHE_MISS);
+POWER_EVENT_ATTR(CMPLU_STALL_STORE,            CMPLU_STALL_STORE);
+POWER_EVENT_ATTR(CMPLU_STALL_THRD,             CMPLU_STALL_THRD);
+POWER_EVENT_ATTR(CMPLU_STALL_IFU,              CMPLU_STALL_IFU);
+POWER_EVENT_ATTR(CMPLU_STALL_BRU,              CMPLU_STALL_BRU);
+POWER_EVENT_ATTR(GCT_NOSLOT_IC_MISS,           GCT_NOSLOT_IC_MISS);
+
+POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED,          GCT_NOSLOT_BR_MPRED);
+POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED_IC_MISS,  GCT_NOSLOT_BR_MPRED_IC_MISS);
+POWER_EVENT_ATTR(GRP_CMPL,                     GRP_CMPL);
+POWER_EVENT_ATTR(1PLUS_PPC_CMPL,               1PLUS_PPC_CMPL);
+POWER_EVENT_ATTR(CMPLU_STALL_DFU,              CMPLU_STALL_DFU);
+POWER_EVENT_ATTR(RUN_CYC,                      RUN_CYC);
+POWER_EVENT_ATTR(RUN_INST_CMPL,                        RUN_INST_CMPL);
+
 static struct attribute *power7_events_attr[] = {
        GENERIC_EVENT_PTR(CYC),
        GENERIC_EVENT_PTR(GCT_NOSLOT_CYC),
@@ -411,6 +459,31 @@ static struct attribute *power7_events_attr[] = {
        POWER_EVENT_PTR(LD_MISS_L1),
        POWER_EVENT_PTR(BRU_FIN),
        POWER_EVENT_PTR(BRU_MPRED),
+
+       POWER_EVENT_PTR(CMPLU_STALL_FXU),
+       POWER_EVENT_PTR(CMPLU_STALL_DIV),
+       POWER_EVENT_PTR(CMPLU_STALL_SCALAR),
+       POWER_EVENT_PTR(CMPLU_STALL_SCALAR_LONG),
+       POWER_EVENT_PTR(CMPLU_STALL_VECTOR),
+       POWER_EVENT_PTR(CMPLU_STALL_VECTOR_LONG),
+       POWER_EVENT_PTR(CMPLU_STALL_LSU),
+       POWER_EVENT_PTR(CMPLU_STALL_REJECT),
+
+       POWER_EVENT_PTR(CMPLU_STALL_ERAT_MISS),
+       POWER_EVENT_PTR(CMPLU_STALL_DCACHE_MISS),
+       POWER_EVENT_PTR(CMPLU_STALL_STORE),
+       POWER_EVENT_PTR(CMPLU_STALL_THRD),
+       POWER_EVENT_PTR(CMPLU_STALL_IFU),
+       POWER_EVENT_PTR(CMPLU_STALL_BRU),
+       POWER_EVENT_PTR(GCT_NOSLOT_IC_MISS),
+       POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED),
+
+       POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED_IC_MISS),
+       POWER_EVENT_PTR(GRP_CMPL),
+       POWER_EVENT_PTR(1PLUS_PPC_CMPL),
+       POWER_EVENT_PTR(CMPLU_STALL_DFU),
+       POWER_EVENT_PTR(RUN_CYC),
+       POWER_EVENT_PTR(RUN_INST_CMPL),
        NULL
 };
 
index b62aab3e22ecd0447caf0db7ff97c2c16bc12644..e17cdfc5ba40bf0b10283dfbf7e66a7a92eebb28 100644 (file)
@@ -193,37 +193,6 @@ config PPC_IO_WORKAROUNDS
 
 source "drivers/cpufreq/Kconfig"
 
-menu "CPU Frequency drivers"
-       depends on CPU_FREQ
-
-config CPU_FREQ_PMAC
-       bool "Support for Apple PowerBooks"
-       depends on ADB_PMU && PPC32
-       select CPU_FREQ_TABLE
-       help
-         This adds support for frequency switching on Apple PowerBooks,
-         this currently includes some models of iBook & Titanium
-         PowerBook.
-
-config CPU_FREQ_PMAC64
-       bool "Support for some Apple G5s"
-       depends on PPC_PMAC && PPC64
-       select CPU_FREQ_TABLE
-       help
-         This adds support for frequency switching on Apple iMac G5,
-         and some of the more recent desktop G5 machines as well.
-
-config PPC_PASEMI_CPUFREQ
-       bool "Support for PA Semi PWRficient"
-       depends on PPC_PASEMI
-       default y
-       select CPU_FREQ_TABLE
-       help
-         This adds the support for frequency switching on PA Semi
-         PWRficient processors.
-
-endmenu
-
 menu "CPUIdle driver"
 
 source "drivers/cpuidle/Kconfig"
index 54f3936001aa1a51a1117b338a4ff06963d27411..7819c40a6bc3a133224d20e5ecdcfddb2b845907 100644 (file)
@@ -158,6 +158,7 @@ config E500
 config PPC_E500MC
        bool "e500mc Support"
        select PPC_FPU
+       select COMMON_CLK
        depends on E500
        help
          This must be enabled for running on e500mc (and derivatives
index ce6d789e0741c8785ba7e213ad007b8de3428fb1..8e8d4cae5ebe731ff5b1c45723ec11ba4c13c68f 100644 (file)
@@ -1,3 +1,2 @@
 obj-y  += setup.o pci.o time.o idle.o powersave.o iommu.o dma_lib.o misc.o
 obj-$(CONFIG_PPC_PASEMI_MDIO)  += gpio_mdio.o
-obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o
index ea47df66fee5235588061efb08d5e2a6be685f4e..52c6ce1cc985ba33c93a9afc35572b5dc9457d8c 100644 (file)
@@ -9,8 +9,6 @@ obj-y                           += pic.o setup.o time.o feature.o pci.o \
                                   sleep.o low_i2c.o cache.o pfunc_core.o \
                                   pfunc_base.o udbg_scc.o udbg_adb.o
 obj-$(CONFIG_PMAC_BACKLIGHT)   += backlight.o
-obj-$(CONFIG_CPU_FREQ_PMAC)    += cpufreq_32.o
-obj-$(CONFIG_CPU_FREQ_PMAC64)  += cpufreq_64.o
 # CONFIG_NVRAM is an arch. independent tristate symbol, for pmac32 we really
 # need this to be a bool.  Cheat here and pretend CONFIG_NVRAM=m is really
 # CONFIG_NVRAM=y
index 7ef60b52d6e0ef7ae1e55aebb78c8a7d562cef4a..42be537431338b5261a829a5266cd6fc2852b3ed 100644 (file)
@@ -32,7 +32,7 @@
  * book:
  * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
-static struct appldata_mem_data {
+struct appldata_mem_data {
        u64 timestamp;
        u32 sync_count_1;       /* after VM collected the record data, */
        u32 sync_count_2;       /* sync_count_1 and sync_count_2 should be the
@@ -63,7 +63,7 @@ static struct appldata_mem_data {
        u64 pgmajfault;         /* page faults (major only) */
 // <-- New in 2.6
 
-} __attribute__((packed)) appldata_mem_data;
+} __packed;
 
 
 /*
@@ -118,7 +118,6 @@ static struct appldata_ops ops = {
        .record_nr = APPLDATA_RECORD_MEM_ID,
        .size      = sizeof(struct appldata_mem_data),
        .callback  = &appldata_get_mem_data,
-       .data      = &appldata_mem_data,
        .owner     = THIS_MODULE,
        .mod_lvl   = {0xF0, 0xF0},              /* EBCDIC "00" */
 };
@@ -131,7 +130,17 @@ static struct appldata_ops ops = {
  */
 static int __init appldata_mem_init(void)
 {
-       return appldata_register_ops(&ops);
+       int ret;
+
+       ops.data = kzalloc(sizeof(struct appldata_mem_data), GFP_KERNEL);
+       if (!ops.data)
+               return -ENOMEM;
+
+       ret = appldata_register_ops(&ops);
+       if (ret)
+               kfree(ops.data);
+
+       return ret;
 }
 
 /*
@@ -142,6 +151,7 @@ static int __init appldata_mem_init(void)
 static void __exit appldata_mem_exit(void)
 {
        appldata_unregister_ops(&ops);
+       kfree(ops.data);
 }
 
 
index 2d224b945355c2897ac9b805284245f5f2ab0204..66037d2622b4075c708068a414aa4b346f8740c1 100644 (file)
@@ -29,7 +29,7 @@
  * book:
  * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
-static struct appldata_net_sum_data {
+struct appldata_net_sum_data {
        u64 timestamp;
        u32 sync_count_1;       /* after VM collected the record data, */
        u32 sync_count_2;       /* sync_count_1 and sync_count_2 should be the
@@ -51,7 +51,7 @@ static struct appldata_net_sum_data {
        u64 rx_dropped;         /* no space in linux buffers     */
        u64 tx_dropped;         /* no space available in linux   */
        u64 collisions;         /* collisions while transmitting */
-} __attribute__((packed)) appldata_net_sum_data;
+} __packed;
 
 
 /*
@@ -121,7 +121,6 @@ static struct appldata_ops ops = {
        .record_nr = APPLDATA_RECORD_NET_SUM_ID,
        .size      = sizeof(struct appldata_net_sum_data),
        .callback  = &appldata_get_net_sum_data,
-       .data      = &appldata_net_sum_data,
        .owner     = THIS_MODULE,
        .mod_lvl   = {0xF0, 0xF0},              /* EBCDIC "00" */
 };
@@ -134,7 +133,17 @@ static struct appldata_ops ops = {
  */
 static int __init appldata_net_init(void)
 {
-       return appldata_register_ops(&ops);
+       int ret;
+
+       ops.data = kzalloc(sizeof(struct appldata_net_sum_data), GFP_KERNEL);
+       if (!ops.data)
+               return -ENOMEM;
+
+       ret = appldata_register_ops(&ops);
+       if (ret)
+               kfree(ops.data);
+
+       return ret;
 }
 
 /*
@@ -145,6 +154,7 @@ static int __init appldata_net_init(void)
 static void __exit appldata_net_exit(void)
 {
        appldata_unregister_ops(&ops);
+       kfree(ops.data);
 }
 
 
index 7fd3690b676050eab20af1caf6a2c50b6a73aba0..138893e5f736f4e186a7cb04285fc55966950bfe 100644 (file)
@@ -651,9 +651,7 @@ static int hypfs_create_cpu_files(struct super_block *sb,
        }
        diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
        rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
-       if (IS_ERR(rc))
-               return PTR_ERR(rc);
-       return 0;
+       return PTR_RET(rc);
 }
 
 static void *hypfs_create_lpar_files(struct super_block *sb,
@@ -702,9 +700,7 @@ static int hypfs_create_phys_cpu_files(struct super_block *sb,
                return PTR_ERR(rc);
        diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
        rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
-       if (IS_ERR(rc))
-               return PTR_ERR(rc);
-       return 0;
+       return PTR_RET(rc);
 }
 
 static void *hypfs_create_phys_files(struct super_block *sb,
index 9819891ed7a20c74d2804fe31723439ad88600e8..4066cee0c2d2635e32a59fecb0eaf2e05c565776 100644 (file)
@@ -9,9 +9,18 @@
 #ifndef _ASM_S390_AIRQ_H
 #define _ASM_S390_AIRQ_H
 
-typedef void (*adapter_int_handler_t)(void *, void *);
+struct airq_struct {
+       struct hlist_node list;         /* Handler queueing. */
+       void (*handler)(struct airq_struct *);  /* Thin-interrupt handler */
+       u8 *lsi_ptr;                    /* Local-Summary-Indicator pointer */
+       u8 lsi_mask;                    /* Local-Summary-Indicator mask */
+       u8 isc;                         /* Interrupt-subclass */
+       u8 flags;
+};
 
-void *s390_register_adapter_interrupt(adapter_int_handler_t, void *, u8);
-void s390_unregister_adapter_interrupt(void *, u8);
+#define AIRQ_PTR_ALLOCATED     0x01
+
+int register_adapter_interrupt(struct airq_struct *airq);
+void unregister_adapter_interrupt(struct airq_struct *airq);
 
 #endif /* _ASM_S390_AIRQ_H */
index 2f8c1abeb086999ada3a2938973b8054f112625e..3fbc67d9e19739edbf5be625a68c5f7e34153771 100644 (file)
@@ -53,7 +53,7 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
        debug_dma_mapping_error(dev, dma_addr);
        if (dma_ops->mapping_error)
                return dma_ops->mapping_error(dev, dma_addr);
-       return (dma_addr == DMA_ERROR_CODE);
+       return dma_addr == DMA_ERROR_CODE;
 }
 
 static inline void *dma_alloc_coherent(struct device *dev, size_t size,
index 2ee66a65f2d4740572791c46b9cf42a9c4e65d51..0aa6a7ed95a35cc441f711b2ba92f2c69b1afdad 100644 (file)
 
 #define MAX_FACILITY_BIT (256*8)       /* stfle_fac_list has 256 bytes */
 
+static inline int __test_facility(unsigned long nr, void *facilities)
+{
+       unsigned char *ptr;
+
+       if (nr >= MAX_FACILITY_BIT)
+               return 0;
+       ptr = (unsigned char *) facilities + (nr >> 3);
+       return (*ptr & (0x80 >> (nr & 7))) != 0;
+}
+
 /*
  * The test_facility function uses the bit odering where the MSB is bit 0.
  * That makes it easier to query facility bits with the bit number as
  */
 static inline int test_facility(unsigned long nr)
 {
-       unsigned char *ptr;
-
-       if (nr >= MAX_FACILITY_BIT)
-               return 0;
-       ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
-       return (*ptr & (0x80 >> (nr & 7))) != 0;
+       return __test_facility(nr, &S390_lowcore.stfle_fac_list);
 }
 
 /**
index fd9be010f9b2614c4b4e75f00e9fefad18cf0855..cd6b9ee7b69c928118e9bce7c8691651a79a9b52 100644 (file)
 #include <asm/page.h>
 #include <asm/pci_io.h>
 
-/*
- * Change virtual addresses to physical addresses and vv.
- * These are pretty trivial
- */
-static inline unsigned long virt_to_phys(volatile void * address)
-{
-       unsigned long real_address;
-       asm volatile(
-                "      lra     %0,0(%1)\n"
-                "      jz      0f\n"
-                "      la      %0,0\n"
-                "0:"
-                : "=a" (real_address) : "a" (address) : "cc");
-       return real_address;
-}
-#define virt_to_phys virt_to_phys
-
-static inline void * phys_to_virt(unsigned long address)
-{
-       return (void *) address;
-}
-
 void *xlate_dev_mem_ptr(unsigned long phys);
 #define xlate_dev_mem_ptr xlate_dev_mem_ptr
 void unxlate_dev_mem_ptr(unsigned long phys, void *addr);
index 16bd5d169cdb4779c975cdd379160ff3ef6d637c..3238d4004e8436aa1a7d1e5eb3d811fe065d0dcb 100644 (file)
@@ -62,13 +62,20 @@ struct sca_block {
 #define CPUSTAT_MCDS       0x00000100
 #define CPUSTAT_SM         0x00000080
 #define CPUSTAT_G          0x00000008
+#define CPUSTAT_GED        0x00000004
 #define CPUSTAT_J          0x00000002
 #define CPUSTAT_P          0x00000001
 
 struct kvm_s390_sie_block {
        atomic_t cpuflags;              /* 0x0000 */
        __u32   prefix;                 /* 0x0004 */
-       __u8    reserved8[32];          /* 0x0008 */
+       __u8    reserved08[4];          /* 0x0008 */
+#define PROG_IN_SIE (1<<0)
+       __u32   prog0c;                 /* 0x000c */
+       __u8    reserved10[16];         /* 0x0010 */
+#define PROG_BLOCK_SIE 0x00000001
+       atomic_t prog20;                /* 0x0020 */
+       __u8    reserved24[4];          /* 0x0024 */
        __u64   cputm;                  /* 0x0028 */
        __u64   ckc;                    /* 0x0030 */
        __u64   epoch;                  /* 0x0038 */
@@ -90,7 +97,8 @@ struct kvm_s390_sie_block {
        __u32   scaoh;                  /* 0x005c */
        __u8    reserved60;             /* 0x0060 */
        __u8    ecb;                    /* 0x0061 */
-       __u8    reserved62[2];          /* 0x0062 */
+       __u8    ecb2;                   /* 0x0062 */
+       __u8    reserved63[1];          /* 0x0063 */
        __u32   scaol;                  /* 0x0064 */
        __u8    reserved68[4];          /* 0x0068 */
        __u32   todpr;                  /* 0x006c */
@@ -130,6 +138,7 @@ struct kvm_vcpu_stat {
        u32 deliver_program_int;
        u32 deliver_io_int;
        u32 exit_wait_state;
+       u32 instruction_pfmf;
        u32 instruction_stidp;
        u32 instruction_spx;
        u32 instruction_stpx;
@@ -166,7 +175,7 @@ struct kvm_s390_ext_info {
 };
 
 #define PGM_OPERATION            0x01
-#define PGM_PRIVILEGED_OPERATION 0x02
+#define PGM_PRIVILEGED_OP       0x02
 #define PGM_EXECUTE              0x03
 #define PGM_PROTECTION           0x04
 #define PGM_ADDRESSING           0x05
@@ -219,7 +228,7 @@ struct kvm_s390_local_interrupt {
        atomic_t active;
        struct kvm_s390_float_interrupt *float_int;
        int timer_due; /* event indicator for waitqueue below */
-       wait_queue_head_t wq;
+       wait_queue_head_t *wq;
        atomic_t *cpuflags;
        unsigned int action_bits;
 };
@@ -266,4 +275,5 @@ struct kvm_arch{
 };
 
 extern int sie64a(struct kvm_s390_sie_block *, u64 *);
+extern char sie_exit;
 #endif
index 6c1801235db961363a14512dda7c306ab2d9a724..6e577ba0e5daa12256590018dfeddb4071a1e892 100644 (file)
@@ -120,7 +120,6 @@ struct zpci_dev {
 
        struct dentry   *debugfs_dev;
        struct dentry   *debugfs_perf;
-       struct dentry   *debugfs_debug;
 };
 
 struct pci_hp_callback_ops {
@@ -143,7 +142,6 @@ int zpci_enable_device(struct zpci_dev *);
 int zpci_disable_device(struct zpci_dev *);
 void zpci_stop_device(struct zpci_dev *);
 void zpci_free_device(struct zpci_dev *);
-int zpci_scan_device(struct zpci_dev *);
 int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
 int zpci_unregister_ioat(struct zpci_dev *, u8);
 
index 5f0173a31693b19700b8afa92b60db199bfcb749..1141fb3e7b21e6ad2e915835eb571301982cf29e 100644 (file)
 /* Per-CPU flags for PMU states */
 #define PMU_F_RESERVED                 0x1000
 #define PMU_F_ENABLED                  0x2000
+
+#ifdef CONFIG_64BIT
+
+/* Perf callbacks */
+struct pt_regs;
+extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
+extern unsigned long perf_misc_flags(struct pt_regs *regs);
+#define perf_misc_flags(regs) perf_misc_flags(regs)
+
+#endif /* CONFIG_64BIT */
index 590c3219c63445f2214a1befc033b7d28e0cf10f..e1408ddb94f8d6d5107561374bb759a37c5d8eb1 100644 (file)
@@ -22,6 +22,9 @@ unsigned long *page_table_alloc(struct mm_struct *, unsigned long);
 void page_table_free(struct mm_struct *, unsigned long *);
 void page_table_free_rcu(struct mmu_gather *, unsigned long *);
 
+int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
+                         unsigned long key, bool nq);
+
 static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
 {
        typedef struct { char _[n]; } addrtype;
index 9aefa3c64eb2d32ab756512e035762613277caa8..0ea4e591fa781e58d89a8e05a195dd70ecba90f7 100644 (file)
@@ -296,18 +296,16 @@ extern unsigned long MODULES_END;
 #define _SEGMENT_ENTRY_EMPTY   (_SEGMENT_ENTRY_INV)
 
 /* Page status table bits for virtualization */
-#define RCP_ACC_BITS   0xf0000000UL
-#define RCP_FP_BIT     0x08000000UL
-#define RCP_PCL_BIT    0x00800000UL
-#define RCP_HR_BIT     0x00400000UL
-#define RCP_HC_BIT     0x00200000UL
-#define RCP_GR_BIT     0x00040000UL
-#define RCP_GC_BIT     0x00020000UL
-#define RCP_IN_BIT     0x00002000UL    /* IPTE notify bit */
-
-/* User dirty / referenced bit for KVM's migration feature */
-#define KVM_UR_BIT     0x00008000UL
-#define KVM_UC_BIT     0x00004000UL
+#define PGSTE_ACC_BITS 0xf0000000UL
+#define PGSTE_FP_BIT   0x08000000UL
+#define PGSTE_PCL_BIT  0x00800000UL
+#define PGSTE_HR_BIT   0x00400000UL
+#define PGSTE_HC_BIT   0x00200000UL
+#define PGSTE_GR_BIT   0x00040000UL
+#define PGSTE_GC_BIT   0x00020000UL
+#define PGSTE_UR_BIT   0x00008000UL
+#define PGSTE_UC_BIT   0x00004000UL    /* user dirty (migration) */
+#define PGSTE_IN_BIT   0x00002000UL    /* IPTE notify bit */
 
 #else /* CONFIG_64BIT */
 
@@ -364,18 +362,16 @@ extern unsigned long MODULES_END;
                                 | _SEGMENT_ENTRY_SPLIT | _SEGMENT_ENTRY_CO)
 
 /* Page status table bits for virtualization */
-#define RCP_ACC_BITS   0xf000000000000000UL
-#define RCP_FP_BIT     0x0800000000000000UL
-#define RCP_PCL_BIT    0x0080000000000000UL
-#define RCP_HR_BIT     0x0040000000000000UL
-#define RCP_HC_BIT     0x0020000000000000UL
-#define RCP_GR_BIT     0x0004000000000000UL
-#define RCP_GC_BIT     0x0002000000000000UL
-#define RCP_IN_BIT     0x0000200000000000UL    /* IPTE notify bit */
-
-/* User dirty / referenced bit for KVM's migration feature */
-#define KVM_UR_BIT     0x0000800000000000UL
-#define KVM_UC_BIT     0x0000400000000000UL
+#define PGSTE_ACC_BITS 0xf000000000000000UL
+#define PGSTE_FP_BIT   0x0800000000000000UL
+#define PGSTE_PCL_BIT  0x0080000000000000UL
+#define PGSTE_HR_BIT   0x0040000000000000UL
+#define PGSTE_HC_BIT   0x0020000000000000UL
+#define PGSTE_GR_BIT   0x0004000000000000UL
+#define PGSTE_GC_BIT   0x0002000000000000UL
+#define PGSTE_UR_BIT   0x0000800000000000UL
+#define PGSTE_UC_BIT   0x0000400000000000UL    /* user dirty (migration) */
+#define PGSTE_IN_BIT   0x0000200000000000UL    /* IPTE notify bit */
 
 #endif /* CONFIG_64BIT */
 
@@ -615,8 +611,8 @@ static inline pgste_t pgste_get_lock(pte_t *ptep)
        asm(
                "       lg      %0,%2\n"
                "0:     lgr     %1,%0\n"
-               "       nihh    %0,0xff7f\n"    /* clear RCP_PCL_BIT in old */
-               "       oihh    %1,0x0080\n"    /* set RCP_PCL_BIT in new */
+               "       nihh    %0,0xff7f\n"    /* clear PCL bit in old */
+               "       oihh    %1,0x0080\n"    /* set PCL bit in new */
                "       csg     %0,%1,%2\n"
                "       jl      0b\n"
                : "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE])
@@ -629,7 +625,7 @@ static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
        asm(
-               "       nihh    %1,0xff7f\n"    /* clear RCP_PCL_BIT */
+               "       nihh    %1,0xff7f\n"    /* clear PCL bit */
                "       stg     %1,%0\n"
                : "=Q" (ptep[PTRS_PER_PTE])
                : "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE])
@@ -662,14 +658,14 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
        else if (bits)
                page_reset_referenced(address);
        /* Transfer page changed & referenced bit to guest bits in pgste */
-       pgste_val(pgste) |= bits << 48;         /* RCP_GR_BIT & RCP_GC_BIT */
+       pgste_val(pgste) |= bits << 48;         /* GR bit & GC bit */
        /* Get host changed & referenced bits from pgste */
-       bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52;
+       bits |= (pgste_val(pgste) & (PGSTE_HR_BIT | PGSTE_HC_BIT)) >> 52;
        /* Transfer page changed & referenced bit to kvm user bits */
-       pgste_val(pgste) |= bits << 45;         /* KVM_UR_BIT & KVM_UC_BIT */
+       pgste_val(pgste) |= bits << 45;         /* PGSTE_UR_BIT & PGSTE_UC_BIT */
        /* Clear relevant host bits in pgste. */
-       pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT);
-       pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT);
+       pgste_val(pgste) &= ~(PGSTE_HR_BIT | PGSTE_HC_BIT);
+       pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT);
        /* Copy page access key and fetch protection bit to pgste */
        pgste_val(pgste) |=
                (unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
@@ -690,15 +686,15 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
        /* Get referenced bit from storage key */
        young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
        if (young)
-               pgste_val(pgste) |= RCP_GR_BIT;
+               pgste_val(pgste) |= PGSTE_GR_BIT;
        /* Get host referenced bit from pgste */
-       if (pgste_val(pgste) & RCP_HR_BIT) {
-               pgste_val(pgste) &= ~RCP_HR_BIT;
+       if (pgste_val(pgste) & PGSTE_HR_BIT) {
+               pgste_val(pgste) &= ~PGSTE_HR_BIT;
                young = 1;
        }
        /* Transfer referenced bit to kvm user bits and pte */
        if (young) {
-               pgste_val(pgste) |= KVM_UR_BIT;
+               pgste_val(pgste) |= PGSTE_UR_BIT;
                pte_val(*ptep) |= _PAGE_SWR;
        }
 #endif
@@ -720,7 +716,7 @@ static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry)
         * The guest C/R information is still in the PGSTE, set real
         * key C/R to 0.
         */
-       nkey = (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56;
+       nkey = (pgste_val(pgste) & (PGSTE_ACC_BITS | PGSTE_FP_BIT)) >> 56;
        page_set_storage_key(address, nkey, 0);
 #endif
 }
@@ -750,6 +746,7 @@ struct gmap {
        struct mm_struct *mm;
        unsigned long *table;
        unsigned long asce;
+       void *private;
        struct list_head crst_list;
 };
 
@@ -808,8 +805,8 @@ static inline pgste_t pgste_ipte_notify(struct mm_struct *mm,
                                        pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
-       if (pgste_val(pgste) & RCP_IN_BIT) {
-               pgste_val(pgste) &= ~RCP_IN_BIT;
+       if (pgste_val(pgste) & PGSTE_IN_BIT) {
+               pgste_val(pgste) &= ~PGSTE_IN_BIT;
                gmap_do_ipte_notify(mm, addr, ptep);
        }
 #endif
@@ -977,8 +974,8 @@ static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm,
        if (mm_has_pgste(mm)) {
                pgste = pgste_get_lock(ptep);
                pgste = pgste_update_all(ptep, pgste);
-               dirty = !!(pgste_val(pgste) & KVM_UC_BIT);
-               pgste_val(pgste) &= ~KVM_UC_BIT;
+               dirty = !!(pgste_val(pgste) & PGSTE_UC_BIT);
+               pgste_val(pgste) &= ~PGSTE_UC_BIT;
                pgste_set_unlock(ptep, pgste);
                return dirty;
        }
@@ -997,8 +994,8 @@ static inline int ptep_test_and_clear_user_young(struct mm_struct *mm,
        if (mm_has_pgste(mm)) {
                pgste = pgste_get_lock(ptep);
                pgste = pgste_update_young(ptep, pgste);
-               young = !!(pgste_val(pgste) & KVM_UR_BIT);
-               pgste_val(pgste) &= ~KVM_UR_BIT;
+               young = !!(pgste_val(pgste) & PGSTE_UR_BIT);
+               pgste_val(pgste) &= ~PGSTE_UR_BIT;
                pgste_set_unlock(ptep, pgste);
        }
        return young;
index 559512a455dabba842d5f4ade3b580fa61ea4b44..52b56533c57cda08f4d8283253ed682a13536f5c 100644 (file)
@@ -24,6 +24,7 @@ struct pt_regs
        unsigned long gprs[NUM_GPRS];
        unsigned long orig_gpr2;
        unsigned int int_code;
+       unsigned int int_parm;
        unsigned long int_parm_long;
 };
 
index 9ccd1905bdad45da5d0f1b18ffae312f59957a7b..6a9a9eb645f523ee203ae87f3c4395de18b578f7 100644 (file)
@@ -35,6 +35,7 @@ header-y += siginfo.h
 header-y += signal.h
 header-y += socket.h
 header-y += sockios.h
+header-y += sclp_ctl.h
 header-y += stat.h
 header-y += statfs.h
 header-y += swab.h
index 1c6a7f85a5819d5354acb38f91820be5767d789c..65dc694725a85d29ba5d15781afff89fd717c59e 100644 (file)
@@ -29,6 +29,16 @@ struct chsc_async_area {
        __u8 data[CHSC_SIZE - sizeof(struct chsc_async_header)];
 } __attribute__ ((packed));
 
+struct chsc_header {
+       __u16 length;
+       __u16 code;
+} __attribute__ ((packed));
+
+struct chsc_sync_area {
+       struct chsc_header header;
+       __u8 data[CHSC_SIZE - sizeof(struct chsc_header)];
+} __attribute__ ((packed));
+
 struct chsc_response_struct {
        __u16 length;
        __u16 code;
@@ -126,5 +136,8 @@ struct chsc_cpd_info {
 #define CHSC_INFO_CCL _IOWR(CHSC_IOCTL_MAGIC, 0x86, struct chsc_comp_list)
 #define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info)
 #define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal)
+#define CHSC_START_SYNC _IOWR(CHSC_IOCTL_MAGIC, 0x89, struct chsc_sync_area)
+#define CHSC_ON_CLOSE_SET _IOWR(CHSC_IOCTL_MAGIC, 0x8a, struct chsc_async_area)
+#define CHSC_ON_CLOSE_REMOVE _IO(CHSC_IOCTL_MAGIC, 0x8b)
 
 #endif
index 38eca3ba40e28a3c5bb2e710bbca2f8e9e8d201d..5812a3b2df9e29ff1f639e59f748a686298ad0eb 100644 (file)
@@ -261,6 +261,10 @@ struct dasd_snid_ioctl_data {
 #define BIODASDQUIESCE _IO(DASD_IOCTL_LETTER,6) 
 /* Resume IO on device */
 #define BIODASDRESUME  _IO(DASD_IOCTL_LETTER,7) 
+/* Abort all I/O on a device */
+#define BIODASDABORTIO _IO(DASD_IOCTL_LETTER, 240)
+/* Allow I/O on a device */
+#define BIODASDALLOWIO _IO(DASD_IOCTL_LETTER, 241)
 
 
 /* retrieve API version number */
diff --git a/arch/s390/include/uapi/asm/sclp_ctl.h b/arch/s390/include/uapi/asm/sclp_ctl.h
new file mode 100644 (file)
index 0000000..f281861
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * IOCTL interface for SCLP
+ *
+ * Copyright IBM Corp. 2012
+ *
+ * Author: Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#ifndef _ASM_SCLP_CTL_H
+#define _ASM_SCLP_CTL_H
+
+#include <linux/types.h>
+
+struct sclp_ctl_sccb {
+       __u32   cmdw;
+       __u64   sccb;
+} __attribute__((packed));
+
+#define SCLP_CTL_IOCTL_MAGIC 0x10
+
+#define SCLP_CTL_SCCB \
+       _IOWR(SCLP_CTL_IOCTL_MAGIC, 0x10, struct sclp_ctl_sccb)
+
+#endif
index 7a82f9f7010015e4d73349a1a46426017a4088dd..2416138ebd3e5fa5584d897737e27ab7e0978383 100644 (file)
@@ -7,6 +7,7 @@
 #define ASM_OFFSETS_C
 
 #include <linux/kbuild.h>
+#include <linux/kvm_host.h>
 #include <linux/sched.h>
 #include <asm/cputime.h>
 #include <asm/vdso.h>
@@ -47,6 +48,7 @@ int main(void)
        DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
        DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
        DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code));
+       DEFINE(__PT_INT_PARM, offsetof(struct pt_regs, int_parm));
        DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long));
        DEFINE(__PT_SIZE, sizeof(struct pt_regs));
        BLANK();
@@ -161,6 +163,8 @@ int main(void)
        DEFINE(__LC_PGM_TDB, offsetof(struct _lowcore, pgm_tdb));
        DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));
        DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce));
+       DEFINE(__SIE_PROG0C, offsetof(struct kvm_s390_sie_block, prog0c));
+       DEFINE(__SIE_PROG20, offsetof(struct kvm_s390_sie_block, prog20));
 #endif /* CONFIG_32BIT */
        return 0;
 }
index 4d5e6f8a7978cb005d0ae15fe3d1837175f285d1..be7a408be7a16bafde657665edb36fcde01c8866 100644 (file)
@@ -429,11 +429,19 @@ io_skip:
        stm     %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
        stm     %r8,%r9,__PT_PSW(%r11)
+       mvc     __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
        TRACE_IRQS_OFF
        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
+io_loop:
        l       %r1,BASED(.Ldo_IRQ)
        lr      %r2,%r11                # pass pointer to pt_regs
        basr    %r14,%r1                # call do_IRQ
+       tm      __LC_MACHINE_FLAGS+2,0x10       # MACHINE_FLAG_LPAR
+       jz      io_return
+       tpi     0
+       jz      io_return
+       mvc     __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
+       j       io_loop
 io_return:
        LOCKDEP_SYS_EXIT
        TRACE_IRQS_ON
@@ -573,10 +581,10 @@ ext_skip:
        stm     %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
        stm     %r8,%r9,__PT_PSW(%r11)
+       mvc     __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
+       mvc     __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
        TRACE_IRQS_OFF
        lr      %r2,%r11                # pass pointer to pt_regs
-       l       %r3,__LC_EXT_CPU_ADDR   # get cpu address + interruption code
-       l       %r4,__LC_EXT_PARAMS     # get external parameters
        l       %r1,BASED(.Ldo_extint)
        basr    %r14,%r1                # call do_extint
        j       io_return
index aa0ab02e9595f8c6d21d6827a8b0ca261c0d71ec..3ddbc26d246e399a0e01bd295c1d9bbec741f034 100644 (file)
@@ -54,7 +54,7 @@ void handle_signal32(unsigned long sig, struct k_sigaction *ka,
 void do_notify_resume(struct pt_regs *regs);
 
 struct ext_code;
-void do_extint(struct pt_regs *regs, struct ext_code, unsigned int, unsigned long);
+void do_extint(struct pt_regs *regs);
 void do_restart(void);
 void __init startup_init(void);
 void die(struct pt_regs *regs, const char *str);
index 4c17eece707eb94d0b08c55b63a25b7788fb0c56..1c039d0c24c7e8b6b65e1aec20307adcabca581b 100644 (file)
@@ -47,7 +47,6 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
                 _TIF_MCCK_PENDING)
 _TIF_TRACE    = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
                 _TIF_SYSCALL_TRACEPOINT)
-_TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
 
 #define BASED(name) name-system_call(%r13)
 
@@ -81,23 +80,27 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
 #endif
        .endm
 
-       .macro  HANDLE_SIE_INTERCEPT scratch,pgmcheck
+       .macro  HANDLE_SIE_INTERCEPT scratch,reason
 #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
        tmhh    %r8,0x0001              # interrupting from user ?
-       jnz     .+42
+       jnz     .+62
        lgr     \scratch,%r9
-       slg     \scratch,BASED(.Lsie_loop)
-       clg     \scratch,BASED(.Lsie_length)
-       .if     \pgmcheck
+       slg     \scratch,BASED(.Lsie_critical)
+       clg     \scratch,BASED(.Lsie_critical_length)
+       .if     \reason==1
        # Some program interrupts are suppressing (e.g. protection).
        # We must also check the instruction after SIE in that case.
        # do_protection_exception will rewind to rewind_pad
-       jh      .+22
+       jh      .+42
        .else
-       jhe     .+22
+       jhe     .+42
        .endif
-       lg      %r9,BASED(.Lsie_loop)
-       LPP     BASED(.Lhost_id)        # set host id
+       lg      %r14,__SF_EMPTY(%r15)           # get control block pointer
+       LPP     __SF_EMPTY+16(%r15)             # set host id
+       ni      __SIE_PROG0C+3(%r14),0xfe       # no longer in SIE
+       lctlg   %c1,%c1,__LC_USER_ASCE          # load primary asce
+       larl    %r9,sie_exit                    # skip forward to sie_exit
+       mvi     __SF_EMPTY+31(%r15),\reason     # set exit reason
 #endif
        .endm
 
@@ -450,7 +453,7 @@ ENTRY(io_int_handler)
        lg      %r12,__LC_THREAD_INFO
        larl    %r13,system_call
        lmg     %r8,%r9,__LC_IO_OLD_PSW
-       HANDLE_SIE_INTERCEPT %r14,0
+       HANDLE_SIE_INTERCEPT %r14,2
        SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
        tmhh    %r8,0x0001              # interrupting from user?
        jz      io_skip
@@ -460,10 +463,18 @@ io_skip:
        stmg    %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
        stmg    %r8,%r9,__PT_PSW(%r11)
+       mvc     __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
        TRACE_IRQS_OFF
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
+io_loop:
        lgr     %r2,%r11                # pass pointer to pt_regs
        brasl   %r14,do_IRQ
+       tm      __LC_MACHINE_FLAGS+6,0x10       # MACHINE_FLAG_LPAR
+       jz      io_return
+       tpi     0
+       jz      io_return
+       mvc     __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
+       j       io_loop
 io_return:
        LOCKDEP_SYS_EXIT
        TRACE_IRQS_ON
@@ -595,7 +606,7 @@ ENTRY(ext_int_handler)
        lg      %r12,__LC_THREAD_INFO
        larl    %r13,system_call
        lmg     %r8,%r9,__LC_EXT_OLD_PSW
-       HANDLE_SIE_INTERCEPT %r14,0
+       HANDLE_SIE_INTERCEPT %r14,3
        SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
        tmhh    %r8,0x0001              # interrupting from user ?
        jz      ext_skip
@@ -605,13 +616,13 @@ ext_skip:
        stmg    %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
        stmg    %r8,%r9,__PT_PSW(%r11)
+       lghi    %r1,__LC_EXT_PARAMS2
+       mvc     __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
+       mvc     __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
+       mvc     __PT_INT_PARM_LONG(8,%r11),0(%r1)
        TRACE_IRQS_OFF
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
-       lghi    %r1,4096
        lgr     %r2,%r11                # pass pointer to pt_regs
-       llgf    %r3,__LC_EXT_CPU_ADDR   # get cpu address + interruption code
-       llgf    %r4,__LC_EXT_PARAMS     # get external parameter
-       lg      %r5,__LC_EXT_PARAMS2-4096(%r1)  # get 64 bit external parameter
        brasl   %r14,do_extint
        j       io_return
 
@@ -643,7 +654,7 @@ ENTRY(mcck_int_handler)
        lg      %r12,__LC_THREAD_INFO
        larl    %r13,system_call
        lmg     %r8,%r9,__LC_MCK_OLD_PSW
-       HANDLE_SIE_INTERCEPT %r14,0
+       HANDLE_SIE_INTERCEPT %r14,4
        tm      __LC_MCCK_CODE,0x80     # system damage?
        jo      mcck_panic              # yes -> rest of mcck code invalid
        lghi    %r14,__LC_CPU_TIMER_SAVE_AREA
@@ -937,56 +948,50 @@ ENTRY(sie64a)
        stmg    %r6,%r14,__SF_GPRS(%r15)        # save kernel registers
        stg     %r2,__SF_EMPTY(%r15)            # save control block pointer
        stg     %r3,__SF_EMPTY+8(%r15)          # save guest register save area
-       xc      __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # host id == 0
+       xc      __SF_EMPTY+16(16,%r15),__SF_EMPTY+16(%r15) # host id & reason
        lmg     %r0,%r13,0(%r3)                 # load guest gprs 0-13
-# some program checks are suppressing. C code (e.g. do_protection_exception)
-# will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other
-# instructions in the sie_loop should not cause program interrupts. So
-# lets use a nop (47 00 00 00) as a landing pad.
-# See also HANDLE_SIE_INTERCEPT
-rewind_pad:
-       nop     0
-sie_loop:
-       lg      %r14,__LC_THREAD_INFO           # pointer thread_info struct
-       tm      __TI_flags+7(%r14),_TIF_EXIT_SIE
-       jnz     sie_exit
        lg      %r14,__LC_GMAP                  # get gmap pointer
        ltgr    %r14,%r14
        jz      sie_gmap
        lctlg   %c1,%c1,__GMAP_ASCE(%r14)       # load primary asce
 sie_gmap:
        lg      %r14,__SF_EMPTY(%r15)           # get control block pointer
+       oi      __SIE_PROG0C+3(%r14),1          # we are going into SIE now
+       tm      __SIE_PROG20+3(%r14),1          # last exit...
+       jnz     sie_done
        LPP     __SF_EMPTY(%r15)                # set guest id
        sie     0(%r14)
 sie_done:
        LPP     __SF_EMPTY+16(%r15)             # set host id
-       lg      %r14,__LC_THREAD_INFO           # pointer thread_info struct
-sie_exit:
+       ni      __SIE_PROG0C+3(%r14),0xfe       # no longer in SIE
        lctlg   %c1,%c1,__LC_USER_ASCE          # load primary asce
+# some program checks are suppressing. C code (e.g. do_protection_exception)
+# will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other
+# instructions beween sie64a and sie_done should not cause program
+# interrupts. So lets use a nop (47 00 00 00) as a landing pad.
+# See also HANDLE_SIE_INTERCEPT
+rewind_pad:
+       nop     0
+       .globl sie_exit
+sie_exit:
        lg      %r14,__SF_EMPTY+8(%r15)         # load guest register save area
        stmg    %r0,%r13,0(%r14)                # save guest gprs 0-13
        lmg     %r6,%r14,__SF_GPRS(%r15)        # restore kernel registers
-       lghi    %r2,0
+       lg      %r2,__SF_EMPTY+24(%r15)         # return exit reason code
        br      %r14
 sie_fault:
-       lctlg   %c1,%c1,__LC_USER_ASCE          # load primary asce
-       lg      %r14,__LC_THREAD_INFO           # pointer thread_info struct
-       lg      %r14,__SF_EMPTY+8(%r15)         # load guest register save area
-       stmg    %r0,%r13,0(%r14)                # save guest gprs 0-13
-       lmg     %r6,%r14,__SF_GPRS(%r15)        # restore kernel registers
-       lghi    %r2,-EFAULT
-       br      %r14
+       lghi    %r14,-EFAULT
+       stg     %r14,__SF_EMPTY+24(%r15)        # set exit reason code
+       j       sie_exit
 
        .align  8
-.Lsie_loop:
-       .quad   sie_loop
-.Lsie_length:
-       .quad   sie_done - sie_loop
-.Lhost_id:
-       .quad   0
+.Lsie_critical:
+       .quad   sie_gmap
+.Lsie_critical_length:
+       .quad   sie_done - sie_gmap
 
        EX_TABLE(rewind_pad,sie_fault)
-       EX_TABLE(sie_loop,sie_fault)
+       EX_TABLE(sie_exit,sie_fault)
 #endif
 
                .section .rodata, "a"
index dd3c1994b8bd405c5fe986d99f5746893fa585a5..54b0995514e8721508d9c98cb801d3bf36195c0a 100644 (file)
@@ -234,9 +234,9 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
 }
 EXPORT_SYMBOL(unregister_external_interrupt);
 
-void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
-                          unsigned int param32, unsigned long param64)
+void __irq_entry do_extint(struct pt_regs *regs)
 {
+       struct ext_code ext_code;
        struct pt_regs *old_regs;
        struct ext_int_info *p;
        int index;
@@ -248,6 +248,7 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
                clock_comparator_work();
        }
        kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL);
+       ext_code = *(struct ext_code *) &regs->int_code;
        if (ext_code.code != 0x1004)
                __get_cpu_var(s390_idle).nohz_delay = 1;
 
@@ -255,7 +256,8 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
        rcu_read_lock();
        list_for_each_entry_rcu(p, &ext_int_hash[index], entry)
                if (likely(p->code == ext_code.code))
-                       p->handler(ext_code, param32, param64);
+                       p->handler(ext_code, regs->int_parm,
+                                  regs->int_parm_long);
        rcu_read_unlock();
        irq_exit();
        set_irq_regs(old_regs);
index f58f37f66824492c09acfc0c54c59c170be3e2a8..a6fc037671b11d0a2e96226256f9e36cd8e4d65d 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/perf_event.h>
+#include <linux/kvm_host.h>
 #include <linux/percpu.h>
 #include <linux/export.h>
 #include <asm/irq.h>
@@ -39,6 +40,57 @@ int perf_num_counters(void)
 }
 EXPORT_SYMBOL(perf_num_counters);
 
+static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs)
+{
+       struct stack_frame *stack = (struct stack_frame *) regs->gprs[15];
+
+       if (!stack)
+               return NULL;
+
+       return (struct kvm_s390_sie_block *) stack->empty1[0];
+}
+
+static bool is_in_guest(struct pt_regs *regs)
+{
+       unsigned long ip = instruction_pointer(regs);
+
+       if (user_mode(regs))
+               return false;
+
+       return ip == (unsigned long) &sie_exit;
+}
+
+static unsigned long guest_is_user_mode(struct pt_regs *regs)
+{
+       return sie_block(regs)->gpsw.mask & PSW_MASK_PSTATE;
+}
+
+static unsigned long instruction_pointer_guest(struct pt_regs *regs)
+{
+       return sie_block(regs)->gpsw.addr & PSW_ADDR_INSN;
+}
+
+unsigned long perf_instruction_pointer(struct pt_regs *regs)
+{
+       return is_in_guest(regs) ? instruction_pointer_guest(regs)
+                                : instruction_pointer(regs);
+}
+
+static unsigned long perf_misc_guest_flags(struct pt_regs *regs)
+{
+       return guest_is_user_mode(regs) ? PERF_RECORD_MISC_GUEST_USER
+                                       : PERF_RECORD_MISC_GUEST_KERNEL;
+}
+
+unsigned long perf_misc_flags(struct pt_regs *regs)
+{
+       if (is_in_guest(regs))
+               return perf_misc_guest_flags(regs);
+
+       return user_mode(regs) ? PERF_RECORD_MISC_USER
+                              : PERF_RECORD_MISC_KERNEL;
+}
+
 void perf_event_print_debug(void)
 {
        struct cpumf_ctr_info cf_info;
index 9bdbcef1da9ecd6ac0136973d59537252f6d3bf2..3bac589844a747c22136810d0f63600139111e3a 100644 (file)
@@ -7,6 +7,7 @@ EXPORT_SYMBOL(_mcount);
 #endif
 #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
 EXPORT_SYMBOL(sie64a);
+EXPORT_SYMBOL(sie_exit);
 #endif
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memset);
index 0a49095104c910f238cd9b28a9c79cf7a9958efc..497451ec5e267f3be025b9b719cf4f2278262d97 100644 (file)
@@ -719,10 +719,6 @@ static void reserve_oldmem(void)
        }
        create_mem_hole(memory_chunk, OLDMEM_BASE, OLDMEM_SIZE);
        create_mem_hole(memory_chunk, OLDMEM_SIZE, real_size - OLDMEM_SIZE);
-       if (OLDMEM_BASE + OLDMEM_SIZE == real_size)
-               saved_max_pfn = PFN_DOWN(OLDMEM_BASE) - 1;
-       else
-               saved_max_pfn = PFN_DOWN(real_size) - 1;
 #endif
 }
 
index 4f977d0d25c2d1b1af674314a0b3da263d602b5a..15a016c1056392969bf84af7d4c1afe34aace480 100644 (file)
@@ -49,7 +49,6 @@
 
 enum {
        ec_schedule = 0,
-       ec_call_function,
        ec_call_function_single,
        ec_stop_cpu,
 };
@@ -438,8 +437,6 @@ static void smp_handle_ext_call(void)
                smp_stop_cpu();
        if (test_bit(ec_schedule, &bits))
                scheduler_ipi();
-       if (test_bit(ec_call_function, &bits))
-               generic_smp_call_function_interrupt();
        if (test_bit(ec_call_function_single, &bits))
                generic_smp_call_function_single_interrupt();
 }
@@ -456,7 +453,7 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
        int cpu;
 
        for_each_cpu(cpu, mask)
-               pcpu_ec_call(pcpu_devices + cpu, ec_call_function);
+               pcpu_ec_call(pcpu_devices + cpu, ec_call_function_single);
 }
 
 void arch_send_call_function_single_ipi(int cpu)
index 8fe9d65a4585b0670c5a1c622d774632b3f39b18..40b4c6470f88a7181b7c8e703db2074016e348d5 100644 (file)
@@ -6,7 +6,8 @@
 # it under the terms of the GNU General Public License (version 2 only)
 # as published by the Free Software Foundation.
 
-common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o eventfd.o)
+KVM := ../../../virt/kvm
+common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o
 
 ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
 
index 1c01a99129896b42868c3dcb67cc2ceda66be97d..3074475c8ae062dbfa7c285b7217fbf2f2c87241 100644 (file)
@@ -132,6 +132,9 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
 {
        int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16;
 
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
        trace_kvm_s390_handle_diag(vcpu, code);
        switch (code) {
        case 0x10:
index b7d1b2edeeb35720402d9bf79055252f2d38ecd1..5ee56e5acc2396f594854dd8a3e0e99bc3b72720 100644 (file)
 #include "trace.h"
 #include "trace-s390.h"
 
-static int handle_lctlg(struct kvm_vcpu *vcpu)
-{
-       int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
-       int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
-       u64 useraddr;
-       int reg, rc;
-
-       vcpu->stat.instruction_lctlg++;
-
-       useraddr = kvm_s390_get_base_disp_rsy(vcpu);
-
-       if (useraddr & 7)
-               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
-
-       reg = reg1;
-
-       VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3,
-                  useraddr);
-       trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr);
-
-       do {
-               rc = get_guest(vcpu, vcpu->arch.sie_block->gcr[reg],
-                              (u64 __user *) useraddr);
-               if (rc)
-                       return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
-               useraddr += 8;
-               if (reg == reg3)
-                       break;
-               reg = (reg + 1) % 16;
-       } while (1);
-       return 0;
-}
-
-static int handle_lctl(struct kvm_vcpu *vcpu)
-{
-       int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
-       int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
-       u64 useraddr;
-       u32 val = 0;
-       int reg, rc;
-
-       vcpu->stat.instruction_lctl++;
-
-       useraddr = kvm_s390_get_base_disp_rs(vcpu);
-
-       if (useraddr & 3)
-               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
-
-       VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3,
-                  useraddr);
-       trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr);
-
-       reg = reg1;
-       do {
-               rc = get_guest(vcpu, val, (u32 __user *) useraddr);
-               if (rc)
-                       return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
-               vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul;
-               vcpu->arch.sie_block->gcr[reg] |= val;
-               useraddr += 4;
-               if (reg == reg3)
-                       break;
-               reg = (reg + 1) % 16;
-       } while (1);
-       return 0;
-}
-
-static const intercept_handler_t eb_handlers[256] = {
-       [0x2f] = handle_lctlg,
-       [0x8a] = kvm_s390_handle_priv_eb,
-};
-
-static int handle_eb(struct kvm_vcpu *vcpu)
-{
-       intercept_handler_t handler;
-
-       handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff];
-       if (handler)
-               return handler(vcpu);
-       return -EOPNOTSUPP;
-}
 
 static const intercept_handler_t instruction_handlers[256] = {
        [0x01] = kvm_s390_handle_01,
@@ -110,10 +29,10 @@ static const intercept_handler_t instruction_handlers[256] = {
        [0x83] = kvm_s390_handle_diag,
        [0xae] = kvm_s390_handle_sigp,
        [0xb2] = kvm_s390_handle_b2,
-       [0xb7] = handle_lctl,
+       [0xb7] = kvm_s390_handle_lctl,
        [0xb9] = kvm_s390_handle_b9,
        [0xe5] = kvm_s390_handle_e5,
-       [0xeb] = handle_eb,
+       [0xeb] = kvm_s390_handle_eb,
 };
 
 static int handle_noop(struct kvm_vcpu *vcpu)
@@ -174,47 +93,12 @@ static int handle_stop(struct kvm_vcpu *vcpu)
 
 static int handle_validity(struct kvm_vcpu *vcpu)
 {
-       unsigned long vmaddr;
        int viwhy = vcpu->arch.sie_block->ipb >> 16;
-       int rc;
 
        vcpu->stat.exit_validity++;
        trace_kvm_s390_intercept_validity(vcpu, viwhy);
-       if (viwhy == 0x37) {
-               vmaddr = gmap_fault(vcpu->arch.sie_block->prefix,
-                                   vcpu->arch.gmap);
-               if (IS_ERR_VALUE(vmaddr)) {
-                       rc = -EOPNOTSUPP;
-                       goto out;
-               }
-               rc = fault_in_pages_writeable((char __user *) vmaddr,
-                        PAGE_SIZE);
-               if (rc) {
-                       /* user will receive sigsegv, exit to user */
-                       rc = -EOPNOTSUPP;
-                       goto out;
-               }
-               vmaddr = gmap_fault(vcpu->arch.sie_block->prefix + PAGE_SIZE,
-                                   vcpu->arch.gmap);
-               if (IS_ERR_VALUE(vmaddr)) {
-                       rc = -EOPNOTSUPP;
-                       goto out;
-               }
-               rc = fault_in_pages_writeable((char __user *) vmaddr,
-                        PAGE_SIZE);
-               if (rc) {
-                       /* user will receive sigsegv, exit to user */
-                       rc = -EOPNOTSUPP;
-                       goto out;
-               }
-       } else
-               rc = -EOPNOTSUPP;
-
-out:
-       if (rc)
-               VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d",
-                          viwhy);
-       return rc;
+       WARN_ONCE(true, "kvm: unhandled validity intercept 0x%x\n", viwhy);
+       return -EOPNOTSUPP;
 }
 
 static int handle_instruction(struct kvm_vcpu *vcpu)
index 5c948177529e281ca7138a1b9bd7ef0186f4cec9..7f35cb33e5102008244b4fd1376954400f2d0009 100644 (file)
@@ -438,7 +438,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
 no_timer:
        spin_lock(&vcpu->arch.local_int.float_int->lock);
        spin_lock_bh(&vcpu->arch.local_int.lock);
-       add_wait_queue(&vcpu->arch.local_int.wq, &wait);
+       add_wait_queue(&vcpu->wq, &wait);
        while (list_empty(&vcpu->arch.local_int.list) &&
                list_empty(&vcpu->arch.local_int.float_int->list) &&
                (!vcpu->arch.local_int.timer_due) &&
@@ -452,7 +452,7 @@ no_timer:
        }
        __unset_cpu_idle(vcpu);
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&vcpu->arch.local_int.wq, &wait);
+       remove_wait_queue(&vcpu->wq, &wait);
        spin_unlock_bh(&vcpu->arch.local_int.lock);
        spin_unlock(&vcpu->arch.local_int.float_int->lock);
        hrtimer_try_to_cancel(&vcpu->arch.ckc_timer);
@@ -465,8 +465,8 @@ void kvm_s390_tasklet(unsigned long parm)
 
        spin_lock(&vcpu->arch.local_int.lock);
        vcpu->arch.local_int.timer_due = 1;
-       if (waitqueue_active(&vcpu->arch.local_int.wq))
-               wake_up_interruptible(&vcpu->arch.local_int.wq);
+       if (waitqueue_active(&vcpu->wq))
+               wake_up_interruptible(&vcpu->wq);
        spin_unlock(&vcpu->arch.local_int.lock);
 }
 
@@ -613,7 +613,7 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
        spin_lock_bh(&li->lock);
        list_add(&inti->list, &li->list);
        atomic_set(&li->active, 1);
-       BUG_ON(waitqueue_active(&li->wq));
+       BUG_ON(waitqueue_active(li->wq));
        spin_unlock_bh(&li->lock);
        return 0;
 }
@@ -746,8 +746,8 @@ int kvm_s390_inject_vm(struct kvm *kvm,
        li = fi->local_int[sigcpu];
        spin_lock_bh(&li->lock);
        atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
-       if (waitqueue_active(&li->wq))
-               wake_up_interruptible(&li->wq);
+       if (waitqueue_active(li->wq))
+               wake_up_interruptible(li->wq);
        spin_unlock_bh(&li->lock);
        spin_unlock(&fi->lock);
        mutex_unlock(&kvm->lock);
@@ -832,8 +832,8 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
        if (inti->type == KVM_S390_SIGP_STOP)
                li->action_bits |= ACTION_STOP_ON_STOP;
        atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
-       if (waitqueue_active(&li->wq))
-               wake_up_interruptible(&vcpu->arch.local_int.wq);
+       if (waitqueue_active(&vcpu->wq))
+               wake_up_interruptible(&vcpu->wq);
        spin_unlock_bh(&li->lock);
        mutex_unlock(&vcpu->kvm->lock);
        return 0;
index c1c7c683fa26d591af0eeac242ee898f88cb9dc2..ba694d2ba51e36a2933ad722db76b00e09735f37 100644 (file)
@@ -59,6 +59,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) },
        { "deliver_program_interruption", VCPU_STAT(deliver_program_int) },
        { "exit_wait_state", VCPU_STAT(exit_wait_state) },
+       { "instruction_pfmf", VCPU_STAT(instruction_pfmf) },
        { "instruction_stidp", VCPU_STAT(instruction_stidp) },
        { "instruction_spx", VCPU_STAT(instruction_spx) },
        { "instruction_stpx", VCPU_STAT(instruction_stpx) },
@@ -84,6 +85,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
 };
 
 static unsigned long long *facilities;
+static struct gmap_notifier gmap_notifier;
 
 /* Section: not file related */
 int kvm_arch_hardware_enable(void *garbage)
@@ -96,13 +98,18 @@ void kvm_arch_hardware_disable(void *garbage)
 {
 }
 
+static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address);
+
 int kvm_arch_hardware_setup(void)
 {
+       gmap_notifier.notifier_call = kvm_gmap_notifier;
+       gmap_register_ipte_notifier(&gmap_notifier);
        return 0;
 }
 
 void kvm_arch_hardware_unsetup(void)
 {
+       gmap_unregister_ipte_notifier(&gmap_notifier);
 }
 
 void kvm_arch_check_processor_compat(void *rtn)
@@ -239,6 +246,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
                kvm->arch.gmap = gmap_alloc(current->mm);
                if (!kvm->arch.gmap)
                        goto out_nogmap;
+               kvm->arch.gmap->private = kvm;
        }
 
        kvm->arch.css_support = 0;
@@ -270,7 +278,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 
        free_page((unsigned long)(vcpu->arch.sie_block));
        kvm_vcpu_uninit(vcpu);
-       kfree(vcpu);
+       kmem_cache_free(kvm_vcpu_cache, vcpu);
 }
 
 static void kvm_free_vcpus(struct kvm *kvm)
@@ -309,6 +317,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
                vcpu->arch.gmap = gmap_alloc(current->mm);
                if (!vcpu->arch.gmap)
                        return -ENOMEM;
+               vcpu->arch.gmap->private = vcpu->kvm;
                return 0;
        }
 
@@ -373,8 +382,10 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
        atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
                                                    CPUSTAT_SM |
-                                                   CPUSTAT_STOPPED);
+                                                   CPUSTAT_STOPPED |
+                                                   CPUSTAT_GED);
        vcpu->arch.sie_block->ecb   = 6;
+       vcpu->arch.sie_block->ecb2  = 8;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
        vcpu->arch.sie_block->fac   = (int) (long) facilities;
        hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
@@ -397,7 +408,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
 
        rc = -ENOMEM;
 
-       vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
+       vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
        if (!vcpu)
                goto out;
 
@@ -427,7 +438,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
        vcpu->arch.local_int.float_int = &kvm->arch.float_int;
        spin_lock(&kvm->arch.float_int.lock);
        kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int;
-       init_waitqueue_head(&vcpu->arch.local_int.wq);
+       vcpu->arch.local_int.wq = &vcpu->wq;
        vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
        spin_unlock(&kvm->arch.float_int.lock);
 
@@ -442,7 +453,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
 out_free_sie_block:
        free_page((unsigned long)(vcpu->arch.sie_block));
 out_free_cpu:
-       kfree(vcpu);
+       kmem_cache_free(kvm_vcpu_cache, vcpu);
 out:
        return ERR_PTR(rc);
 }
@@ -454,6 +465,50 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+void s390_vcpu_block(struct kvm_vcpu *vcpu)
+{
+       atomic_set_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20);
+}
+
+void s390_vcpu_unblock(struct kvm_vcpu *vcpu)
+{
+       atomic_clear_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20);
+}
+
+/*
+ * Kick a guest cpu out of SIE and wait until SIE is not running.
+ * If the CPU is not running (e.g. waiting as idle) the function will
+ * return immediately. */
+void exit_sie(struct kvm_vcpu *vcpu)
+{
+       atomic_set_mask(CPUSTAT_STOP_INT, &vcpu->arch.sie_block->cpuflags);
+       while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE)
+               cpu_relax();
+}
+
+/* Kick a guest cpu out of SIE and prevent SIE-reentry */
+void exit_sie_sync(struct kvm_vcpu *vcpu)
+{
+       s390_vcpu_block(vcpu);
+       exit_sie(vcpu);
+}
+
+static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address)
+{
+       int i;
+       struct kvm *kvm = gmap->private;
+       struct kvm_vcpu *vcpu;
+
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               /* match against both prefix pages */
+               if (vcpu->arch.sie_block->prefix == (address & ~0x1000UL)) {
+                       VCPU_EVENT(vcpu, 2, "gmap notifier for %lx", address);
+                       kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
+                       exit_sie_sync(vcpu);
+               }
+       }
+}
+
 int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
 {
        /* kvm common code refers to this, but never calls it */
@@ -606,6 +661,27 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
        return -EINVAL; /* not implemented yet */
 }
 
+static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
+{
+       /*
+        * We use MMU_RELOAD just to re-arm the ipte notifier for the
+        * guest prefix page. gmap_ipte_notify will wait on the ptl lock.
+        * This ensures that the ipte instruction for this request has
+        * already finished. We might race against a second unmapper that
+        * wants to set the blocking bit. Lets just retry the request loop.
+        */
+       while (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) {
+               int rc;
+               rc = gmap_ipte_notify(vcpu->arch.gmap,
+                                     vcpu->arch.sie_block->prefix,
+                                     PAGE_SIZE * 2);
+               if (rc)
+                       return rc;
+               s390_vcpu_unblock(vcpu);
+       }
+       return 0;
+}
+
 static int __vcpu_run(struct kvm_vcpu *vcpu)
 {
        int rc;
@@ -621,6 +697,10 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
        if (!kvm_is_ucontrol(vcpu->kvm))
                kvm_s390_deliver_pending_interrupts(vcpu);
 
+       rc = kvm_s390_handle_requests(vcpu);
+       if (rc)
+               return rc;
+
        vcpu->arch.sie_block->icptcode = 0;
        preempt_disable();
        kvm_guest_enter();
@@ -630,7 +710,9 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
        trace_kvm_s390_sie_enter(vcpu,
                                 atomic_read(&vcpu->arch.sie_block->cpuflags));
        rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs);
-       if (rc) {
+       if (rc > 0)
+               rc = 0;
+       if (rc < 0) {
                if (kvm_is_ucontrol(vcpu->kvm)) {
                        rc = SIE_INTERCEPT_UCONTROL;
                } else {
@@ -1046,7 +1128,7 @@ static int __init kvm_s390_init(void)
                return -ENOMEM;
        }
        memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
-       facilities[0] &= 0xff00fff3f47c0000ULL;
+       facilities[0] &= 0xff82fff3f47c0000ULL;
        facilities[1] &= 0x001c000000000000ULL;
        return 0;
 }
@@ -1059,3 +1141,12 @@ static void __exit kvm_s390_exit(void)
 
 module_init(kvm_s390_init);
 module_exit(kvm_s390_exit);
+
+/*
+ * Enable autoloading of the kvm module.
+ * Note that we add the module alias here instead of virt/kvm/kvm_main.c
+ * since x86 takes a different approach.
+ */
+#include <linux/miscdevice.h>
+MODULE_ALIAS_MISCDEV(KVM_MINOR);
+MODULE_ALIAS("devname:kvm");
index efc14f687265d5e0c5ad2d74c4104943187ca72b..028ca9fd2158f4ab015e40236d70b3acbf53c6e5 100644 (file)
@@ -63,6 +63,7 @@ static inline void kvm_s390_set_prefix(struct kvm_vcpu *vcpu, u32 prefix)
 {
        vcpu->arch.sie_block->prefix = prefix & 0x7fffe000u;
        vcpu->arch.sie_block->ihcpu  = 0xffff;
+       kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
 }
 
 static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu)
@@ -85,6 +86,12 @@ static inline void kvm_s390_get_base_disp_sse(struct kvm_vcpu *vcpu,
        *address2 = (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
 }
 
+static inline void kvm_s390_get_regs_rre(struct kvm_vcpu *vcpu, int *r1, int *r2)
+{
+       *r1 = (vcpu->arch.sie_block->ipb & 0x00f00000) >> 20;
+       *r2 = (vcpu->arch.sie_block->ipb & 0x000f0000) >> 16;
+}
+
 static inline u64 kvm_s390_get_base_disp_rsy(struct kvm_vcpu *vcpu)
 {
        u32 base2 = vcpu->arch.sie_block->ipb >> 28;
@@ -125,7 +132,8 @@ int kvm_s390_handle_e5(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_01(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_b9(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu);
-int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu);
+int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu);
+int kvm_s390_handle_eb(struct kvm_vcpu *vcpu);
 
 /* implemented in sigp.c */
 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
@@ -133,6 +141,10 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
 /* implemented in kvm-s390.c */
 int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
                                 unsigned long addr);
+void s390_vcpu_block(struct kvm_vcpu *vcpu);
+void s390_vcpu_unblock(struct kvm_vcpu *vcpu);
+void exit_sie(struct kvm_vcpu *vcpu);
+void exit_sie_sync(struct kvm_vcpu *vcpu);
 /* implemented in diag.c */
 int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
 
index 6bbd7b5a0bbee36d483e7deba484ce96e3176dfb..0da3e6eb6be6cec4d55780b838492e52d093f08d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * handling privileged instructions
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008, 2013
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License (version 2 only)
@@ -20,6 +20,9 @@
 #include <asm/debug.h>
 #include <asm/ebcdic.h>
 #include <asm/sysinfo.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
 #include <asm/ptrace.h>
 #include <asm/compat.h>
 #include "gaccess.h"
@@ -34,6 +37,9 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu)
 
        vcpu->stat.instruction_spx++;
 
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
        operand2 = kvm_s390_get_base_disp_s(vcpu);
 
        /* must be word boundary */
@@ -65,6 +71,9 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu)
 
        vcpu->stat.instruction_stpx++;
 
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
        operand2 = kvm_s390_get_base_disp_s(vcpu);
 
        /* must be word boundary */
@@ -89,6 +98,9 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
 
        vcpu->stat.instruction_stap++;
 
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
        useraddr = kvm_s390_get_base_disp_s(vcpu);
 
        if (useraddr & 1)
@@ -105,7 +117,12 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
 static int handle_skey(struct kvm_vcpu *vcpu)
 {
        vcpu->stat.instruction_storage_key++;
-       vcpu->arch.sie_block->gpsw.addr -= 4;
+
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+       vcpu->arch.sie_block->gpsw.addr =
+               __rewind_psw(vcpu->arch.sie_block->gpsw, 4);
        VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
        return 0;
 }
@@ -129,9 +146,10 @@ static int handle_tpi(struct kvm_vcpu *vcpu)
                 * Store the two-word I/O interruption code into the
                 * provided area.
                 */
-               put_guest(vcpu, inti->io.subchannel_id, (u16 __user *) addr);
-               put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *) (addr + 2));
-               put_guest(vcpu, inti->io.io_int_parm, (u32 __user *) (addr + 4));
+               if (put_guest(vcpu, inti->io.subchannel_id, (u16 __user *)addr)
+                   || put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *)(addr + 2))
+                   || put_guest(vcpu, inti->io.io_int_parm, (u32 __user *)(addr + 4)))
+                       return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
        } else {
                /*
                 * Store the three-word I/O interruption code into
@@ -182,6 +200,9 @@ static int handle_io_inst(struct kvm_vcpu *vcpu)
 {
        VCPU_EVENT(vcpu, 4, "%s", "I/O instruction");
 
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
        if (vcpu->kvm->arch.css_support) {
                /*
                 * Most I/O instructions will be handled by userspace.
@@ -210,8 +231,12 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
        int rc;
 
        vcpu->stat.instruction_stfl++;
+
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
        /* only pass the facility bits, which we can handle */
-       facility_list = S390_lowcore.stfl_fac_list & 0xff00fff3;
+       facility_list = S390_lowcore.stfl_fac_list & 0xff82fff3;
 
        rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
                           &facility_list, sizeof(facility_list));
@@ -255,8 +280,8 @@ int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu)
        u64 addr;
 
        if (gpsw->mask & PSW_MASK_PSTATE)
-               return kvm_s390_inject_program_int(vcpu,
-                                                  PGM_PRIVILEGED_OPERATION);
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
        addr = kvm_s390_get_base_disp_s(vcpu);
        if (addr & 7)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -278,6 +303,9 @@ static int handle_lpswe(struct kvm_vcpu *vcpu)
        psw_t new_psw;
        u64 addr;
 
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
        addr = kvm_s390_get_base_disp_s(vcpu);
        if (addr & 7)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -296,6 +324,9 @@ static int handle_stidp(struct kvm_vcpu *vcpu)
 
        vcpu->stat.instruction_stidp++;
 
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
        operand2 = kvm_s390_get_base_disp_s(vcpu);
 
        if (operand2 & 7)
@@ -351,16 +382,30 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
        vcpu->stat.instruction_stsi++;
        VCPU_EVENT(vcpu, 4, "stsi: fc: %x sel1: %x sel2: %x", fc, sel1, sel2);
 
-       operand2 = kvm_s390_get_base_disp_s(vcpu);
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+       if (fc > 3) {
+               vcpu->arch.sie_block->gpsw.mask |= 3ul << 44;     /* cc 3 */
+               return 0;
+       }
 
-       if (operand2 & 0xfff && fc > 0)
+       if (vcpu->run->s.regs.gprs[0] & 0x0fffff00
+           || vcpu->run->s.regs.gprs[1] & 0xffff0000)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
-       switch (fc) {
-       case 0:
+       if (fc == 0) {
                vcpu->run->s.regs.gprs[0] = 3 << 28;
-               vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
+               vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);  /* cc 0 */
                return 0;
+       }
+
+       operand2 = kvm_s390_get_base_disp_s(vcpu);
+
+       if (operand2 & 0xfff)
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       switch (fc) {
        case 1: /* same handling for 1 and 2 */
        case 2:
                mem = get_zeroed_page(GFP_KERNEL);
@@ -377,8 +422,6 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
                        goto out_no_data;
                handle_stsi_3_2_2(vcpu, (void *) mem);
                break;
-       default:
-               goto out_no_data;
        }
 
        if (copy_to_guest_absolute(vcpu, operand2, (void *) mem, PAGE_SIZE)) {
@@ -432,20 +475,14 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
        intercept_handler_t handler;
 
        /*
-        * a lot of B2 instructions are priviledged. We first check for
-        * the privileged ones, that we can handle in the kernel. If the
-        * kernel can handle this instruction, we check for the problem
-        * state bit and (a) handle the instruction or (b) send a code 2
-        * program check.
-        * Anything else goes to userspace.*/
+        * A lot of B2 instructions are priviledged. Here we check for
+        * the privileged ones, that we can handle in the kernel.
+        * Anything else goes to userspace.
+        */
        handler = b2_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
-       if (handler) {
-               if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
-                       return kvm_s390_inject_program_int(vcpu,
-                                                  PGM_PRIVILEGED_OPERATION);
-               else
-                       return handler(vcpu);
-       }
+       if (handler)
+               return handler(vcpu);
+
        return -EOPNOTSUPP;
 }
 
@@ -453,8 +490,7 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
 {
        int reg1, reg2;
 
-       reg1 = (vcpu->arch.sie_block->ipb & 0x00f00000) >> 24;
-       reg2 = (vcpu->arch.sie_block->ipb & 0x000f0000) >> 16;
+       kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
 
        /* This basically extracts the mask half of the psw. */
        vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000;
@@ -467,9 +503,88 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+#define PFMF_RESERVED   0xfffc0101UL
+#define PFMF_SK         0x00020000UL
+#define PFMF_CF         0x00010000UL
+#define PFMF_UI         0x00008000UL
+#define PFMF_FSC        0x00007000UL
+#define PFMF_NQ         0x00000800UL
+#define PFMF_MR         0x00000400UL
+#define PFMF_MC         0x00000200UL
+#define PFMF_KEY        0x000000feUL
+
+static int handle_pfmf(struct kvm_vcpu *vcpu)
+{
+       int reg1, reg2;
+       unsigned long start, end;
+
+       vcpu->stat.instruction_pfmf++;
+
+       kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
+
+       if (!MACHINE_HAS_PFMF)
+               return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
+
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+       if (vcpu->run->s.regs.gprs[reg1] & PFMF_RESERVED)
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       /* Only provide non-quiescing support if the host supports it */
+       if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ &&
+           S390_lowcore.stfl_fac_list & 0x00020000)
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       /* No support for conditional-SSKE */
+       if (vcpu->run->s.regs.gprs[reg1] & (PFMF_MR | PFMF_MC))
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
+       switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
+       case 0x00000000:
+               end = (start + (1UL << 12)) & ~((1UL << 12) - 1);
+               break;
+       case 0x00001000:
+               end = (start + (1UL << 20)) & ~((1UL << 20) - 1);
+               break;
+       /* We dont support EDAT2
+       case 0x00002000:
+               end = (start + (1UL << 31)) & ~((1UL << 31) - 1);
+               break;*/
+       default:
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+       }
+       while (start < end) {
+               unsigned long useraddr;
+
+               useraddr = gmap_translate(start, vcpu->arch.gmap);
+               if (IS_ERR((void *)useraddr))
+                       return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+
+               if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
+                       if (clear_user((void __user *)useraddr, PAGE_SIZE))
+                               return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+               }
+
+               if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) {
+                       if (set_guest_storage_key(current->mm, useraddr,
+                                       vcpu->run->s.regs.gprs[reg1] & PFMF_KEY,
+                                       vcpu->run->s.regs.gprs[reg1] & PFMF_NQ))
+                               return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+               }
+
+               start += PAGE_SIZE;
+       }
+       if (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC)
+               vcpu->run->s.regs.gprs[reg2] = end;
+       return 0;
+}
+
 static const intercept_handler_t b9_handlers[256] = {
        [0x8d] = handle_epsw,
        [0x9c] = handle_io_inst,
+       [0xaf] = handle_pfmf,
 };
 
 int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
@@ -478,29 +593,96 @@ int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
 
        /* This is handled just as for the B2 instructions. */
        handler = b9_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
-       if (handler) {
-               if ((handler != handle_epsw) &&
-                   (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE))
-                       return kvm_s390_inject_program_int(vcpu,
-                                                  PGM_PRIVILEGED_OPERATION);
-               else
-                       return handler(vcpu);
-       }
+       if (handler)
+               return handler(vcpu);
+
        return -EOPNOTSUPP;
 }
 
+int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu)
+{
+       int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
+       int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
+       u64 useraddr;
+       u32 val = 0;
+       int reg, rc;
+
+       vcpu->stat.instruction_lctl++;
+
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+       useraddr = kvm_s390_get_base_disp_rs(vcpu);
+
+       if (useraddr & 3)
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3,
+                  useraddr);
+       trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr);
+
+       reg = reg1;
+       do {
+               rc = get_guest(vcpu, val, (u32 __user *) useraddr);
+               if (rc)
+                       return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+               vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul;
+               vcpu->arch.sie_block->gcr[reg] |= val;
+               useraddr += 4;
+               if (reg == reg3)
+                       break;
+               reg = (reg + 1) % 16;
+       } while (1);
+
+       return 0;
+}
+
+static int handle_lctlg(struct kvm_vcpu *vcpu)
+{
+       int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
+       int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
+       u64 useraddr;
+       int reg, rc;
+
+       vcpu->stat.instruction_lctlg++;
+
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+       useraddr = kvm_s390_get_base_disp_rsy(vcpu);
+
+       if (useraddr & 7)
+               return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+       reg = reg1;
+
+       VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3,
+                  useraddr);
+       trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr);
+
+       do {
+               rc = get_guest(vcpu, vcpu->arch.sie_block->gcr[reg],
+                              (u64 __user *) useraddr);
+               if (rc)
+                       return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+               useraddr += 8;
+               if (reg == reg3)
+                       break;
+               reg = (reg + 1) % 16;
+       } while (1);
+
+       return 0;
+}
+
 static const intercept_handler_t eb_handlers[256] = {
+       [0x2f] = handle_lctlg,
        [0x8a] = handle_io_inst,
 };
 
-int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu)
+int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)
 {
        intercept_handler_t handler;
 
-       /* All eb instructions that end up here are privileged. */
-       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
-               return kvm_s390_inject_program_int(vcpu,
-                                                  PGM_PRIVILEGED_OPERATION);
        handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff];
        if (handler)
                return handler(vcpu);
@@ -515,6 +697,9 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
 
        vcpu->stat.instruction_tprot++;
 
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
        kvm_s390_get_base_disp_sse(vcpu, &address1, &address2);
 
        /* we only handle the Linux memory detection case:
@@ -560,8 +745,7 @@ static int handle_sckpf(struct kvm_vcpu *vcpu)
        u32 value;
 
        if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
-               return kvm_s390_inject_program_int(vcpu,
-                                                  PGM_PRIVILEGED_OPERATION);
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
 
        if (vcpu->run->s.regs.gprs[0] & 0x00000000ffff0000)
                return kvm_s390_inject_program_int(vcpu,
index 1c48ab2845e0fdab9ec19fbb03060d4346ee4ffa..bec398c57acf76f15db4668003b27a61b4b30bbe 100644 (file)
@@ -79,8 +79,8 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
        list_add_tail(&inti->list, &li->list);
        atomic_set(&li->active, 1);
        atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
-       if (waitqueue_active(&li->wq))
-               wake_up_interruptible(&li->wq);
+       if (waitqueue_active(li->wq))
+               wake_up_interruptible(li->wq);
        spin_unlock_bh(&li->lock);
        rc = SIGP_CC_ORDER_CODE_ACCEPTED;
        VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
@@ -117,8 +117,8 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
        list_add_tail(&inti->list, &li->list);
        atomic_set(&li->active, 1);
        atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
-       if (waitqueue_active(&li->wq))
-               wake_up_interruptible(&li->wq);
+       if (waitqueue_active(li->wq))
+               wake_up_interruptible(li->wq);
        spin_unlock_bh(&li->lock);
        rc = SIGP_CC_ORDER_CODE_ACCEPTED;
        VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr);
@@ -145,8 +145,8 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
        atomic_set(&li->active, 1);
        atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
        li->action_bits |= action;
-       if (waitqueue_active(&li->wq))
-               wake_up_interruptible(&li->wq);
+       if (waitqueue_active(li->wq))
+               wake_up_interruptible(li->wq);
 out:
        spin_unlock_bh(&li->lock);
 
@@ -250,8 +250,8 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
 
        list_add_tail(&inti->list, &li->list);
        atomic_set(&li->active, 1);
-       if (waitqueue_active(&li->wq))
-               wake_up_interruptible(&li->wq);
+       if (waitqueue_active(li->wq))
+               wake_up_interruptible(li->wq);
        rc = SIGP_CC_ORDER_CODE_ACCEPTED;
 
        VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address);
@@ -333,8 +333,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
 
        /* sigp in userspace can exit */
        if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
-               return kvm_s390_inject_program_int(vcpu,
-                                                  PGM_PRIVILEGED_OPERATION);
+               return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
 
        order_code = kvm_s390_get_base_disp_rs(vcpu);
 
index 89ebae4008f2ff6ec46a40e10327b2302f668705..ce36ea80e4f9157f5c754b51c1ff9c700106d689 100644 (file)
@@ -135,30 +135,17 @@ void __init paging_init(void)
 
 void __init mem_init(void)
 {
-       unsigned long codesize, reservedpages, datasize, initsize;
-
-        max_mapnr = num_physpages = max_low_pfn;
+        max_mapnr = max_low_pfn;
         high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 
        /* Setup guest page hinting */
        cmma_init();
 
        /* this will put all low memory onto the freelists */
-       totalram_pages += free_all_bootmem();
+       free_all_bootmem();
        setup_zero_pages();     /* Setup zeroed pages. */
 
-       reservedpages = 0;
-
-       codesize =  (unsigned long) &_etext - (unsigned long) &_text;
-       datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
-       initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
-        printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n",
-               nr_free_pages() << (PAGE_SHIFT-10),
-                max_mapnr << (PAGE_SHIFT-10),
-                codesize >> 10,
-                reservedpages << (PAGE_SHIFT-10),
-                datasize >>10,
-                initsize >> 10);
+       mem_init_print_info(NULL);
        printk("Write protected kernel read-only data: %#lx - %#lx\n",
               (unsigned long)&_stext,
               PFN_ALIGN((unsigned long)&_eshared) - 1);
@@ -166,13 +153,14 @@ void __init mem_init(void)
 
 void free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(POISON_FREE_INITMEM);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
+       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+                          "initrd");
 }
 #endif
 
index a938b548f07e2d18c5510dbe99e47cdf231265a8..17bf4d3d303aaed6da37d6679a2080a3d2727c06 100644 (file)
@@ -689,7 +689,7 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long start, unsigned long len)
                entry = *ptep;
                if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_RO)) == 0) {
                        pgste = pgste_get_lock(ptep);
-                       pgste_val(pgste) |= RCP_IN_BIT;
+                       pgste_val(pgste) |= PGSTE_IN_BIT;
                        pgste_set_unlock(ptep, pgste);
                        start += PAGE_SIZE;
                        len -= PAGE_SIZE;
@@ -771,6 +771,54 @@ static inline void page_table_free_pgste(unsigned long *table)
        __free_page(page);
 }
 
+int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
+                         unsigned long key, bool nq)
+{
+       spinlock_t *ptl;
+       pgste_t old, new;
+       pte_t *ptep;
+
+       down_read(&mm->mmap_sem);
+       ptep = get_locked_pte(current->mm, addr, &ptl);
+       if (unlikely(!ptep)) {
+               up_read(&mm->mmap_sem);
+               return -EFAULT;
+       }
+
+       new = old = pgste_get_lock(ptep);
+       pgste_val(new) &= ~(PGSTE_GR_BIT | PGSTE_GC_BIT |
+                           PGSTE_ACC_BITS | PGSTE_FP_BIT);
+       pgste_val(new) |= (key & (_PAGE_CHANGED | _PAGE_REFERENCED)) << 48;
+       pgste_val(new) |= (key & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
+       if (!(pte_val(*ptep) & _PAGE_INVALID)) {
+               unsigned long address, bits;
+               unsigned char skey;
+
+               address = pte_val(*ptep) & PAGE_MASK;
+               skey = page_get_storage_key(address);
+               bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
+               /* Set storage key ACC and FP */
+               page_set_storage_key(address,
+                               (key & (_PAGE_ACC_BITS | _PAGE_FP_BIT)),
+                               !nq);
+
+               /* Merge host changed & referenced into pgste  */
+               pgste_val(new) |= bits << 52;
+               /* Transfer skey changed & referenced bit to kvm user bits */
+               pgste_val(new) |= bits << 45;   /* PGSTE_UR_BIT & PGSTE_UC_BIT */
+       }
+       /* changing the guest storage key is considered a change of the page */
+       if ((pgste_val(new) ^ pgste_val(old)) &
+           (PGSTE_ACC_BITS | PGSTE_FP_BIT | PGSTE_GR_BIT | PGSTE_GC_BIT))
+               pgste_val(new) |= PGSTE_UC_BIT;
+
+       pgste_set_unlock(ptep, new);
+       pte_unmap_unlock(*ptep, ptl);
+       up_read(&mm->mmap_sem);
+       return 0;
+}
+EXPORT_SYMBOL(set_guest_storage_key);
+
 #else /* CONFIG_PGSTE */
 
 static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
index 1912f3bb190cfbf9c7cf7218e84b2cd1555baf57..0022e1ebfbde9063c349820df37b4dc5f29c0e20 100644 (file)
@@ -81,8 +81,8 @@ struct hws_data_entry {
        unsigned int:16;
        unsigned int prim_asn:16;   /* primary ASN                       */
        unsigned long long ia;      /* Instruction Address               */
-       unsigned long long lpp;     /* Logical-Partition Program Param.  */
-       unsigned long long vpp;     /* Virtual-Machine Program Param.    */
+       unsigned long long gpp;     /* Guest Program Parameter           */
+       unsigned long long hpp;     /* Host Program Parameter            */
 };
 
 struct hws_trailer_entry {
index f1e5be85d592a421fd51abe79f3210053a9c2cdc..e2956ad39a4f59ac2e8ffbe2a8626b2d9c84d363 100644 (file)
@@ -82,10 +82,13 @@ struct intr_bucket {
 
 static struct intr_bucket *bucket;
 
-/* Adapter local summary indicator */
-static u8 *zpci_irq_si;
+/* Adapter interrupt definitions */
+static void zpci_irq_handler(struct airq_struct *airq);
 
-static atomic_t irq_retries = ATOMIC_INIT(0);
+static struct airq_struct zpci_airq = {
+       .handler = zpci_irq_handler,
+       .isc = PCI_ISC,
+};
 
 /* I/O Map */
 static DEFINE_SPINLOCK(zpci_iomap_lock);
@@ -404,7 +407,7 @@ static struct pci_ops pci_root_ops = {
 /* store the last handled bit to implement fair scheduling of devices */
 static DEFINE_PER_CPU(unsigned long, next_sbit);
 
-static void zpci_irq_handler(void *dont, void *need)
+static void zpci_irq_handler(struct airq_struct *airq)
 {
        unsigned long sbit, mbit, last = 0, start = __get_cpu_var(next_sbit);
        int rescan = 0, max = aisb_max;
@@ -452,7 +455,6 @@ scan:
        max = aisb_max;
        sbit = find_first_bit_left(bucket->aisb, max);
        if (sbit != max) {
-               atomic_inc(&irq_retries);
                rescan++;
                goto scan;
        }
@@ -565,7 +567,21 @@ static void zpci_map_resources(struct zpci_dev *zdev)
                pr_debug("BAR%i: -> start: %Lx  end: %Lx\n",
                        i, pdev->resource[i].start, pdev->resource[i].end);
        }
-};
+}
+
+static void zpci_unmap_resources(struct zpci_dev *zdev)
+{
+       struct pci_dev *pdev = zdev->pdev;
+       resource_size_t len;
+       int i;
+
+       for (i = 0; i < PCI_BAR_COUNT; i++) {
+               len = pci_resource_len(pdev, i);
+               if (!len)
+                       continue;
+               pci_iounmap(pdev, (void *) pdev->resource[i].start);
+       }
+}
 
 struct zpci_dev *zpci_alloc_device(void)
 {
@@ -701,25 +717,20 @@ static int __init zpci_irq_init(void)
                goto out_alloc;
        }
 
-       isc_register(PCI_ISC);
-       zpci_irq_si = s390_register_adapter_interrupt(&zpci_irq_handler, NULL, PCI_ISC);
-       if (IS_ERR(zpci_irq_si)) {
-               rc = PTR_ERR(zpci_irq_si);
-               zpci_irq_si = NULL;
+       rc = register_adapter_interrupt(&zpci_airq);
+       if (rc)
                goto out_ai;
-       }
+       /* Set summary to 1 to be called every time for the ISC. */
+       *zpci_airq.lsi_ptr = 1;
 
        for_each_online_cpu(cpu)
                per_cpu(next_sbit, cpu) = 0;
 
        spin_lock_init(&bucket->lock);
-       /* set summary to 1 to be called every time for the ISC */
-       *zpci_irq_si = 1;
        set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
        return 0;
 
 out_ai:
-       isc_unregister(PCI_ISC);
        free_page((unsigned long) bucket->alloc);
 out_alloc:
        free_page((unsigned long) bucket->aisb);
@@ -732,21 +743,10 @@ static void zpci_irq_exit(void)
 {
        free_page((unsigned long) bucket->alloc);
        free_page((unsigned long) bucket->aisb);
-       s390_unregister_adapter_interrupt(zpci_irq_si, PCI_ISC);
-       isc_unregister(PCI_ISC);
+       unregister_adapter_interrupt(&zpci_airq);
        kfree(bucket);
 }
 
-void zpci_debug_info(struct zpci_dev *zdev, struct seq_file *m)
-{
-       if (!zdev)
-               return;
-
-       seq_printf(m, "global irq retries: %u\n", atomic_read(&irq_retries));
-       seq_printf(m, "aibv[0]:%016lx  aibv[1]:%016lx  aisb:%016lx\n",
-                  get_imap(0)->aibv, get_imap(1)->aibv, *bucket->aisb);
-}
-
 static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size,
                                                unsigned long flags, int domain)
 {
@@ -810,6 +810,16 @@ int pcibios_add_device(struct pci_dev *pdev)
        return 0;
 }
 
+void pcibios_release_device(struct pci_dev *pdev)
+{
+       struct zpci_dev *zdev = get_zdev(pdev);
+
+       zpci_unmap_resources(zdev);
+       zpci_fmb_disable_device(zdev);
+       zpci_debug_exit_device(zdev);
+       zdev->pdev = NULL;
+}
+
 static int zpci_scan_bus(struct zpci_dev *zdev)
 {
        struct resource *res;
@@ -950,25 +960,6 @@ void zpci_stop_device(struct zpci_dev *zdev)
 }
 EXPORT_SYMBOL_GPL(zpci_stop_device);
 
-int zpci_scan_device(struct zpci_dev *zdev)
-{
-       zdev->pdev = pci_scan_single_device(zdev->bus, ZPCI_DEVFN);
-       if (!zdev->pdev) {
-               pr_err("pci_scan_single_device failed for fid: 0x%x\n",
-                       zdev->fid);
-               goto out;
-       }
-
-       pci_bus_add_devices(zdev->bus);
-
-       return 0;
-out:
-       zpci_dma_exit_device(zdev);
-       clp_disable_fh(zdev);
-       return -EIO;
-}
-EXPORT_SYMBOL_GPL(zpci_scan_device);
-
 static inline int barsize(u8 size)
 {
        return (size) ? (1 << size) >> 10 : 0;
index bd34359d1546cc0c0eb4625ab3a25e0c72470604..2e9539625d93b1a66257b7413bd3f8da738beb57 100644 (file)
@@ -236,7 +236,6 @@ int clp_disable_fh(struct zpci_dev *zdev)
        if (!zdev_enabled(zdev))
                return 0;
 
-       dev_info(&zdev->pdev->dev, "disabling fn handle: 0x%x\n", fh);
        rc = clp_set_pci_fn(&fh, 0, CLP_SET_DISABLE_PCI_FN);
        if (!rc)
                /* Success -> store disabled handle in zdev */
index 771b82359af421b1a213b276b39bbe0b8d84c5a6..75c69b402e05aa3ca12f3b7ee8ca78864886c1b4 100644 (file)
@@ -115,27 +115,6 @@ static const struct file_operations debugfs_pci_perf_fops = {
        .release = single_release,
 };
 
-static int pci_debug_show(struct seq_file *m, void *v)
-{
-       struct zpci_dev *zdev = m->private;
-
-       zpci_debug_info(zdev, m);
-       return 0;
-}
-
-static int pci_debug_seq_open(struct inode *inode, struct file *filp)
-{
-       return single_open(filp, pci_debug_show,
-                          file_inode(filp)->i_private);
-}
-
-static const struct file_operations debugfs_pci_debug_fops = {
-       .open    = pci_debug_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = single_release,
-};
-
 void zpci_debug_init_device(struct zpci_dev *zdev)
 {
        zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev),
@@ -149,19 +128,11 @@ void zpci_debug_init_device(struct zpci_dev *zdev)
                                &debugfs_pci_perf_fops);
        if (IS_ERR(zdev->debugfs_perf))
                zdev->debugfs_perf = NULL;
-
-       zdev->debugfs_debug = debugfs_create_file("debug",
-                               S_IFREG | S_IRUGO | S_IWUSR,
-                               zdev->debugfs_dev, zdev,
-                               &debugfs_pci_debug_fops);
-       if (IS_ERR(zdev->debugfs_debug))
-               zdev->debugfs_debug = NULL;
 }
 
 void zpci_debug_exit_device(struct zpci_dev *zdev)
 {
        debugfs_remove(zdev->debugfs_perf);
-       debugfs_remove(zdev->debugfs_debug);
        debugfs_remove(zdev->debugfs_dev);
 }
 
index f8e69d5bc0a90631cb12c43fbe3b01e02786e7ea..a2343c1f6e0494e0904871a10a69c312fb89fa47 100644 (file)
@@ -263,7 +263,7 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
                                     enum dma_data_direction direction,
                                     struct dma_attrs *attrs)
 {
-       struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
        unsigned long nr_pages, iommu_page_index;
        unsigned long pa = page_to_phys(page) + offset;
        int flags = ZPCI_PTE_VALID;
@@ -304,7 +304,7 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,
                                 size_t size, enum dma_data_direction direction,
                                 struct dma_attrs *attrs)
 {
-       struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
        unsigned long iommu_page_index;
        int npages;
 
@@ -323,7 +323,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size,
                            dma_addr_t *dma_handle, gfp_t flag,
                            struct dma_attrs *attrs)
 {
-       struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
        struct page *page;
        unsigned long pa;
        dma_addr_t map;
index a42cce69d0a00785f74f830e4521ced9d0170b3c..e99a2557f1865f5c50e246b1e52b08227d2f83f5 100644 (file)
 static ssize_t show_fid(struct device *dev, struct device_attribute *attr,
                        char *buf)
 {
-       struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
 
-       sprintf(buf, "0x%08x\n", zdev->fid);
-       return strlen(buf);
+       return sprintf(buf, "0x%08x\n", zdev->fid);
 }
 static DEVICE_ATTR(function_id, S_IRUGO, show_fid, NULL);
 
 static ssize_t show_fh(struct device *dev, struct device_attribute *attr,
                       char *buf)
 {
-       struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
 
-       sprintf(buf, "0x%08x\n", zdev->fh);
-       return strlen(buf);
+       return sprintf(buf, "0x%08x\n", zdev->fh);
 }
 static DEVICE_ATTR(function_handle, S_IRUGO, show_fh, NULL);
 
 static ssize_t show_pchid(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
-       struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
 
-       sprintf(buf, "0x%04x\n", zdev->pchid);
-       return strlen(buf);
+       return sprintf(buf, "0x%04x\n", zdev->pchid);
 }
 static DEVICE_ATTR(pchid, S_IRUGO, show_pchid, NULL);
 
 static ssize_t show_pfgid(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
-       struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+       struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
 
-       sprintf(buf, "0x%02x\n", zdev->pfgid);
-       return strlen(buf);
+       return sprintf(buf, "0x%02x\n", zdev->pfgid);
 }
 static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL);
 
index cebaff8069a169c3c2fe61e226694d8d40825344..e1c7bb999b06af31fe908089c3ff8e65484e4f82 100644 (file)
@@ -3,3 +3,4 @@ header-y +=
 
 generic-y += clkdev.h
 generic-y += trace_clock.h
+generic-y += xor.h
diff --git a/arch/score/include/asm/dma-mapping.h b/arch/score/include/asm/dma-mapping.h
deleted file mode 100644 (file)
index f9c0193..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_SCORE_DMA_MAPPING_H
-#define _ASM_SCORE_DMA_MAPPING_H
-
-#include <asm-generic/dma-mapping-broken.h>
-
-#endif /* _ASM_SCORE_DMA_MAPPING_H */
index eebcbaa4e9783b1685c856fa794c63123344131a..7274b5c4287ee4cbaad56a1eb41ad43a0d90c047 100644 (file)
@@ -49,6 +49,7 @@ SECTIONS
        }
 
        . = ALIGN(16);
+       _sdata =  .;                    /* Start of data section */
        RODATA
 
        EXCEPTION_TABLE(16)
index 0940682ab38bdd700227226e22803e6310096aa5..9fbce49ad3bdd4304226aa767c8f5b2fcd2e0a49 100644 (file)
@@ -75,40 +75,19 @@ void __init paging_init(void)
 
 void __init mem_init(void)
 {
-       unsigned long codesize, reservedpages, datasize, initsize;
-       unsigned long tmp, ram = 0;
-
        high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
-       totalram_pages += free_all_bootmem();
+       free_all_bootmem();
        setup_zero_page();      /* Setup zeroed pages. */
-       reservedpages = 0;
-
-       for (tmp = 0; tmp < max_low_pfn; tmp++)
-               if (page_is_ram(tmp)) {
-                       ram++;
-                       if (PageReserved(pfn_to_page(tmp)))
-                               reservedpages++;
-               }
-
-       num_physpages = ram;
-       codesize = (unsigned long) &_etext - (unsigned long) &_text;
-       datasize = (unsigned long) &_edata - (unsigned long) &_etext;
-       initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
-       printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
-                       "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
-                       (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
-                       ram << (PAGE_SHIFT-10), codesize >> 10,
-                       reservedpages << (PAGE_SHIFT-10), datasize >> 10,
-                       initsize >> 10,
-                       totalhigh_pages << (PAGE_SHIFT-10));
+
+       mem_init_print_info(NULL);
 }
 #endif /* !CONFIG_NEED_MULTIPLE_NODES */
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
+       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+                          "initrd");
 }
 #endif
 
index 090358a7e1bbd6ff9da88a10282da83662ca9fd4..dad29b687bd33c18291523206985cb6b52dbdad0 100644 (file)
@@ -37,7 +37,7 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
 }
 
 static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count)
 {
        int __done, __res;
 
@@ -51,7 +51,7 @@ __mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
                : "t");
 
        if (unlikely(!__done || __res != 0))
-               __res = fail_fn(count);
+               __res = -1;
 
        return __res;
 }
index 20f9ead650d3e27c20d6f37e87a639288729b22d..33890fd267cb056c979def415ff6d49f054c55c4 100644 (file)
@@ -407,30 +407,16 @@ unsigned int mem_init_done = 0;
 
 void __init mem_init(void)
 {
-       int codesize, datasize, initsize;
-       int nid;
+       pg_data_t *pgdat;
 
        iommu_init();
 
-       num_physpages = 0;
        high_memory = NULL;
+       for_each_online_pgdat(pgdat)
+               high_memory = max_t(void *, high_memory,
+                                   __va(pgdat_end_pfn(pgdat) << PAGE_SHIFT));
 
-       for_each_online_node(nid) {
-               pg_data_t *pgdat = NODE_DATA(nid);
-               void *node_high_memory;
-
-               num_physpages += pgdat->node_present_pages;
-
-               if (pgdat->node_spanned_pages)
-                       totalram_pages += free_all_bootmem_node(pgdat);
-
-
-               node_high_memory = (void *)__va((pgdat->node_start_pfn +
-                                                pgdat->node_spanned_pages) <<
-                                                PAGE_SHIFT);
-               if (node_high_memory > high_memory)
-                       high_memory = node_high_memory;
-       }
+       free_all_bootmem();
 
        /* Set this up early, so we can take care of the zero page */
        cpu_cache_init();
@@ -441,19 +427,8 @@ void __init mem_init(void)
 
        vsyscall_init();
 
-       codesize =  (unsigned long) &_etext - (unsigned long) &_text;
-       datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
-       initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
-       printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
-              "%dk data, %dk init)\n",
-               nr_free_pages() << (PAGE_SHIFT-10),
-               num_physpages << (PAGE_SHIFT-10),
-               codesize >> 10,
-               datasize >> 10,
-               initsize >> 10);
-
-       printk(KERN_INFO "virtual kernel memory layout:\n"
+       mem_init_print_info(NULL);
+       pr_info("virtual kernel memory layout:\n"
                "    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #ifdef CONFIG_HIGHMEM
                "    pkmap   : 0x%08lx - 0x%08lx   (%4ld kB)\n"
@@ -499,13 +474,13 @@ void __init mem_init(void)
 
 void free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
 
index d0b83f66f356402a651249a2bed2079e98a85d76..d73e5e008b0de953d5e7eaf958d5c7bfed0c45c8 100644 (file)
@@ -35,6 +35,7 @@
 #define O_SYNC         (__O_SYNC|O_DSYNC)
 
 #define O_PATH         0x1000000
+#define O_TMPFILE      0x2000000
 
 #define F_GETOWN       5       /*  for sockets. */
 #define F_SETOWN       6       /*  for sockets. */
index 6cfc1b09ec25a28a683a76aa6d2ebb4e1d288a2d..d7aa524b72832d2555dcf2ffe831e5816641f840 100644 (file)
@@ -254,15 +254,12 @@ void __init leon_smp_done(void)
        /* Free unneeded trap tables */
        if (!cpu_present(1)) {
                free_reserved_page(virt_to_page(&trapbase_cpu1));
-               num_physpages++;
        }
        if (!cpu_present(2)) {
                free_reserved_page(virt_to_page(&trapbase_cpu2));
-               num_physpages++;
        }
        if (!cpu_present(3)) {
                free_reserved_page(virt_to_page(&trapbase_cpu3));
-               num_physpages++;
        }
        /* Ok, they are spinning and ready to go. */
        smp_processors_ready = 1;
index 2031c65fd4ea2ec209460bf3d7c0b5bf0aa4a283..bc4d3f5d2e5d1683bdfe6d0b33a4a60adcd21916 100644 (file)
@@ -254,7 +254,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        const char *type;
        u32 class;
 
-       dev = alloc_pci_dev();
+       dev = pci_alloc_dev(bus);
        if (!dev)
                return NULL;
 
@@ -281,7 +281,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
                printk("    create device, devfn: %x, type: %s\n",
                       devfn, type);
 
-       dev->bus = bus;
        dev->sysdata = node;
        dev->dev.parent = bus->bridge;
        dev->dev.bus = &pci_bus_type;
@@ -327,7 +326,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
                pci_set_master(dev);
 
-       dev->current_state = 4;         /* unknown power state */
+       dev->current_state = PCI_UNKNOWN;       /* unknown power state */
        dev->error_state = pci_channel_io_normal;
        dev->dma_mask = 0xffffffff;
 
index af472cf7c69a1998ab1b16dcba9edb884ef7e743..db69870828058db51e07699472cc9d9bcd3f7e34 100644 (file)
@@ -288,10 +288,6 @@ static void map_high_region(unsigned long start_pfn, unsigned long end_pfn)
 
 void __init mem_init(void)
 {
-       int codepages = 0;
-       int datapages = 0;
-       int initpages = 0; 
-       int reservedpages = 0;
        int i;
 
        if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) {
@@ -323,15 +319,12 @@ void __init mem_init(void)
 
        max_mapnr = last_valid_pfn - pfn_base;
        high_memory = __va(max_low_pfn << PAGE_SHIFT);
-
-       totalram_pages = free_all_bootmem();
+       free_all_bootmem();
 
        for (i = 0; sp_banks[i].num_bytes != 0; i++) {
                unsigned long start_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
                unsigned long end_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
 
-               num_physpages += sp_banks[i].num_bytes >> PAGE_SHIFT;
-
                if (end_pfn <= highstart_pfn)
                        continue;
 
@@ -341,39 +334,19 @@ void __init mem_init(void)
                map_high_region(start_pfn, end_pfn);
        }
        
-       codepages = (((unsigned long) &_etext) - ((unsigned long)&_start));
-       codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
-       datapages = (((unsigned long) &_edata) - ((unsigned long)&_etext));
-       datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
-       initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin));
-       initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
-
-       /* Ignore memory holes for the purpose of counting reserved pages */
-       for (i=0; i < max_low_pfn; i++)
-               if (test_bit(i >> (20 - PAGE_SHIFT), sparc_valid_addr_bitmap)
-                   && PageReserved(pfn_to_page(i)))
-                       reservedpages++;
-
-       printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
-              nr_free_pages() << (PAGE_SHIFT-10),
-              num_physpages << (PAGE_SHIFT - 10),
-              codepages << (PAGE_SHIFT-10),
-              reservedpages << (PAGE_SHIFT - 10),
-              datapages << (PAGE_SHIFT-10), 
-              initpages << (PAGE_SHIFT-10),
-              totalhigh_pages << (PAGE_SHIFT-10));
+       mem_init_print_info(NULL);
 }
 
 void free_initmem (void)
 {
-       num_physpages += free_initmem_default(POISON_FREE_INITMEM);
+       free_initmem_default(POISON_FREE_INITMEM);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       num_physpages += free_reserved_area(start, end, POISON_FREE_INITMEM,
-                                           "initrd");
+       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+                          "initrd");
 }
 #endif
 
index 04fd55a6e4613ae009d6f53abce4fbf3f043bc8e..a9c42a7ffb6a611a4b39129d3d698a2e710b863e 100644 (file)
@@ -2045,7 +2045,6 @@ static void __init register_page_bootmem_info(void)
 }
 void __init mem_init(void)
 {
-       unsigned long codepages, datapages, initpages;
        unsigned long addr, last;
 
        addr = PAGE_OFFSET + kern_base;
@@ -2061,12 +2060,7 @@ void __init mem_init(void)
        high_memory = __va(last_valid_pfn << PAGE_SHIFT);
 
        register_page_bootmem_info();
-       totalram_pages = free_all_bootmem();
-
-       /* We subtract one to account for the mem_map_zero page
-        * allocated below.
-        */
-       num_physpages = totalram_pages - 1;
+       free_all_bootmem();
 
        /*
         * Set up the zero page, mark it reserved, so that page count
@@ -2079,19 +2073,7 @@ void __init mem_init(void)
        }
        mark_page_reserved(mem_map_zero);
 
-       codepages = (((unsigned long) _etext) - ((unsigned long) _start));
-       codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
-       datapages = (((unsigned long) _edata) - ((unsigned long) _etext));
-       datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
-       initpages = (((unsigned long) __init_end) - ((unsigned long) __init_begin));
-       initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
-
-       printk("Memory: %luk available (%ldk kernel code, %ldk data, %ldk init) [%016lx,%016lx]\n",
-              nr_free_pages() << (PAGE_SHIFT-10),
-              codepages << (PAGE_SHIFT-10),
-              datapages << (PAGE_SHIFT-10), 
-              initpages << (PAGE_SHIFT-10), 
-              PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
+       mem_init_print_info(NULL);
 
        if (tlb_type == cheetah || tlb_type == cheetah_plus)
                cheetah_ecache_flush_init();
@@ -2131,8 +2113,8 @@ void free_initmem(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       num_physpages += free_reserved_area(start, end, POISON_FREE_INITMEM,
-                                           "initrd");
+       free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+                          "initrd");
 }
 #endif
 
index 2b70dfb1442eb3325bb8f5f088231ecd2e79cef3..b3f104953da2a67db4684cbad564a5547ad7aee4 100644 (file)
@@ -225,7 +225,7 @@ extern int do_work_pending(struct pt_regs *regs, u32 flags);
 
 /*
  * Return saved (kernel) PC of a blocked thread.
- * Only used in a printk() in kernel/sched.c, so don't work too hard.
+ * Only used in a printk() in kernel/sched/core.c, so don't work too hard.
  */
 #define thread_saved_pc(t)   ((t)->thread.pc)
 
index d062d463fca9c36f96818c40d65beda8efa09edd..7d8a935a9238a0191b0692a68ec85bcc57a9e3c7 100644 (file)
@@ -34,7 +34,7 @@ extern char __sys_cmpxchg_grab_lock[];
 extern char __start_atomic_asm_code[], __end_atomic_asm_code[];
 #endif
 
-/* Handle the discontiguity between _sdata and _stext. */
+/* Handle the discontiguity between _sdata and _text. */
 static inline int arch_is_kernel_data(unsigned long addr)
 {
        return addr >= (unsigned long)_sdata &&
index 8a082bc6bca57153efb53d69fc36068a9741f0ff..e4d44bd7df271f6b5445f5e7d5e593fe69cc58c7 100644 (file)
@@ -442,7 +442,7 @@ extern unsigned long __copy_in_user_inatomic(
 static inline unsigned long __must_check
 __copy_in_user(void __user *to, const void __user *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        return __copy_in_user_inatomic(to, from, n);
 }
 
index 7a5aa1a7864e2371900e5ccba2d2a0f507fa834e..68b542677f6ab51006e567c10023a132145fcdb4 100644 (file)
@@ -307,8 +307,8 @@ static void __cpuinit store_permanent_mappings(void)
                hv_store_mapping(addr, pages << PAGE_SHIFT, pa);
        }
 
-       hv_store_mapping((HV_VirtAddr)_stext,
-                        (uint32_t)(_einittext - _stext), 0);
+       hv_store_mapping((HV_VirtAddr)_text,
+                        (uint32_t)(_einittext - _text), 0);
 }
 
 /*
@@ -329,6 +329,7 @@ static void __init setup_memory(void)
 #if defined(CONFIG_HIGHMEM) || defined(__tilegx__)
        long lowmem_pages;
 #endif
+       unsigned long physpages = 0;
 
        /* We are using a char to hold the cpu_2_node[] mapping */
        BUILD_BUG_ON(MAX_NUMNODES > 127);
@@ -388,8 +389,8 @@ static void __init setup_memory(void)
                                continue;
                        }
                }
-               if (num_physpages + PFN_DOWN(range.size) > maxmem_pfn) {
-                       int max_size = maxmem_pfn - num_physpages;
+               if (physpages + PFN_DOWN(range.size) > maxmem_pfn) {
+                       int max_size = maxmem_pfn - physpages;
                        if (max_size > 0) {
                                pr_err("Maxmem reduced node %d to %d pages\n",
                                       i, max_size);
@@ -446,7 +447,7 @@ static void __init setup_memory(void)
                node_start_pfn[i] = start;
                node_end_pfn[i] = end;
                node_controller[i] = range.controller;
-               num_physpages += size;
+               physpages += size;
                max_pfn = end;
 
                /* Mark node as online */
@@ -465,7 +466,7 @@ static void __init setup_memory(void)
         * we're willing to use at 8 million pages (32GB of 4KB pages).
         */
        cap = 8 * 1024 * 1024;  /* 8 million pages */
-       if (num_physpages > cap) {
+       if (physpages > cap) {
                int num_nodes = num_online_nodes();
                int cap_each = cap / num_nodes;
                unsigned long dropped_pages = 0;
@@ -476,10 +477,10 @@ static void __init setup_memory(void)
                                node_end_pfn[i] = node_start_pfn[i] + cap_each;
                        }
                }
-               num_physpages -= dropped_pages;
+               physpages -= dropped_pages;
                pr_warning("Only using %ldMB memory;"
                       " ignoring %ldMB.\n",
-                      num_physpages >> (20 - PAGE_SHIFT),
+                      physpages >> (20 - PAGE_SHIFT),
                       dropped_pages >> (20 - PAGE_SHIFT));
                pr_warning("Consider using a larger page size.\n");
        }
@@ -497,7 +498,7 @@ static void __init setup_memory(void)
 
        lowmem_pages = (mappable_physpages > MAXMEM_PFN) ?
                MAXMEM_PFN : mappable_physpages;
-       highmem_pages = (long) (num_physpages - lowmem_pages);
+       highmem_pages = (long) (physpages - lowmem_pages);
 
        pr_notice("%ldMB HIGHMEM available.\n",
               pages_to_mb(highmem_pages > 0 ? highmem_pages : 0));
@@ -514,7 +515,6 @@ static void __init setup_memory(void)
                pr_warning("Use a HIGHMEM enabled kernel.\n");
                max_low_pfn = MAXMEM_PFN;
                max_pfn = MAXMEM_PFN;
-               num_physpages = MAXMEM_PFN;
                node_end_pfn[0] = MAXMEM_PFN;
        } else {
                pr_notice("%ldMB memory available.\n",
index ed258b8ae320229f401e7f22a9515ab4b6cda954..af8dfc9665f673982d27b65efd8ee52e495baa03 100644 (file)
@@ -442,7 +442,7 @@ void _KBacktraceIterator_init_current(struct KBacktraceIterator *kbt, ulong pc,
                                regs_to_pt_regs(&regs, pc, lr, sp, r52));
 }
 
-/* This is called only from kernel/sched.c, with esp == NULL */
+/* This is called only from kernel/sched/core.c, with esp == NULL */
 void show_stack(struct task_struct *task, unsigned long *esp)
 {
        struct KBacktraceIterator kbt;
index 631f10de12feee423e5c3376f56813cc35fb6053..a13ed902afbbd645c521a7751f5930d76b5c8704 100644 (file)
@@ -27,7 +27,6 @@ SECTIONS
   .intrpt1 (LOAD_OFFSET) : AT ( 0 )   /* put at the start of physical memory */
   {
     _text = .;
-    _stext = .;
     *(.intrpt1)
   } :intrpt1 =0
 
@@ -36,6 +35,7 @@ SECTIONS
 
   /* Now the real code */
   . = ALIGN(0x20000);
+  _stext = .;
   .text : AT (ADDR(.text) - LOAD_OFFSET) {
     HEAD_TEXT
     SCHED_TEXT
@@ -58,11 +58,13 @@ SECTIONS
   #define LOAD_OFFSET PAGE_OFFSET
 
   . = ALIGN(PAGE_SIZE);
+  __init_begin = .;
   VMLINUX_SYMBOL(_sinitdata) = .;
   INIT_DATA_SECTION(16) :data =0
   PERCPU_SECTION(L2_CACHE_BYTES)
   . = ALIGN(PAGE_SIZE);
   VMLINUX_SYMBOL(_einitdata) = .;
+  __init_end = .;
 
   _sdata = .;                   /* Start of data section */
 
index 2749515a054784ad95b2329b2c4d25bbb5270b98..e182958c707de30629c514819b2dd2ca386a9d6c 100644 (file)
@@ -562,7 +562,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
                        prot = ktext_set_nocache(prot);
                }
 
-               BUG_ON(address != (unsigned long)_stext);
+               BUG_ON(address != (unsigned long)_text);
                pte = NULL;
                for (; address < (unsigned long)_einittext;
                     pfn++, address += PAGE_SIZE) {
@@ -720,7 +720,7 @@ static void __init init_free_pfn_range(unsigned long start, unsigned long end)
                }
                init_page_count(page);
                __free_pages(page, order);
-               totalram_pages += count;
+               adjust_managed_page_count(page, count);
 
                page += count;
                pfn += count;
@@ -821,7 +821,6 @@ static void __init set_max_mapnr_init(void)
 
 void __init mem_init(void)
 {
-       int codesize, datasize, initsize;
        int i;
 #ifndef __tilegx__
        void *last;
@@ -846,26 +845,14 @@ void __init mem_init(void)
        set_max_mapnr_init();
 
        /* this will put all bootmem onto the freelists */
-       totalram_pages += free_all_bootmem();
+       free_all_bootmem();
 
 #ifndef CONFIG_64BIT
        /* count all remaining LOWMEM and give all HIGHMEM to page allocator */
        set_non_bootmem_pages_init();
 #endif
 
-       codesize =  (unsigned long)&_etext - (unsigned long)&_text;
-       datasize =  (unsigned long)&_end - (unsigned long)&_sdata;
-       initsize =  (unsigned long)&_einittext - (unsigned long)&_sinittext;
-       initsize += (unsigned long)&_einitdata - (unsigned long)&_sinitdata;
-
-       pr_info("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init, %ldk highmem)\n",
-               (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
-               num_physpages << (PAGE_SHIFT-10),
-               codesize >> 10,
-               datasize >> 10,
-               initsize >> 10,
-               (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
-              );
+       mem_init_print_info(NULL);
 
        /*
         * In debug mode, dump some interesting memory mappings.
@@ -1024,16 +1011,13 @@ static void free_init_pages(char *what, unsigned long begin, unsigned long end)
                        pte_clear(&init_mm, addr, ptep);
                        continue;
                }
-               __ClearPageReserved(page);
-               init_page_count(page);
                if (pte_huge(*ptep))
                        BUG_ON(!kdata_huge);
                else
                        set_pte_at(&init_mm, addr, ptep,
                                   pfn_pte(pfn, PAGE_KERNEL));
                memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
-               free_page(addr);
-               totalram_pages++;
+               free_reserved_page(page);
        }
        pr_info("Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
 }
index 4938de5512d20add327d2865e9c60ce6fb21181a..1dd5bd8a8c599360ae1626b66010c1a18b12145b 100644 (file)
@@ -57,7 +57,6 @@
        *(.uml.initcall.init)
        __uml_initcall_end = .;
   }
-  __init_end = .;
 
   SECURITY_INIT
 
index fb8fd6fb6563f6305a808973f748ffea438a9597..adde088aeefff64f5820fcf1636e5b3afa3577ab 100644 (file)
@@ -14,8 +14,6 @@ SECTIONS
   __binary_start = .;
   . = ALIGN(4096);             /* Init code and data */
   _text = .;
-  _stext = .;
-  __init_begin = .;
   INIT_TEXT_SECTION(PAGE_SIZE)
 
   . = ALIGN(PAGE_SIZE);
@@ -67,6 +65,7 @@ SECTIONS
   } =0x90909090
   .plt            : { *(.plt) }
   .text           : {
+    _stext = .;
     TEXT_TEXT
     SCHED_TEXT
     LOCK_TEXT
@@ -91,7 +90,9 @@ SECTIONS
 
   #include <asm/common.lds.S>
 
+  __init_begin = .;
   init.data : { INIT_DATA }
+  __init_end = .;
 
   /* Ensure the __preinit_array_start label is properly aligned.  We
      could instead move the label definition inside the section, but
@@ -155,6 +156,7 @@ SECTIONS
    . = ALIGN(32 / 8);
   . = ALIGN(32 / 8);
   }
+   __bss_stop = .;
   _end = .;
   PROVIDE (end = .);
 
index 9df292b270a8f40fed5e32121d2dafb086919a23..7ddb64baf3270620ae608e4764407ccbfe36dd7b 100644 (file)
@@ -65,15 +65,13 @@ void __init mem_init(void)
        uml_reserved = brk_end;
 
        /* this will put all low memory onto the freelists */
-       totalram_pages = free_all_bootmem();
+       free_all_bootmem();
        max_low_pfn = totalram_pages;
 #ifdef CONFIG_HIGHMEM
        setup_highmem(end_iomem, highmem);
 #endif
-       num_physpages = totalram_pages;
        max_pfn = totalram_pages;
-       printk(KERN_INFO "Memory: %luk available\n",
-              nr_free_pages() << (PAGE_SHIFT-10));
+       mem_init_print_info(NULL);
        kmalloc_ok = 1;
 }
 
@@ -244,7 +242,7 @@ void free_initmem(void)
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       free_reserved_area(start, end, 0, "initrd");
+       free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
 
index 7d101a2a15410e2003407c111a1d8dbb033ce95b..0dc4d1c6f98a19b5ed018c58d7aeb683d468ae1c 100644 (file)
@@ -39,7 +39,7 @@ void show_trace(struct task_struct *task, unsigned long * stack)
 static const int kstack_depth_to_print = 24;
 
 /* This recently started being used in arch-independent code too, as in
- * kernel/sched.c.*/
+ * kernel/sched/core.c.*/
 void show_stack(struct task_struct *task, unsigned long *esp)
 {
        unsigned long *stack;
index ff65fb4f1a95487f7a13940a986dac6380138006..6899195602b77fd3ed259f41977a2984faa902f4 100644 (file)
@@ -20,13 +20,12 @@ SECTIONS
   . = START + SIZEOF_HEADERS;
 
   _text = .;
-  _stext = .;
-  __init_begin = .;
   INIT_TEXT_SECTION(0)
   . = ALIGN(PAGE_SIZE);
 
   .text      :
   {
+    _stext = .;
     TEXT_TEXT
     SCHED_TEXT
     LOCK_TEXT
@@ -62,7 +61,10 @@ SECTIONS
 
   #include <asm/common.lds.S>
 
+  __init_begin = .;
   init.data : { INIT_DATA }
+  __init_end = .;
+
   .data    :
   {
     INIT_TASK_DATA(KERNEL_STACK_SIZE)
@@ -97,6 +99,7 @@ SECTIONS
   PROVIDE(_bss_start = .);
   SBSS(0)
   BSS(0)
+   __bss_stop = .;
   _end = .;
   PROVIDE (end = .);
 
index 950a9afa38f8632239df166ac21ffe094229217e..96494fb646f74b2e1dddc42028f52db1a7afe36c 100644 (file)
@@ -17,7 +17,7 @@ OBJS          := misc.o
 
 # font.c and font.o
 CFLAGS_font.o  := -Dstatic=
-$(obj)/font.c: $(srctree)/drivers/video/console/font_8x8.c
+$(obj)/font.c: $(srctree)/lib/fonts/font_8x8.c
        $(call cmd,shipped)
 
 # piggy.S and piggy.o
index 5eddb997defef4dc49a054771f1f7eb4dd913538..debafc40200a4faf985c737aefbae80db4806e1c 100644 (file)
 /*
  * Conversion between a struct page and a physical address.
  *
- * Note: when converting an unknown physical address to a
- * struct page, the resulting pointer must be validated
- * using VALID_PAGE().  It must return an invalid struct page
- * for any physical address not corresponding to a system
- * RAM address.
- *
  *  page_to_pfn(page)  convert a struct page * to a PFN number
  *  pfn_to_page(pfn)   convert a _valid_ PFN number to struct page *
  *
index ef69c0c828253991c7b633a22822acc04d333633..374a055a8e6bb5886ead0595dabaa5627cf5868a 100644 (file)
@@ -277,11 +277,6 @@ static int __init pci_common_init(void)
                pci_bus_assign_resources(puv3_bus);
        }
 
-       /*
-        * Tell drivers about devices found.
-        */
-       pci_bus_add_devices(puv3_bus);
-
        return 0;
 }
 subsys_initcall(pci_common_init);
index 63df12d71ce386247971161ce4d070a089731ed1..ae6bc036db92afdc4de9f83de485caf2a86695fe 100644 (file)
@@ -383,59 +383,14 @@ static void __init free_unused_memmap(struct meminfo *mi)
  */
 void __init mem_init(void)
 {
-       unsigned long reserved_pages, free_pages;
-       struct memblock_region *reg;
-       int i;
-
        max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
 
        free_unused_memmap(&meminfo);
 
        /* this will put all unused low memory onto the freelists */
-       totalram_pages += free_all_bootmem();
-
-       reserved_pages = free_pages = 0;
-
-       for_each_bank(i, &meminfo) {
-               struct membank *bank = &meminfo.bank[i];
-               unsigned int pfn1, pfn2;
-               struct page *page, *end;
-
-               pfn1 = bank_pfn_start(bank);
-               pfn2 = bank_pfn_end(bank);
-
-               page = pfn_to_page(pfn1);
-               end  = pfn_to_page(pfn2 - 1) + 1;
-
-               do {
-                       if (PageReserved(page))
-                               reserved_pages++;
-                       else if (!page_count(page))
-                               free_pages++;
-                       page++;
-               } while (page < end);
-       }
-
-       /*
-        * Since our memory may not be contiguous, calculate the
-        * real number of pages we have in this system
-        */
-       printk(KERN_INFO "Memory:");
-       num_physpages = 0;
-       for_each_memblock(memory, reg) {
-               unsigned long pages = memblock_region_memory_end_pfn(reg) -
-                       memblock_region_memory_base_pfn(reg);
-               num_physpages += pages;
-               printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
-       }
-       printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
-
-       printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
-               nr_free_pages() << (PAGE_SHIFT-10),
-               free_pages << (PAGE_SHIFT-10),
-               reserved_pages << (PAGE_SHIFT-10),
-               totalhigh_pages << (PAGE_SHIFT-10));
+       free_all_bootmem();
 
+       mem_init_print_info(NULL);
        printk(KERN_NOTICE "Virtual kernel memory layout:\n"
                "    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
                "    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
@@ -464,7 +419,7 @@ void __init mem_init(void)
        BUILD_BUG_ON(TASK_SIZE                          > MODULES_VADDR);
        BUG_ON(TASK_SIZE                                > MODULES_VADDR);
 
-       if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
+       if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
                /*
                 * On a machine this small we won't get
                 * anywhere without overcommit, so turn
@@ -476,7 +431,7 @@ void __init mem_init(void)
 
 void free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -486,7 +441,7 @@ static int keep_initrd;
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
        if (!keep_initrd)
-               free_reserved_area(start, end, 0, "initrd");
+               free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 
 static int __init keepinitrd_setup(char *__unused)
index c49b4dc8ffe03ad37b93e716d59c63161453460c..2775023a074491e2ab3351a567a3735e3ca5066a 100644 (file)
@@ -102,6 +102,7 @@ config X86
        select HAVE_ARCH_SECCOMP_FILTER
        select BUILDTIME_EXTABLE_SORT
        select GENERIC_CMOS_UPDATE
+       select HAVE_ARCH_SOFT_DIRTY
        select CLOCKSOURCE_WATCHDOG
        select GENERIC_CLOCKEVENTS
        select ARCH_CLOCKSOURCE_DATA if X86_64
@@ -207,6 +208,12 @@ config ARCH_HIBERNATION_POSSIBLE
 config ARCH_SUSPEND_POSSIBLE
        def_bool y
 
+config ARCH_WANT_HUGE_PMD_SHARE
+       def_bool y
+
+config ARCH_WANT_GENERAL_HUGETLB
+       def_bool y
+
 config ZONE_DMA32
        bool
        default X86_64
@@ -336,6 +343,7 @@ config X86_EXTENDED_PLATFORM
 
          If you enable this option then you'll be able to select support
          for the following (non-PC) 32 bit x86 platforms:
+               Goldfish (Android emulator)
                AMD Elan
                NUMAQ (IBM/Sequent)
                RDC R-321x SoC
@@ -410,6 +418,7 @@ config X86_UV
 config X86_GOLDFISH
        bool "Goldfish (Virtual Platform)"
        depends on X86_32
+       depends on X86_EXTENDED_PLATFORM
        ---help---
         Enable support for the Goldfish virtual platform used primarily
         for Android development. Unless you are building for the Android
@@ -1058,8 +1067,16 @@ config MICROCODE_INTEL_LIB
        depends on MICROCODE_INTEL
 
 config MICROCODE_INTEL_EARLY
+       def_bool n
+
+config MICROCODE_AMD_EARLY
+       def_bool n
+
+config MICROCODE_EARLY
        bool "Early load microcode"
-       depends on MICROCODE_INTEL && BLK_DEV_INITRD
+       depends on MICROCODE=y && BLK_DEV_INITRD
+       select MICROCODE_INTEL_EARLY if MICROCODE_INTEL
+       select MICROCODE_AMD_EARLY if MICROCODE_AMD
        default y
        help
          This option provides functionality to read additional microcode data
@@ -1067,10 +1084,6 @@ config MICROCODE_INTEL_EARLY
          microcode to CPU's as early as possible. No functional change if no
          microcode data is glued to the initrd, therefore it's safe to say Y.
 
-config MICROCODE_EARLY
-       def_bool y
-       depends on MICROCODE_INTEL_EARLY
-
 config X86_MSR
        tristate "/dev/cpu/*/msr - Model-specific register support"
        ---help---
@@ -2246,11 +2259,11 @@ source "drivers/pcmcia/Kconfig"
 source "drivers/pci/hotplug/Kconfig"
 
 config RAPIDIO
-       bool "RapidIO support"
+       tristate "RapidIO support"
        depends on PCI
        default n
        help
-         If you say Y here, the kernel will include drivers and
+         If enabled this option will include drivers and the core
          infrastructure code to support RapidIO interconnect devices.
 
 source "drivers/rapidio/Kconfig"
index c198b7e13e7bba5be02fdd04db10681bdda97337..c963881de0d0bdac76923e8fa93e8cc02e6eaab4 100644 (file)
@@ -122,7 +122,6 @@ config DEBUG_NX_TEST
 config DOUBLEFAULT
        default y
        bool "Enable doublefault exception handler" if EXPERT
-       depends on X86_32
        ---help---
          This option allows trapping of rare doublefault exceptions that
          would otherwise cause a system to silently reboot. Disabling this
@@ -304,4 +303,14 @@ config DEBUG_NMI_SELFTEST
 
          If unsure, say N.
 
+config X86_DEBUG_STATIC_CPU_HAS
+       bool "Debug alternatives"
+       depends on DEBUG_KERNEL
+       ---help---
+         This option causes additional code to be generated which
+         fails if static_cpu_has() is used before alternatives have
+         run.
+
+         If unsure, say N.
+
 endmenu
index 5c477260294f6ef78b1c1de6998b4860cc64ffbb..07639c656fcd89b1212e14b57bfc910549a44407 100644 (file)
@@ -220,6 +220,12 @@ archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
        $(Q)$(MAKE) $(clean)=arch/x86/tools
 
+PHONY += kvmconfig
+kvmconfig:
+       $(if $(wildcard $(objtree)/.config),, $(error You need an existing .config for this target))
+       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m -O $(objtree) $(objtree)/.config arch/x86/configs/kvm_guest.config
+       $(Q)yes "" | $(MAKE) oldconfig
+
 define archhelp
   echo  '* bzImage      - Compressed kernel image (arch/x86/boot/bzImage)'
   echo  '  install      - Install kernel using'
@@ -233,4 +239,5 @@ define archhelp
   echo  '                  bzdisk/fdimage*/isoimage also accept:'
   echo  '                  FDARGS="..."  arguments for the booted kernel'
   echo  '                  FDINITRD=file initrd for the booted kernel'
+  echo  '  kvmconfig   - Enable additional options for guest kernel support'
 endef
index c205035a6b96b836ef683ddf8592dbc9c82200e6..d606463aa6d63bfdab5641e6bd7e6b68545e32d9 100644 (file)
@@ -992,18 +992,20 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
        efi_memory_desc_t *mem_map;
        efi_status_t status;
        __u32 desc_version;
+       bool called_exit = false;
        u8 nr_entries;
        int i;
 
        size = sizeof(*mem_map) * 32;
 
 again:
-       size += sizeof(*mem_map);
+       size += sizeof(*mem_map) * 2;
        _size = size;
        status = low_alloc(size, 1, (unsigned long *)&mem_map);
        if (status != EFI_SUCCESS)
                return status;
 
+get_map:
        status = efi_call_phys5(sys_table->boottime->get_memory_map, &size,
                                mem_map, &key, &desc_size, &desc_version);
        if (status == EFI_BUFFER_TOO_SMALL) {
@@ -1029,8 +1031,20 @@ again:
        /* Might as well exit boot services now */
        status = efi_call_phys2(sys_table->boottime->exit_boot_services,
                                handle, key);
-       if (status != EFI_SUCCESS)
-               goto free_mem_map;
+       if (status != EFI_SUCCESS) {
+               /*
+                * ExitBootServices() will fail if any of the event
+                * handlers change the memory map. In which case, we
+                * must be prepared to retry, but only once so that
+                * we're guaranteed to exit on repeated failures instead
+                * of spinning forever.
+                */
+               if (called_exit)
+                       goto free_mem_map;
+
+               called_exit = true;
+               goto get_map;
+       }
 
        /* Historic? */
        boot_params->alt_mem_k = 32 * 1024;
index 16f24e6dad79826e8714a01fb5db750c1551dc6f..06e71c2c16bf012c006fab90caa72bb9d25cb8db 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <asm/segment.h>
-#include <asm/pgtable_types.h>
-#include <asm/page_types.h>
 #include <asm/boot.h>
 #include <asm/msr.h>
 #include <asm/processor-flags.h>
index 94c54465002003e34af8f6fb3d14a1be839fdeba..c941d6a8887f8099cb31edabd9a6be80d11b8a1d 100644 (file)
@@ -243,6 +243,7 @@ static void parse_zoffset(char *fname)
        c = fread(buf, 1, sizeof(buf) - 1, file);
        if (ferror(file))
                die("read-error on `zoffset.h'");
+       fclose(file);
        buf[c] = 0;
 
        p = (char *)buf;
diff --git a/arch/x86/configs/kvm_guest.config b/arch/x86/configs/kvm_guest.config
new file mode 100644 (file)
index 0000000..f9affcc
--- /dev/null
@@ -0,0 +1,28 @@
+CONFIG_NET=y
+CONFIG_NET_CORE=y
+CONFIG_NETDEVICES=y
+CONFIG_BLOCK=y
+CONFIG_BLK_DEV=y
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_INET=y
+CONFIG_TTY=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_BINFMT_ELF=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_VIRTUALIZATION=y
+CONFIG_HYPERVISOR_GUEST=y
+CONFIG_PARAVIRT=y
+CONFIG_KVM_GUEST=y
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_NET=y
+CONFIG_9P_FS=y
+CONFIG_NET_9P=y
+CONFIG_NET_9P_VIRTIO=y
index cf1a471a18a2f7dc1178810fc80d8c3b6462c46a..bccfca68430ec1bb130feb6a87a37385b8b7b6af 100644 (file)
@@ -34,8 +34,6 @@
 #include <asm/sys_ia32.h>
 #include <asm/smap.h>
 
-#define FIX_EFLAGS     __FIX_EFLAGS
-
 int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
 {
        int err = 0;
index b31bf97775fcbeea3b29a9537092b24b379aba67..2dfac58f3b11049e21b9ed752546f873b207adb0 100644 (file)
@@ -111,7 +111,7 @@ static inline void acpi_disable_pci(void)
 }
 
 /* Low-level suspend routine. */
-extern int acpi_suspend_lowlevel(void);
+extern int (*acpi_suspend_lowlevel)(void);
 
 /* Physical address to resume after wakeup */
 #define acpi_wakeup_address ((unsigned long)(real_mode_header->wakeup_start))
index 3388034222390150c0ee27674a012e6b3a47095b..f8119b582c3c0b6e724aa4f1552269d2854de904 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/fixmap.h>
 #include <asm/mpspec.h>
 #include <asm/msr.h>
+#include <asm/idle.h>
 
 #define ARCH_APICTIMER_STOPS_ON_C3     1
 
@@ -687,5 +688,31 @@ extern int default_check_phys_apicid_present(int phys_apicid);
 #endif
 
 #endif /* CONFIG_X86_LOCAL_APIC */
+extern void irq_enter(void);
+extern void irq_exit(void);
+
+static inline void entering_irq(void)
+{
+       irq_enter();
+       exit_idle();
+}
+
+static inline void entering_ack_irq(void)
+{
+       ack_APIC_irq();
+       entering_irq();
+}
+
+static inline void exiting_irq(void)
+{
+       irq_exit();
+}
+
+static inline void exiting_ack_irq(void)
+{
+       irq_exit();
+       /* Ack only at the end to avoid potential reentry */
+       ack_APIC_irq();
+}
 
 #endif /* _ASM_X86_APIC_H */
index e99ac27f95b2cbcf9c0c5458cce4a946b7917b5e..47538a61c91bfddc1eff8a6712e4f89a5b0187b4 100644 (file)
@@ -92,7 +92,7 @@
 #define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* "" Lfence synchronizes RDTSC */
 #define X86_FEATURE_11AP       (3*32+19) /* "" Bad local APIC aka 11AP */
 #define X86_FEATURE_NOPL       (3*32+20) /* The NOPL (0F 1F) instructions */
-                                         /* 21 available, was AMD_C1E */
+#define X86_FEATURE_ALWAYS     (3*32+21) /* "" Always-present feature */
 #define X86_FEATURE_XTOPOLOGY  (3*32+22) /* cpu topology enum extensions */
 #define X86_FEATURE_TSC_RELIABLE (3*32+23) /* TSC is known to be reliable */
 #define X86_FEATURE_NONSTOP_TSC        (3*32+24) /* TSC does not stop in C states */
@@ -356,15 +356,36 @@ extern const char * const x86_power_flags[32];
 #endif /* CONFIG_X86_64 */
 
 #if __GNUC__ >= 4
+extern void warn_pre_alternatives(void);
+extern bool __static_cpu_has_safe(u16 bit);
+
 /*
  * Static testing of CPU features.  Used the same as boot_cpu_has().
  * These are only valid after alternatives have run, but will statically
  * patch the target code for additional performance.
- *
  */
 static __always_inline __pure bool __static_cpu_has(u16 bit)
 {
 #if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
+
+#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
+               /*
+                * Catch too early usage of this before alternatives
+                * have run.
+                */
+               asm goto("1: jmp %l[t_warn]\n"
+                        "2:\n"
+                        ".section .altinstructions,\"a\"\n"
+                        " .long 1b - .\n"
+                        " .long 0\n"           /* no replacement */
+                        " .word %P0\n"         /* 1: do replace */
+                        " .byte 2b - 1b\n"     /* source len */
+                        " .byte 0\n"           /* replacement len */
+                        ".previous\n"
+                        /* skipping size check since replacement size = 0 */
+                        : : "i" (X86_FEATURE_ALWAYS) : : t_warn);
+#endif
+
                asm goto("1: jmp %l[t_no]\n"
                         "2:\n"
                         ".section .altinstructions,\"a\"\n"
@@ -379,7 +400,13 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
                return true;
        t_no:
                return false;
-#else
+
+#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
+       t_warn:
+               warn_pre_alternatives();
+               return false;
+#endif
+#else /* GCC_VERSION >= 40500 */
                u8 flag;
                /* Open-coded due to __stringify() in ALTERNATIVE() */
                asm volatile("1: movb $0,%0\n"
@@ -411,11 +438,94 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
                __static_cpu_has(bit) :                         \
                boot_cpu_has(bit)                               \
 )
+
+static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
+{
+#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
+/*
+ * We need to spell the jumps to the compiler because, depending on the offset,
+ * the replacement jump can be bigger than the original jump, and this we cannot
+ * have. Thus, we force the jump to the widest, 4-byte, signed relative
+ * offset even though the last would often fit in less bytes.
+ */
+               asm goto("1: .byte 0xe9\n .long %l[t_dynamic] - 2f\n"
+                        "2:\n"
+                        ".section .altinstructions,\"a\"\n"
+                        " .long 1b - .\n"              /* src offset */
+                        " .long 3f - .\n"              /* repl offset */
+                        " .word %P1\n"                 /* always replace */
+                        " .byte 2b - 1b\n"             /* src len */
+                        " .byte 4f - 3f\n"             /* repl len */
+                        ".previous\n"
+                        ".section .altinstr_replacement,\"ax\"\n"
+                        "3: .byte 0xe9\n .long %l[t_no] - 2b\n"
+                        "4:\n"
+                        ".previous\n"
+                        ".section .altinstructions,\"a\"\n"
+                        " .long 1b - .\n"              /* src offset */
+                        " .long 0\n"                   /* no replacement */
+                        " .word %P0\n"                 /* feature bit */
+                        " .byte 2b - 1b\n"             /* src len */
+                        " .byte 0\n"                   /* repl len */
+                        ".previous\n"
+                        : : "i" (bit), "i" (X86_FEATURE_ALWAYS)
+                        : : t_dynamic, t_no);
+               return true;
+       t_no:
+               return false;
+       t_dynamic:
+               return __static_cpu_has_safe(bit);
+#else /* GCC_VERSION >= 40500 */
+               u8 flag;
+               /* Open-coded due to __stringify() in ALTERNATIVE() */
+               asm volatile("1: movb $2,%0\n"
+                            "2:\n"
+                            ".section .altinstructions,\"a\"\n"
+                            " .long 1b - .\n"          /* src offset */
+                            " .long 3f - .\n"          /* repl offset */
+                            " .word %P2\n"             /* always replace */
+                            " .byte 2b - 1b\n"         /* source len */
+                            " .byte 4f - 3f\n"         /* replacement len */
+                            ".previous\n"
+                            ".section .discard,\"aw\",@progbits\n"
+                            " .byte 0xff + (4f-3f) - (2b-1b)\n" /* size check */
+                            ".previous\n"
+                            ".section .altinstr_replacement,\"ax\"\n"
+                            "3: movb $0,%0\n"
+                            "4:\n"
+                            ".previous\n"
+                            ".section .altinstructions,\"a\"\n"
+                            " .long 1b - .\n"          /* src offset */
+                            " .long 5f - .\n"          /* repl offset */
+                            " .word %P1\n"             /* feature bit */
+                            " .byte 4b - 3b\n"         /* src len */
+                            " .byte 6f - 5f\n"         /* repl len */
+                            ".previous\n"
+                            ".section .discard,\"aw\",@progbits\n"
+                            " .byte 0xff + (6f-5f) - (4b-3b)\n" /* size check */
+                            ".previous\n"
+                            ".section .altinstr_replacement,\"ax\"\n"
+                            "5: movb $1,%0\n"
+                            "6:\n"
+                            ".previous\n"
+                            : "=qm" (flag)
+                            : "i" (bit), "i" (X86_FEATURE_ALWAYS));
+               return (flag == 2 ? __static_cpu_has_safe(bit) : flag);
+#endif
+}
+
+#define static_cpu_has_safe(bit)                               \
+(                                                              \
+       __builtin_constant_p(boot_cpu_has(bit)) ?               \
+               boot_cpu_has(bit) :                             \
+               _static_cpu_has_safe(bit)                       \
+)
 #else
 /*
  * gcc 3.x is too stupid to do the static test; fall back to dynamic.
  */
-#define static_cpu_has(bit) boot_cpu_has(bit)
+#define static_cpu_has(bit)            boot_cpu_has(bit)
+#define static_cpu_has_safe(bit)       boot_cpu_has(bit)
 #endif
 
 #define cpu_has_bug(c, bit)    cpu_has(c, (bit))
index 8bf1c06070d5655b3fcad7727ad53bd5e8ceaf8a..b90e5dfeee462b55bd942b4bdc5fab2eb4817403 100644 (file)
@@ -36,8 +36,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in
 
 extern struct desc_ptr idt_descr;
 extern gate_desc idt_table[];
-extern struct desc_ptr nmi_idt_descr;
-extern gate_desc nmi_idt_table[];
+extern struct desc_ptr debug_idt_descr;
+extern gate_desc debug_idt_table[];
 
 struct gdt_page {
        struct desc_struct gdt[GDT_ENTRIES];
@@ -316,7 +316,20 @@ static inline void set_nmi_gate(int gate, void *addr)
        gate_desc s;
 
        pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS);
-       write_idt_entry(nmi_idt_table, gate, &s);
+       write_idt_entry(debug_idt_table, gate, &s);
+}
+#endif
+
+#ifdef CONFIG_TRACING
+extern struct desc_ptr trace_idt_descr;
+extern gate_desc trace_idt_table[];
+static inline void write_trace_idt_entry(int entry, const gate_desc *gate)
+{
+       write_idt_entry(trace_idt_table, entry, gate);
+}
+#else
+static inline void write_trace_idt_entry(int entry, const gate_desc *gate)
+{
 }
 #endif
 
@@ -331,6 +344,7 @@ static inline void _set_gate(int gate, unsigned type, void *addr,
         * setup time
         */
        write_idt_entry(idt_table, gate, &s);
+       write_trace_idt_entry(gate, &s);
 }
 
 /*
@@ -360,12 +374,39 @@ static inline void alloc_system_vector(int vector)
        }
 }
 
-static inline void alloc_intr_gate(unsigned int n, void *addr)
+#ifdef CONFIG_TRACING
+static inline void trace_set_intr_gate(unsigned int gate, void *addr)
+{
+       gate_desc s;
+
+       pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS);
+       write_idt_entry(trace_idt_table, gate, &s);
+}
+
+static inline void __trace_alloc_intr_gate(unsigned int n, void *addr)
+{
+       trace_set_intr_gate(n, addr);
+}
+#else
+static inline void trace_set_intr_gate(unsigned int gate, void *addr)
+{
+}
+
+#define __trace_alloc_intr_gate(n, addr)
+#endif
+
+static inline void __alloc_intr_gate(unsigned int n, void *addr)
 {
-       alloc_system_vector(n);
        set_intr_gate(n, addr);
 }
 
+#define alloc_intr_gate(n, addr)                               \
+       do {                                                    \
+               alloc_system_vector(n);                         \
+               __alloc_intr_gate(n, addr);                     \
+               __trace_alloc_intr_gate(n, trace_##addr);       \
+       } while (0)
+
 /*
  * This routine sets up an interrupt gate at directory privilege level 3.
  */
@@ -405,4 +446,70 @@ static inline void set_system_intr_gate_ist(int n, void *addr, unsigned ist)
        _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS);
 }
 
+#ifdef CONFIG_X86_64
+DECLARE_PER_CPU(u32, debug_idt_ctr);
+static inline bool is_debug_idt_enabled(void)
+{
+       if (this_cpu_read(debug_idt_ctr))
+               return true;
+
+       return false;
+}
+
+static inline void load_debug_idt(void)
+{
+       load_idt((const struct desc_ptr *)&debug_idt_descr);
+}
+#else
+static inline bool is_debug_idt_enabled(void)
+{
+       return false;
+}
+
+static inline void load_debug_idt(void)
+{
+}
+#endif
+
+#ifdef CONFIG_TRACING
+extern atomic_t trace_idt_ctr;
+static inline bool is_trace_idt_enabled(void)
+{
+       if (atomic_read(&trace_idt_ctr))
+               return true;
+
+       return false;
+}
+
+static inline void load_trace_idt(void)
+{
+       load_idt((const struct desc_ptr *)&trace_idt_descr);
+}
+#else
+static inline bool is_trace_idt_enabled(void)
+{
+       return false;
+}
+
+static inline void load_trace_idt(void)
+{
+}
+#endif
+
+/*
+ * The load_current_idt() must be called with interrupts disabled
+ * to avoid races. That way the IDT will always be set back to the expected
+ * descriptor. It's also called when a CPU is being initialized, and
+ * that doesn't need to disable interrupts, as nothing should be
+ * bothering the CPU then.
+ */
+static inline void load_current_idt(void)
+{
+       if (is_debug_idt_enabled())
+               load_debug_idt();
+       else if (is_trace_idt_enabled())
+               load_trace_idt();
+       else
+               load_idt((const struct desc_ptr *)&idt_descr);
+}
 #endif /* _ASM_X86_DESC_H */
index 60c89f30c727458df128543a6302e95aeede8758..0062a0125041cb2958621f98b4a3f8838e24c8bc 100644 (file)
@@ -52,40 +52,40 @@ extern u64 efi_call6(void *fp, u64 arg1, u64 arg2, u64 arg3,
                     u64 arg4, u64 arg5, u64 arg6);
 
 #define efi_call_phys0(f)                      \
-       efi_call0((void *)(f))
+       efi_call0((f))
 #define efi_call_phys1(f, a1)                  \
-       efi_call1((void *)(f), (u64)(a1))
+       efi_call1((f), (u64)(a1))
 #define efi_call_phys2(f, a1, a2)                      \
-       efi_call2((void *)(f), (u64)(a1), (u64)(a2))
+       efi_call2((f), (u64)(a1), (u64)(a2))
 #define efi_call_phys3(f, a1, a2, a3)                          \
-       efi_call3((void *)(f), (u64)(a1), (u64)(a2), (u64)(a3))
+       efi_call3((f), (u64)(a1), (u64)(a2), (u64)(a3))
 #define efi_call_phys4(f, a1, a2, a3, a4)                              \
-       efi_call4((void *)(f), (u64)(a1), (u64)(a2), (u64)(a3),         \
+       efi_call4((f), (u64)(a1), (u64)(a2), (u64)(a3),         \
                  (u64)(a4))
 #define efi_call_phys5(f, a1, a2, a3, a4, a5)                          \
-       efi_call5((void *)(f), (u64)(a1), (u64)(a2), (u64)(a3),         \
+       efi_call5((f), (u64)(a1), (u64)(a2), (u64)(a3),         \
                  (u64)(a4), (u64)(a5))
 #define efi_call_phys6(f, a1, a2, a3, a4, a5, a6)                      \
-       efi_call6((void *)(f), (u64)(a1), (u64)(a2), (u64)(a3),         \
+       efi_call6((f), (u64)(a1), (u64)(a2), (u64)(a3),         \
                  (u64)(a4), (u64)(a5), (u64)(a6))
 
 #define efi_call_virt0(f)                              \
-       efi_call0((void *)(efi.systab->runtime->f))
+       efi_call0((efi.systab->runtime->f))
 #define efi_call_virt1(f, a1)                                  \
-       efi_call1((void *)(efi.systab->runtime->f), (u64)(a1))
+       efi_call1((efi.systab->runtime->f), (u64)(a1))
 #define efi_call_virt2(f, a1, a2)                                      \
-       efi_call2((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2))
+       efi_call2((efi.systab->runtime->f), (u64)(a1), (u64)(a2))
 #define efi_call_virt3(f, a1, a2, a3)                                  \
-       efi_call3((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
+       efi_call3((efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
                  (u64)(a3))
 #define efi_call_virt4(f, a1, a2, a3, a4)                              \
-       efi_call4((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
+       efi_call4((efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
                  (u64)(a3), (u64)(a4))
 #define efi_call_virt5(f, a1, a2, a3, a4, a5)                          \
-       efi_call5((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
+       efi_call5((efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
                  (u64)(a3), (u64)(a4), (u64)(a5))
 #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6)                      \
-       efi_call6((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
+       efi_call6((efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
                  (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6))
 
 extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
index 9bd4ecac72be33f4366e08d5a98ac687cf4a6fe7..dc5fa661465f9a3fda9788c2f6caf9adc185a741 100644 (file)
 BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
 BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
 BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR)
-BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR)
-BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR)
+BUILD_INTERRUPT3(irq_move_cleanup_interrupt, IRQ_MOVE_CLEANUP_VECTOR,
+                smp_irq_move_cleanup_interrupt)
+BUILD_INTERRUPT3(reboot_interrupt, REBOOT_VECTOR, smp_reboot_interrupt)
 #endif
 
 BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR)
 
 #ifdef CONFIG_HAVE_KVM
-BUILD_INTERRUPT(kvm_posted_intr_ipi, POSTED_INTR_VECTOR)
+BUILD_INTERRUPT3(kvm_posted_intr_ipi, POSTED_INTR_VECTOR,
+                smp_kvm_posted_intr_ipi)
 #endif
 
 /*
index 0dc7d9e21c34f2d8e8284c7f9a76b78c19eef2e9..e846225265ed4a6b8dccc6384b06a6e806d9f1c6 100644 (file)
@@ -81,10 +81,10 @@ enum fixed_addresses {
                            + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
        VVAR_PAGE,
        VSYSCALL_HPET,
-#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 e25cc33ec54d5476dba4a46337ab893785e48783..4d0bda7b11e3b6715b026f5995183ddb4e218ae1 100644 (file)
@@ -62,10 +62,8 @@ extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
 #define xstateregs_active      fpregs_active
 
 #ifdef CONFIG_MATH_EMULATION
-# define HAVE_HWFP             (boot_cpu_data.hard_math)
 extern void finit_soft_fpu(struct i387_soft_struct *soft);
 #else
-# define HAVE_HWFP             1
 static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
 #endif
 
@@ -345,7 +343,7 @@ static inline void __thread_fpu_end(struct task_struct *tsk)
 
 static inline void __thread_fpu_begin(struct task_struct *tsk)
 {
-       if (!use_eager_fpu())
+       if (!static_cpu_has_safe(X86_FEATURE_EAGER_FPU))
                clts();
        __thread_set_has_fpu(tsk);
 }
index 1da97efad08ae3c79f73827be832ed5618dd0372..e4ac559c4a244849f32fb5914a333ae8eb60695b 100644 (file)
@@ -77,6 +77,23 @@ extern void threshold_interrupt(void);
 extern void call_function_interrupt(void);
 extern void call_function_single_interrupt(void);
 
+#ifdef CONFIG_TRACING
+/* Interrupt handlers registered during init_IRQ */
+extern void trace_apic_timer_interrupt(void);
+extern void trace_x86_platform_ipi(void);
+extern void trace_error_interrupt(void);
+extern void trace_irq_work_interrupt(void);
+extern void trace_spurious_interrupt(void);
+extern void trace_thermal_interrupt(void);
+extern void trace_reschedule_interrupt(void);
+extern void trace_threshold_interrupt(void);
+extern void trace_call_function_interrupt(void);
+extern void trace_call_function_single_interrupt(void);
+#define trace_irq_move_cleanup_interrupt  irq_move_cleanup_interrupt
+#define trace_reboot_interrupt  reboot_interrupt
+#define trace_kvm_posted_intr_ipi kvm_posted_intr_ipi
+#endif /* CONFIG_TRACING */
+
 /* IOAPIC */
 #define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1<<(x)) & io_apic_irqs))
 extern unsigned long io_apic_irqs;
index 3741c653767ca958d0cc56f91d4807a4db7440b7..f87f7fcefa0acdc4856aa576078a34c2d4002e1e 100644 (file)
@@ -59,7 +59,7 @@
        (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
                          | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE     \
                          | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_PCIDE \
-                         | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_RDWRGSFS \
+                         | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \
                          | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
 
 #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
@@ -222,14 +222,22 @@ struct kvm_mmu_page {
        int root_count;          /* Currently serving as active root */
        unsigned int unsync_children;
        unsigned long parent_ptes;      /* Reverse mapping for parent_pte */
+
+       /* The page is obsolete if mmu_valid_gen != kvm->arch.mmu_valid_gen.  */
+       unsigned long mmu_valid_gen;
+
        DECLARE_BITMAP(unsync_child_bitmap, 512);
 
 #ifdef CONFIG_X86_32
+       /*
+        * Used out of the mmu-lock to avoid reading spte values while an
+        * update is in progress; see the comments in __get_spte_lockless().
+        */
        int clear_spte_count;
 #endif
 
+       /* Number of writes since the last time traversal visited this page.  */
        int write_flooding_count;
-       bool mmio_cached;
 };
 
 struct kvm_pio_request {
@@ -529,11 +537,14 @@ struct kvm_arch {
        unsigned int n_requested_mmu_pages;
        unsigned int n_max_mmu_pages;
        unsigned int indirect_shadow_pages;
+       unsigned long mmu_valid_gen;
        struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
        /*
         * Hash table of struct kvm_mmu_page.
         */
        struct list_head active_mmu_pages;
+       struct list_head zapped_obsolete_pages;
+
        struct list_head assigned_dev_head;
        struct iommu_domain *iommu_domain;
        int iommu_flags;
@@ -769,7 +780,7 @@ void kvm_mmu_write_protect_pt_masked(struct kvm *kvm,
                                     struct kvm_memory_slot *slot,
                                     gfn_t gfn_offset, unsigned long mask);
 void kvm_mmu_zap_all(struct kvm *kvm);
-void kvm_mmu_zap_mmio_sptes(struct kvm *kvm);
+void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm);
 unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm);
 void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages);
 
index fa5f71e021d5363735caeaa3fbb834600d4bc5f2..6b52980c29c10be9673c2aed2acc68176377d547 100644 (file)
@@ -61,7 +61,7 @@
 #define MCJ_CTX_IRQ            0x2  /* inject context: IRQ */
 #define MCJ_NMI_BROADCAST      0x4  /* do NMI broadcasting */
 #define MCJ_EXCEPTION          0x8  /* raise as exception */
-#define MCJ_IRQ_BRAODCAST      0x10 /* do IRQ broadcasting */
+#define MCJ_IRQ_BROADCAST      0x10 /* do IRQ broadcasting */
 
 #define MCE_OVERFLOW 0         /* bit 0 in flags means overflow */
 
diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h
new file mode 100644 (file)
index 0000000..c6b043f
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef _ASM_X86_MICROCODE_AMD_H
+#define _ASM_X86_MICROCODE_AMD_H
+
+#include <asm/microcode.h>
+
+#define UCODE_MAGIC                    0x00414d44
+#define UCODE_EQUIV_CPU_TABLE_TYPE     0x00000000
+#define UCODE_UCODE_TYPE               0x00000001
+
+#define SECTION_HDR_SIZE               8
+#define CONTAINER_HDR_SZ               12
+
+struct equiv_cpu_entry {
+       u32     installed_cpu;
+       u32     fixed_errata_mask;
+       u32     fixed_errata_compare;
+       u16     equiv_cpu;
+       u16     res;
+} __attribute__((packed));
+
+struct microcode_header_amd {
+       u32     data_code;
+       u32     patch_id;
+       u16     mc_patch_data_id;
+       u8      mc_patch_data_len;
+       u8      init_flag;
+       u32     mc_patch_data_checksum;
+       u32     nb_dev_id;
+       u32     sb_dev_id;
+       u16     processor_rev_id;
+       u8      nb_rev_id;
+       u8      sb_rev_id;
+       u8      bios_api_rev;
+       u8      reserved1[3];
+       u32     match_reg[8];
+} __attribute__((packed));
+
+struct microcode_amd {
+       struct microcode_header_amd     hdr;
+       unsigned int                    mpb[0];
+};
+
+static inline u16 find_equiv_id(struct equiv_cpu_entry *equiv_cpu_table,
+                               unsigned int sig)
+{
+       int i = 0;
+
+       if (!equiv_cpu_table)
+               return 0;
+
+       while (equiv_cpu_table[i].installed_cpu != 0) {
+               if (sig == equiv_cpu_table[i].installed_cpu)
+                       return equiv_cpu_table[i].equiv_cpu;
+
+               i++;
+       }
+       return 0;
+}
+
+extern int __apply_microcode_amd(struct microcode_amd *mc_amd);
+extern int apply_microcode_amd(int cpu);
+extern enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size);
+
+#ifdef CONFIG_MICROCODE_AMD_EARLY
+#ifdef CONFIG_X86_32
+#define MPB_MAX_SIZE PAGE_SIZE
+extern u8 amd_bsp_mpb[MPB_MAX_SIZE];
+#endif
+extern void __init load_ucode_amd_bsp(void);
+extern void __cpuinit load_ucode_amd_ap(void);
+extern int __init save_microcode_in_initrd_amd(void);
+#else
+static inline void __init load_ucode_amd_bsp(void) {}
+static inline void __cpuinit load_ucode_amd_ap(void) {}
+static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; }
+#endif
+
+#endif /* _ASM_X86_MICROCODE_AMD_H */
index 5356f927d411cd237c4249624ab850bf3c46daff..87a085333cbf563f2e0cc1ad8845fa7d822cfc99 100644 (file)
@@ -67,10 +67,12 @@ update_match_revision(struct microcode_header_intel *mc_header, int rev);
 extern void __init load_ucode_intel_bsp(void);
 extern void __cpuinit load_ucode_intel_ap(void);
 extern void show_ucode_info_early(void);
+extern int __init save_microcode_in_initrd_intel(void);
 #else
 static inline __init void load_ucode_intel_bsp(void) {}
 static inline __cpuinit void load_ucode_intel_ap(void) {}
 static inline void show_ucode_info_early(void) {}
+static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; }
 #endif
 
 #if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU)
index c2934be2446a73df2d66c97e32911b5d47860f98..cd9c41938b8a1ba8f830c888a078e8395cf76af1 100644 (file)
@@ -12,6 +12,9 @@ struct ms_hyperv_info {
 extern struct ms_hyperv_info ms_hyperv;
 
 void hyperv_callback_vector(void);
+#ifdef CONFIG_TRACING
+#define trace_hyperv_callback_vector hyperv_callback_vector
+#endif
 void hyperv_vector_handler(struct pt_regs *regs);
 void hv_register_vmbus_handler(int irq, irq_handler_t handler);
 
index 03f90c8a5a7c392b7f50ea0914cba04b0718fa76..0208c3c2cbc6733e3053681a5430428d5cacff5e 100644 (file)
@@ -42,17 +42,14 @@ do {                                                                \
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
  *                                 from 1 to a 0 value
  *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 1
  *
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if it
- * wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
  */
-static inline int __mutex_fastpath_lock_retval(atomic_t *count,
-                                              int (*fail_fn)(atomic_t *))
+static inline int __mutex_fastpath_lock_retval(atomic_t *count)
 {
        if (unlikely(atomic_dec_return(count) < 0))
-               return fail_fn(count);
+               return -1;
        else
                return 0;
 }
index 68a87b0f8e29e491e4b71c3c9eb68d78efb6db3c..2c543fff241bb85cb3b07c6cd1c19033380ffd3c 100644 (file)
@@ -37,17 +37,14 @@ do {                                                                \
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
  *                                 from 1 to a 0 value
  *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 1
  *
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
  */
-static inline int __mutex_fastpath_lock_retval(atomic_t *count,
-                                              int (*fail_fn)(atomic_t *))
+static inline int __mutex_fastpath_lock_retval(atomic_t *count)
 {
        if (unlikely(atomic_dec_return(count) < 0))
-               return fail_fn(count);
+               return -1;
        else
                return 0;
 }
index 57cb634022136f39f3c9b4eebe9390b917717d89..8249df45d2f2b52dcecd46411db73408bf1ab392 100644 (file)
@@ -29,6 +29,9 @@
 #define ARCH_PERFMON_EVENTSEL_INV                      (1ULL << 23)
 #define ARCH_PERFMON_EVENTSEL_CMASK                    0xFF000000ULL
 
+#define HSW_IN_TX                                      (1ULL << 32)
+#define HSW_IN_TX_CHECKPOINTED                         (1ULL << 33)
+
 #define AMD64_EVENTSEL_INT_CORE_ENABLE                 (1ULL << 36)
 #define AMD64_EVENTSEL_GUESTONLY                       (1ULL << 40)
 #define AMD64_EVENTSEL_HOSTONLY                                (1ULL << 41)
index 5b0818bc89635cb6e27d5793fb4a32f83866c192..7dc305a46058a230ad5eef2df9f5e54b66ac0017 100644 (file)
@@ -207,7 +207,7 @@ static inline pte_t pte_mkexec(pte_t pte)
 
 static inline pte_t pte_mkdirty(pte_t pte)
 {
-       return pte_set_flags(pte, _PAGE_DIRTY);
+       return pte_set_flags(pte, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
 }
 
 static inline pte_t pte_mkyoung(pte_t pte)
@@ -271,7 +271,7 @@ static inline pmd_t pmd_wrprotect(pmd_t pmd)
 
 static inline pmd_t pmd_mkdirty(pmd_t pmd)
 {
-       return pmd_set_flags(pmd, _PAGE_DIRTY);
+       return pmd_set_flags(pmd, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
 }
 
 static inline pmd_t pmd_mkhuge(pmd_t pmd)
@@ -294,6 +294,26 @@ static inline pmd_t pmd_mknotpresent(pmd_t pmd)
        return pmd_clear_flags(pmd, _PAGE_PRESENT);
 }
 
+static inline int pte_soft_dirty(pte_t pte)
+{
+       return pte_flags(pte) & _PAGE_SOFT_DIRTY;
+}
+
+static inline int pmd_soft_dirty(pmd_t pmd)
+{
+       return pmd_flags(pmd) & _PAGE_SOFT_DIRTY;
+}
+
+static inline pte_t pte_mksoft_dirty(pte_t pte)
+{
+       return pte_set_flags(pte, _PAGE_SOFT_DIRTY);
+}
+
+static inline pmd_t pmd_mksoft_dirty(pmd_t pmd)
+{
+       return pmd_set_flags(pmd, _PAGE_SOFT_DIRTY);
+}
+
 /*
  * Mask out unsupported bits in a present pgprot.  Non-present pgprots
  * can use those bits for other purposes, so leave them be.
index e6423002c10b5211af8fd45cb1cefa120d45c534..c98ac63aae487580727cac5d9f194ef04d9913cb 100644 (file)
 #define _PAGE_HIDDEN   (_AT(pteval_t, 0))
 #endif
 
+/*
+ * The same hidden bit is used by kmemcheck, but since kmemcheck
+ * works on kernel pages while soft-dirty engine on user space,
+ * they do not conflict with each other.
+ */
+
+#ifdef CONFIG_MEM_SOFT_DIRTY
+#define _PAGE_SOFT_DIRTY       (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN)
+#else
+#define _PAGE_SOFT_DIRTY       (_AT(pteval_t, 0))
+#endif
+
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
 #define _PAGE_NX       (_AT(pteval_t, 1) << _PAGE_BIT_NX)
 #else
index 22224b3b43bb4587562ea1dd1374a1f8f9e571bb..29937c4f6ff8d560900bfbad9a79c919a24aa710 100644 (file)
@@ -89,9 +89,9 @@ struct cpuinfo_x86 {
        char                    wp_works_ok;    /* It doesn't on 386's */
 
        /* Problems on some 486Dx4's and old 386's: */
-       char                    hard_math;
        char                    rfu;
        char                    pad0;
+       char                    pad1;
 #else
        /* Number of 4K pages in DTLB/ITLB combined(in pages): */
        int                     x86_tlbsize;
@@ -164,6 +164,7 @@ extern const struct seq_operations cpuinfo_op;
 #define cache_line_size()      (boot_cpu_data.x86_cache_alignment)
 
 extern void cpu_detect(struct cpuinfo_x86 *c);
+extern void __cpuinit fpu_detect(struct cpuinfo_x86 *c);
 
 extern void early_cpu_init(void);
 extern void identify_boot_cpu(void);
@@ -981,5 +982,5 @@ bool xen_set_default_idle(void);
 #endif
 
 void stop_this_cpu(void *dummy);
-
+void df_debug(struct pt_regs *regs, long error_code);
 #endif /* _ASM_X86_PROCESSOR_H */
index beff97f7df3790d04dfba1906fe657b1d024e579..7a958164088c10a61aeed98f6353152ebad83ff5 100644 (file)
@@ -7,10 +7,10 @@
 
 #include <asm/processor-flags.h>
 
-#define __FIX_EFLAGS   (X86_EFLAGS_AC | X86_EFLAGS_OF | \
+#define FIX_EFLAGS     (X86_EFLAGS_AC | X86_EFLAGS_OF | \
                         X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \
                         X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \
-                        X86_EFLAGS_CF)
+                        X86_EFLAGS_CF | X86_EFLAGS_RF)
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
 
index 41fc93a2e225d1793465e1ccf5e5ebc0e354d8a5..2f4d924fe6c9fdf0181b309a160b2dae42b7c384 100644 (file)
@@ -16,7 +16,7 @@ static inline void native_clts(void)
  * all loads stores around it, which can hurt performance. Solution is to
  * use a variable and mimic reads and writes to it to enforce serialization
  */
-static unsigned long __force_order;
+extern unsigned long __force_order;
 
 static inline unsigned long native_read_cr0(void)
 {
index a1df6e84691f962c46fa909af1d93dcd60c7360d..27811190cbd70e5787263e6f064069776064fe3f 100644 (file)
@@ -89,7 +89,6 @@ struct thread_info {
 #define TIF_FORK               18      /* ret_from_fork */
 #define TIF_NOHZ               19      /* in adaptive nohz mode */
 #define TIF_MEMDIE             20      /* is terminating due to OOM killer */
-#define TIF_DEBUG              21      /* uses debug registers */
 #define TIF_IO_BITMAP          22      /* uses I/O bitmap */
 #define TIF_FORCED_TF          24      /* true if TF in eflags artificially */
 #define TIF_BLOCKSTEP          25      /* set when we want DEBUGCTLMSR_BTF */
@@ -113,7 +112,6 @@ struct thread_info {
 #define _TIF_IA32              (1 << TIF_IA32)
 #define _TIF_FORK              (1 << TIF_FORK)
 #define _TIF_NOHZ              (1 << TIF_NOHZ)
-#define _TIF_DEBUG             (1 << TIF_DEBUG)
 #define _TIF_IO_BITMAP         (1 << TIF_IO_BITMAP)
 #define _TIF_FORCED_TF         (1 << TIF_FORCED_TF)
 #define _TIF_BLOCKSTEP         (1 << TIF_BLOCKSTEP)
@@ -154,7 +152,7 @@ struct thread_info {
        (_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP)
 
 #define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
-#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
+#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW)
 
 #define PREEMPT_ACTIVE         0x10000000
 
index 50a7fc0f824a8f027376f0f38af9d820502095bf..cf512003e6633309587e15f179d0745976f6b510 100644 (file)
@@ -62,7 +62,7 @@ static inline void __flush_tlb_all(void)
 
 static inline void __flush_tlb_one(unsigned long addr)
 {
-               __flush_tlb_single(addr);
+       __flush_tlb_single(addr);
 }
 
 #define TLB_FLUSH_ALL  -1UL
diff --git a/arch/x86/include/asm/trace/irq_vectors.h b/arch/x86/include/asm/trace/irq_vectors.h
new file mode 100644 (file)
index 0000000..2874df2
--- /dev/null
@@ -0,0 +1,104 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM irq_vectors
+
+#if !defined(_TRACE_IRQ_VECTORS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_IRQ_VECTORS_H
+
+#include <linux/tracepoint.h>
+
+extern void trace_irq_vector_regfunc(void);
+extern void trace_irq_vector_unregfunc(void);
+
+DECLARE_EVENT_CLASS(x86_irq_vector,
+
+       TP_PROTO(int vector),
+
+       TP_ARGS(vector),
+
+       TP_STRUCT__entry(
+               __field(                int,    vector  )
+       ),
+
+       TP_fast_assign(
+               __entry->vector = vector;
+       ),
+
+       TP_printk("vector=%d", __entry->vector) );
+
+#define DEFINE_IRQ_VECTOR_EVENT(name)          \
+DEFINE_EVENT_FN(x86_irq_vector, name##_entry,  \
+       TP_PROTO(int vector),                   \
+       TP_ARGS(vector),                        \
+       trace_irq_vector_regfunc,               \
+       trace_irq_vector_unregfunc);            \
+DEFINE_EVENT_FN(x86_irq_vector, name##_exit,   \
+       TP_PROTO(int vector),                   \
+       TP_ARGS(vector),                        \
+       trace_irq_vector_regfunc,               \
+       trace_irq_vector_unregfunc);
+
+
+/*
+ * local_timer - called when entering/exiting a local timer interrupt
+ * vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(local_timer);
+
+/*
+ * reschedule - called when entering/exiting a reschedule vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(reschedule);
+
+/*
+ * spurious_apic - called when entering/exiting a spurious apic vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(spurious_apic);
+
+/*
+ * error_apic - called when entering/exiting an error apic vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(error_apic);
+
+/*
+ * x86_platform_ipi - called when entering/exiting a x86 platform ipi interrupt
+ * vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(x86_platform_ipi);
+
+/*
+ * irq_work - called when entering/exiting a irq work interrupt
+ * vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(irq_work);
+
+/*
+ * call_function - called when entering/exiting a call function interrupt
+ * vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(call_function);
+
+/*
+ * call_function_single - called when entering/exiting a call function
+ * single interrupt vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(call_function_single);
+
+/*
+ * threshold_apic - called when entering/exiting a threshold apic interrupt
+ * vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(threshold_apic);
+
+/*
+ * thermal_apic - called when entering/exiting a thermal apic interrupt
+ * vector handler
+ */
+DEFINE_IRQ_VECTOR_EVENT(thermal_apic);
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE irq_vectors
+#endif /*  _TRACE_IRQ_VECTORS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 142810c457dc5f91d90668480babd95d8a03f9b3..4f7923dd00079d0a582cb5467e05e43774001c44 100644 (file)
@@ -235,7 +235,7 @@ extern long __copy_user_nocache(void *dst, const void __user *src,
 static inline int
 __copy_from_user_nocache(void *dst, const void __user *src, unsigned size)
 {
-       might_sleep();
+       might_fault();
        return __copy_user_nocache(dst, src, size, 1);
 }
 
index a06983cdc125d842c58ca13dfc6817282413ee54..0b46ef261c7755837d770832489e6a6c090fc0ac 100644 (file)
@@ -731,6 +731,9 @@ static inline void bau_cpubits_clear(struct bau_local_cpumask *dstp, int nbits)
 }
 
 extern void uv_bau_message_intr1(void);
+#ifdef CONFIG_TRACING
+#define trace_uv_bau_message_intr1 uv_bau_message_intr1
+#endif
 extern void uv_bau_timeout_intr1(void);
 
 struct atomic_short {
index 2af848dfa75424b7798924dd9a91524af7f088e3..bb0465090ae53eb3246b5022d187dd4517bd39d0 100644 (file)
 #define MSR_KNC_EVNTSEL0               0x00000028
 #define MSR_KNC_EVNTSEL1               0x00000029
 
+/* Alternative perfctr range with full access. */
+#define MSR_IA32_PMC0                  0x000004c1
+
 /* AMD64 MSRs. Not complete. See the architecture manual for a more
    complete list. */
 
index 54991a746043853b187e062cf3c53a2f4f411054..180a0c3c224db00e67d91434784b7a217cd45de9 100644 (file)
 #define _UAPI_ASM_X86_PROCESSOR_FLAGS_H
 /* Various flags defined: can be included from assembler. */
 
+#include <linux/const.h>
+
 /*
  * EFLAGS bits
  */
-#define X86_EFLAGS_CF  0x00000001 /* Carry Flag */
-#define X86_EFLAGS_BIT1        0x00000002 /* Bit 1 - always on */
-#define X86_EFLAGS_PF  0x00000004 /* Parity Flag */
-#define X86_EFLAGS_AF  0x00000010 /* Auxiliary carry Flag */
-#define X86_EFLAGS_ZF  0x00000040 /* Zero Flag */
-#define X86_EFLAGS_SF  0x00000080 /* Sign Flag */
-#define X86_EFLAGS_TF  0x00000100 /* Trap Flag */
-#define X86_EFLAGS_IF  0x00000200 /* Interrupt Flag */
-#define X86_EFLAGS_DF  0x00000400 /* Direction Flag */
-#define X86_EFLAGS_OF  0x00000800 /* Overflow Flag */
-#define X86_EFLAGS_IOPL        0x00003000 /* IOPL mask */
-#define X86_EFLAGS_NT  0x00004000 /* Nested Task */
-#define X86_EFLAGS_RF  0x00010000 /* Resume Flag */
-#define X86_EFLAGS_VM  0x00020000 /* Virtual Mode */
-#define X86_EFLAGS_AC  0x00040000 /* Alignment Check */
-#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
-#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
-#define X86_EFLAGS_ID  0x00200000 /* CPUID detection flag */
+#define X86_EFLAGS_CF_BIT      0 /* Carry Flag */
+#define X86_EFLAGS_CF          _BITUL(X86_EFLAGS_CF_BIT)
+#define X86_EFLAGS_FIXED_BIT   1 /* Bit 1 - always on */
+#define X86_EFLAGS_FIXED       _BITUL(X86_EFLAGS_FIXED_BIT)
+#define X86_EFLAGS_PF_BIT      2 /* Parity Flag */
+#define X86_EFLAGS_PF          _BITUL(X86_EFLAGS_PF_BIT)
+#define X86_EFLAGS_AF_BIT      4 /* Auxiliary carry Flag */
+#define X86_EFLAGS_AF          _BITUL(X86_EFLAGS_AF_BIT)
+#define X86_EFLAGS_ZF_BIT      6 /* Zero Flag */
+#define X86_EFLAGS_ZF          _BITUL(X86_EFLAGS_ZF_BIT)
+#define X86_EFLAGS_SF_BIT      7 /* Sign Flag */
+#define X86_EFLAGS_SF          _BITUL(X86_EFLAGS_SF_BIT)
+#define X86_EFLAGS_TF_BIT      8 /* Trap Flag */
+#define X86_EFLAGS_TF          _BITUL(X86_EFLAGS_TF_BIT)
+#define X86_EFLAGS_IF_BIT      9 /* Interrupt Flag */
+#define X86_EFLAGS_IF          _BITUL(X86_EFLAGS_IF_BIT)
+#define X86_EFLAGS_DF_BIT      10 /* Direction Flag */
+#define X86_EFLAGS_DF          _BITUL(X86_EFLAGS_DF_BIT)
+#define X86_EFLAGS_OF_BIT      11 /* Overflow Flag */
+#define X86_EFLAGS_OF          _BITUL(X86_EFLAGS_OF_BIT)
+#define X86_EFLAGS_IOPL_BIT    12 /* I/O Privilege Level (2 bits) */
+#define X86_EFLAGS_IOPL                (_AC(3,UL) << X86_EFLAGS_IOPL_BIT)
+#define X86_EFLAGS_NT_BIT      14 /* Nested Task */
+#define X86_EFLAGS_NT          _BITUL(X86_EFLAGS_NT_BIT)
+#define X86_EFLAGS_RF_BIT      16 /* Resume Flag */
+#define X86_EFLAGS_RF          _BITUL(X86_EFLAGS_RF_BIT)
+#define X86_EFLAGS_VM_BIT      17 /* Virtual Mode */
+#define X86_EFLAGS_VM          _BITUL(X86_EFLAGS_VM_BIT)
+#define X86_EFLAGS_AC_BIT      18 /* Alignment Check/Access Control */
+#define X86_EFLAGS_AC          _BITUL(X86_EFLAGS_AC_BIT)
+#define X86_EFLAGS_AC_BIT      18 /* Alignment Check/Access Control */
+#define X86_EFLAGS_AC          _BITUL(X86_EFLAGS_AC_BIT)
+#define X86_EFLAGS_VIF_BIT     19 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIF         _BITUL(X86_EFLAGS_VIF_BIT)
+#define X86_EFLAGS_VIP_BIT     20 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_VIP         _BITUL(X86_EFLAGS_VIP_BIT)
+#define X86_EFLAGS_ID_BIT      21 /* CPUID detection */
+#define X86_EFLAGS_ID          _BITUL(X86_EFLAGS_ID_BIT)
 
 /*
  * Basic CPU control in CR0
  */
-#define X86_CR0_PE     0x00000001 /* Protection Enable */
-#define X86_CR0_MP     0x00000002 /* Monitor Coprocessor */
-#define X86_CR0_EM     0x00000004 /* Emulation */
-#define X86_CR0_TS     0x00000008 /* Task Switched */
-#define X86_CR0_ET     0x00000010 /* Extension Type */
-#define X86_CR0_NE     0x00000020 /* Numeric Error */
-#define X86_CR0_WP     0x00010000 /* Write Protect */
-#define X86_CR0_AM     0x00040000 /* Alignment Mask */
-#define X86_CR0_NW     0x20000000 /* Not Write-through */
-#define X86_CR0_CD     0x40000000 /* Cache Disable */
-#define X86_CR0_PG     0x80000000 /* Paging */
+#define X86_CR0_PE_BIT         0 /* Protection Enable */
+#define X86_CR0_PE             _BITUL(X86_CR0_PE_BIT)
+#define X86_CR0_MP_BIT         1 /* Monitor Coprocessor */
+#define X86_CR0_MP             _BITUL(X86_CR0_MP_BIT)
+#define X86_CR0_EM_BIT         2 /* Emulation */
+#define X86_CR0_EM             _BITUL(X86_CR0_EM_BIT)
+#define X86_CR0_TS_BIT         3 /* Task Switched */
+#define X86_CR0_TS             _BITUL(X86_CR0_TS_BIT)
+#define X86_CR0_ET_BIT         4 /* Extension Type */
+#define X86_CR0_ET             _BITUL(X86_CR0_ET_BIT)
+#define X86_CR0_NE_BIT         5 /* Numeric Error */
+#define X86_CR0_NE             _BITUL(X86_CR0_NE_BIT)
+#define X86_CR0_WP_BIT         16 /* Write Protect */
+#define X86_CR0_WP             _BITUL(X86_CR0_WP_BIT)
+#define X86_CR0_AM_BIT         18 /* Alignment Mask */
+#define X86_CR0_AM             _BITUL(X86_CR0_AM_BIT)
+#define X86_CR0_NW_BIT         29 /* Not Write-through */
+#define X86_CR0_NW             _BITUL(X86_CR0_NW_BIT)
+#define X86_CR0_CD_BIT         30 /* Cache Disable */
+#define X86_CR0_CD             _BITUL(X86_CR0_CD_BIT)
+#define X86_CR0_PG_BIT         31 /* Paging */
+#define X86_CR0_PG             _BITUL(X86_CR0_PG_BIT)
 
 /*
  * Paging options in CR3
  */
-#define X86_CR3_PWT    0x00000008 /* Page Write Through */
-#define X86_CR3_PCD    0x00000010 /* Page Cache Disable */
-#define X86_CR3_PCID_MASK 0x00000fff /* PCID Mask */
+#define X86_CR3_PWT_BIT                3 /* Page Write Through */
+#define X86_CR3_PWT            _BITUL(X86_CR3_PWT_BIT)
+#define X86_CR3_PCD_BIT                4 /* Page Cache Disable */
+#define X86_CR3_PCD            _BITUL(X86_CR3_PCD_BIT)
+#define X86_CR3_PCID_MASK      _AC(0x00000fff,UL) /* PCID Mask */
 
 /*
  * Intel CPU features in CR4
  */
-#define X86_CR4_VME    0x00000001 /* enable vm86 extensions */
-#define X86_CR4_PVI    0x00000002 /* virtual interrupts flag enable */
-#define X86_CR4_TSD    0x00000004 /* disable time stamp at ipl 3 */
-#define X86_CR4_DE     0x00000008 /* enable debugging extensions */
-#define X86_CR4_PSE    0x00000010 /* enable page size extensions */
-#define X86_CR4_PAE    0x00000020 /* enable physical address extensions */
-#define X86_CR4_MCE    0x00000040 /* Machine check enable */
-#define X86_CR4_PGE    0x00000080 /* enable global pages */
-#define X86_CR4_PCE    0x00000100 /* enable performance counters at ipl 3 */
-#define X86_CR4_OSFXSR 0x00000200 /* enable fast FPU save and restore */
-#define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */
-#define X86_CR4_VMXE   0x00002000 /* enable VMX virtualization */
-#define X86_CR4_RDWRGSFS 0x00010000 /* enable RDWRGSFS support */
-#define X86_CR4_PCIDE  0x00020000 /* enable PCID support */
-#define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */
-#define X86_CR4_SMEP   0x00100000 /* enable SMEP support */
-#define X86_CR4_SMAP   0x00200000 /* enable SMAP support */
+#define X86_CR4_VME_BIT                0 /* enable vm86 extensions */
+#define X86_CR4_VME            _BITUL(X86_CR4_VME_BIT)
+#define X86_CR4_PVI_BIT                1 /* virtual interrupts flag enable */
+#define X86_CR4_PVI            _BITUL(X86_CR4_PVI_BIT)
+#define X86_CR4_TSD_BIT                2 /* disable time stamp at ipl 3 */
+#define X86_CR4_TSD            _BITUL(X86_CR4_TSD_BIT)
+#define X86_CR4_DE_BIT         3 /* enable debugging extensions */
+#define X86_CR4_DE             _BITUL(X86_CR4_DE_BIT)
+#define X86_CR4_PSE_BIT                4 /* enable page size extensions */
+#define X86_CR4_PSE            _BITUL(X86_CR4_PSE_BIT)
+#define X86_CR4_PAE_BIT                5 /* enable physical address extensions */
+#define X86_CR4_PAE            _BITUL(X86_CR4_PAE_BIT)
+#define X86_CR4_MCE_BIT                6 /* Machine check enable */
+#define X86_CR4_MCE            _BITUL(X86_CR4_MCE_BIT)
+#define X86_CR4_PGE_BIT                7 /* enable global pages */
+#define X86_CR4_PGE            _BITUL(X86_CR4_PGE_BIT)
+#define X86_CR4_PCE_BIT                8 /* enable performance counters at ipl 3 */
+#define X86_CR4_PCE            _BITUL(X86_CR4_PCE_BIT)
+#define X86_CR4_OSFXSR_BIT     9 /* enable fast FPU save and restore */
+#define X86_CR4_OSFXSR         _BITUL(X86_CR4_OSFXSR_BIT)
+#define X86_CR4_OSXMMEXCPT_BIT 10 /* enable unmasked SSE exceptions */
+#define X86_CR4_OSXMMEXCPT     _BITUL(X86_CR4_OSXMMEXCPT_BIT)
+#define X86_CR4_VMXE_BIT       13 /* enable VMX virtualization */
+#define X86_CR4_VMXE           _BITUL(X86_CR4_VMXE_BIT)
+#define X86_CR4_SMXE_BIT       14 /* enable safer mode (TXT) */
+#define X86_CR4_SMXE           _BITUL(X86_CR4_SMXE_BIT)
+#define X86_CR4_FSGSBASE_BIT   16 /* enable RDWRFSGS support */
+#define X86_CR4_FSGSBASE       _BITUL(X86_CR4_FSGSBASE_BIT)
+#define X86_CR4_PCIDE_BIT      17 /* enable PCID support */
+#define X86_CR4_PCIDE          _BITUL(X86_CR4_PCIDE_BIT)
+#define X86_CR4_OSXSAVE_BIT    18 /* enable xsave and xrestore */
+#define X86_CR4_OSXSAVE                _BITUL(X86_CR4_OSXSAVE_BIT)
+#define X86_CR4_SMEP_BIT       20 /* enable SMEP support */
+#define X86_CR4_SMEP           _BITUL(X86_CR4_SMEP_BIT)
+#define X86_CR4_SMAP_BIT       21 /* enable SMAP support */
+#define X86_CR4_SMAP           _BITUL(X86_CR4_SMAP_BIT)
 
 /*
  * x86-64 Task Priority Register, CR8
  */
-#define X86_CR8_TPR    0x0000000F /* task priority register */
+#define X86_CR8_TPR            _AC(0x0000000f,UL) /* task priority register */
 
 /*
  * AMD and Transmeta use MSRs for configuration; see <asm/msr-index.h>
index 7bd3bd31010623367c540755d1dcf3ba0186bdf9..88d99ea77723f768385c602e98fa9a5a1ed58e1c 100644 (file)
@@ -16,6 +16,8 @@ CFLAGS_REMOVE_ftrace.o = -pg
 CFLAGS_REMOVE_early_printk.o = -pg
 endif
 
+CFLAGS_irq.o := -I$(src)/../include/asm/trace
+
 obj-y                  := process_$(BITS).o signal.o entry_$(BITS).o
 obj-y                  += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y                  += time.o ioport.o ldt.o dumpstack.o nmi.o
@@ -67,7 +69,7 @@ obj-$(CONFIG_KEXEC)           += relocate_kernel_$(BITS).o crash.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump_$(BITS).o
 obj-y                          += kprobes/
 obj-$(CONFIG_MODULES)          += module.o
-obj-$(CONFIG_DOUBLEFAULT)      += doublefault_32.o
+obj-$(CONFIG_DOUBLEFAULT)      += doublefault.o
 obj-$(CONFIG_KGDB)             += kgdb.o
 obj-$(CONFIG_VM86)             += vm86_32.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
@@ -93,6 +95,7 @@ obj-$(CONFIG_MICROCODE_INTEL_LIB)     += microcode_intel_lib.o
 microcode-y                            := microcode_core.o
 microcode-$(CONFIG_MICROCODE_INTEL)    += microcode_intel.o
 microcode-$(CONFIG_MICROCODE_AMD)      += microcode_amd.o
+obj-$(CONFIG_MICROCODE_AMD_EARLY)      += microcode_amd_early.o
 obj-$(CONFIG_MICROCODE)                        += microcode.o
 
 obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
@@ -102,6 +105,7 @@ obj-$(CONFIG_OF)                    += devicetree.o
 obj-$(CONFIG_UPROBES)                  += uprobes.o
 
 obj-$(CONFIG_PERF_EVENTS)              += perf_regs.o
+obj-$(CONFIG_TRACING)                  += tracepoint.o
 
 ###
 # 64 bit specific files
index 230c8ea878e5f41ce3f63d2be6a4490759e46b49..d81a972dd506f24059bcaa19a5259ca9ff908ede 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/mpspec.h>
 #include <asm/smp.h>
 
+#include "sleep.h" /* To include x86_acpi_suspend_lowlevel */
 static int __initdata acpi_force = 0;
 u32 acpi_rsdt_forced;
 int acpi_disabled;
@@ -559,6 +560,12 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
 int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
                           int trigger, int polarity) = acpi_register_gsi_pic;
 
+#ifdef CONFIG_ACPI_SLEEP
+int (*acpi_suspend_lowlevel)(void) = x86_acpi_suspend_lowlevel;
+#else
+int (*acpi_suspend_lowlevel)(void);
+#endif
+
 /*
  * success: return IRQ number (>=0)
  * failure: return < 0
index b44577bc97449c14af7988e18a14b4b9c31cc262..2a34aaf3c8f139ff8bd35f702b7431ff75895c9c 100644 (file)
@@ -26,12 +26,12 @@ static char temp_stack[4096];
 #endif
 
 /**
- * acpi_suspend_lowlevel - save kernel state
+ * x86_acpi_suspend_lowlevel - save kernel state
  *
  * Create an identity mapped page table and copy the wakeup routine to
  * low memory.
  */
-int acpi_suspend_lowlevel(void)
+int x86_acpi_suspend_lowlevel(void)
 {
        struct wakeup_header *header =
                (struct wakeup_header *) __va(real_mode_header->wakeup_header);
index 67f59f8c695651977e45d88e15bc66781777f31c..c9c2c982d5e4e168a20a3a2e8fb98bbabf1860e0 100644 (file)
@@ -15,3 +15,5 @@ extern unsigned long acpi_copy_wakeup_routine(unsigned long);
 extern void wakeup_long64(void);
 
 extern void do_suspend_lowlevel(void);
+
+extern int x86_acpi_suspend_lowlevel(void);
index 904611bf0e5a3edf7e7069c42795104275cb0a3b..99663b59123a0066fe42a427bb2a2cb51b8b8a55 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/smp.h>
 #include <linux/mm.h>
 
+#include <asm/trace/irq_vectors.h>
 #include <asm/irq_remapping.h>
 #include <asm/perf_event.h>
 #include <asm/x86_init.h>
@@ -919,17 +920,35 @@ void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs)
        /*
         * NOTE! We'd better ACK the irq immediately,
         * because timer handling can be slow.
+        *
+        * update_process_times() expects us to have done irq_enter().
+        * Besides, if we don't timer interrupts ignore the global
+        * interrupt lock, which is the WrongThing (tm) to do.
         */
-       ack_APIC_irq();
+       entering_ack_irq();
+       local_apic_timer_interrupt();
+       exiting_irq();
+
+       set_irq_regs(old_regs);
+}
+
+void __irq_entry smp_trace_apic_timer_interrupt(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
+
        /*
+        * NOTE! We'd better ACK the irq immediately,
+        * because timer handling can be slow.
+        *
         * update_process_times() expects us to have done irq_enter().
         * Besides, if we don't timer interrupts ignore the global
         * interrupt lock, which is the WrongThing (tm) to do.
         */
-       irq_enter();
-       exit_idle();
+       entering_ack_irq();
+       trace_local_timer_entry(LOCAL_TIMER_VECTOR);
        local_apic_timer_interrupt();
-       irq_exit();
+       trace_local_timer_exit(LOCAL_TIMER_VECTOR);
+       exiting_irq();
 
        set_irq_regs(old_regs);
 }
@@ -1907,12 +1926,10 @@ int __init APIC_init_uniprocessor(void)
 /*
  * This interrupt should _never_ happen with our APIC/SMP architecture
  */
-void smp_spurious_interrupt(struct pt_regs *regs)
+static inline void __smp_spurious_interrupt(void)
 {
        u32 v;
 
-       irq_enter();
-       exit_idle();
        /*
         * Check if this really is a spurious interrupt and ACK it
         * if it is a vectored one.  Just in case...
@@ -1927,13 +1944,28 @@ void smp_spurious_interrupt(struct pt_regs *regs)
        /* see sw-dev-man vol 3, chapter 7.4.13.5 */
        pr_info("spurious APIC interrupt on CPU#%d, "
                "should never happen.\n", smp_processor_id());
-       irq_exit();
+}
+
+void smp_spurious_interrupt(struct pt_regs *regs)
+{
+       entering_irq();
+       __smp_spurious_interrupt();
+       exiting_irq();
+}
+
+void smp_trace_spurious_interrupt(struct pt_regs *regs)
+{
+       entering_irq();
+       trace_spurious_apic_entry(SPURIOUS_APIC_VECTOR);
+       __smp_spurious_interrupt();
+       trace_spurious_apic_exit(SPURIOUS_APIC_VECTOR);
+       exiting_irq();
 }
 
 /*
  * This interrupt should never happen with our APIC/SMP architecture
  */
-void smp_error_interrupt(struct pt_regs *regs)
+static inline void __smp_error_interrupt(struct pt_regs *regs)
 {
        u32 v0, v1;
        u32 i = 0;
@@ -1948,8 +1980,6 @@ void smp_error_interrupt(struct pt_regs *regs)
                "Illegal register address",     /* APIC Error Bit 7 */
        };
 
-       irq_enter();
-       exit_idle();
        /* First tickle the hardware, only then report what went on. -- REW */
        v0 = apic_read(APIC_ESR);
        apic_write(APIC_ESR, 0);
@@ -1970,7 +2000,22 @@ void smp_error_interrupt(struct pt_regs *regs)
 
        apic_printk(APIC_DEBUG, KERN_CONT "\n");
 
-       irq_exit();
+}
+
+void smp_error_interrupt(struct pt_regs *regs)
+{
+       entering_irq();
+       __smp_error_interrupt(regs);
+       exiting_irq();
+}
+
+void smp_trace_error_interrupt(struct pt_regs *regs)
+{
+       entering_irq();
+       trace_error_apic_entry(ERROR_APIC_VECTOR);
+       __smp_error_interrupt(regs);
+       trace_error_apic_exit(ERROR_APIC_VECTOR);
+       exiting_irq();
 }
 
 /**
@@ -2302,7 +2347,7 @@ 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_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
+#if defined(CONFIG_X86_MCE_INTEL)
        if (maxlvt >= 5)
                apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
 #endif
index 794f6eb54cd3bf6f55093819a938c7dc91448b0e..39cc7f7acab3f58fd3e25d524be55b16f7b766e4 100644 (file)
@@ -51,6 +51,8 @@ DEFINE_PER_CPU(int, x2apic_extra_bits);
 
 static enum uv_system_type uv_system_type;
 static u64 gru_start_paddr, gru_end_paddr;
+static u64 gru_dist_base, gru_first_node_paddr = -1LL, gru_last_node_paddr;
+static u64 gru_dist_lmask, gru_dist_umask;
 static union uvh_apicid uvh_apicid;
 int uv_min_hub_revision_id;
 EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
@@ -72,7 +74,20 @@ static unsigned long __init uv_early_read_mmr(unsigned long addr)
 
 static inline bool is_GRU_range(u64 start, u64 end)
 {
-       return start >= gru_start_paddr && end <= gru_end_paddr;
+       if (gru_dist_base) {
+               u64 su = start & gru_dist_umask; /* upper (incl pnode) bits */
+               u64 sl = start & gru_dist_lmask; /* base offset bits */
+               u64 eu = end & gru_dist_umask;
+               u64 el = end & gru_dist_lmask;
+
+               /* Must reside completely within a single GRU range */
+               return (sl == gru_dist_base && el == gru_dist_base &&
+                       su >= gru_first_node_paddr &&
+                       su <= gru_last_node_paddr &&
+                       eu == su);
+       } else {
+               return start >= gru_start_paddr && end <= gru_end_paddr;
+       }
 }
 
 static bool uv_is_untracked_pat_range(u64 start, u64 end)
@@ -463,26 +478,63 @@ static __init void map_high(char *id, unsigned long base, int pshift,
                pr_info("UV: Map %s_HI base address NULL\n", id);
                return;
        }
-       pr_info("UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, paddr + bytes);
+       pr_debug("UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, paddr + bytes);
        if (map_type == map_uc)
                init_extra_mapping_uc(paddr, bytes);
        else
                init_extra_mapping_wb(paddr, bytes);
 }
 
+static __init void map_gru_distributed(unsigned long c)
+{
+       union uvh_rh_gam_gru_overlay_config_mmr_u gru;
+       u64 paddr;
+       unsigned long bytes;
+       int nid;
+
+       gru.v = c;
+       /* only base bits 42:28 relevant in dist mode */
+       gru_dist_base = gru.v & 0x000007fff0000000UL;
+       if (!gru_dist_base) {
+               pr_info("UV: Map GRU_DIST base address NULL\n");
+               return;
+       }
+       bytes = 1UL << UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT;
+       gru_dist_lmask = ((1UL << uv_hub_info->m_val) - 1) & ~(bytes - 1);
+       gru_dist_umask = ~((1UL << uv_hub_info->m_val) - 1);
+       gru_dist_base &= gru_dist_lmask; /* Clear bits above M */
+       for_each_online_node(nid) {
+               paddr = ((u64)uv_node_to_pnode(nid) << uv_hub_info->m_val) |
+                               gru_dist_base;
+               init_extra_mapping_wb(paddr, bytes);
+               gru_first_node_paddr = min(paddr, gru_first_node_paddr);
+               gru_last_node_paddr = max(paddr, gru_last_node_paddr);
+       }
+       /* Save upper (63:M) bits of address only for is_GRU_range */
+       gru_first_node_paddr &= gru_dist_umask;
+       gru_last_node_paddr &= gru_dist_umask;
+       pr_debug("UV: Map GRU_DIST base 0x%016llx  0x%016llx - 0x%016llx\n",
+               gru_dist_base, gru_first_node_paddr, gru_last_node_paddr);
+}
+
 static __init void map_gru_high(int max_pnode)
 {
        union uvh_rh_gam_gru_overlay_config_mmr_u gru;
        int shift = UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT;
 
        gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
-       if (gru.s.enable) {
-               map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb);
-               gru_start_paddr = ((u64)gru.s.base << shift);
-               gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1);
-       } else {
+       if (!gru.s.enable) {
                pr_info("UV: GRU disabled\n");
+               return;
+       }
+
+       if (is_uv3_hub() && gru.s3.mode) {
+               map_gru_distributed(gru.v);
+               return;
        }
+       map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb);
+       gru_start_paddr = ((u64)gru.s.base << shift);
+       gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1);
 }
 
 static __init void map_mmr_high(int max_pnode)
index 0ef4bba2acb75d8bdade42a54cec79ad8673d09a..d67c4be3e8b1e24ec845ecdb4c5de615523cf066 100644 (file)
@@ -28,7 +28,6 @@ void foo(void)
        OFFSET(CPUINFO_x86_vendor, cpuinfo_x86, x86_vendor);
        OFFSET(CPUINFO_x86_model, cpuinfo_x86, x86_model);
        OFFSET(CPUINFO_x86_mask, cpuinfo_x86, x86_mask);
-       OFFSET(CPUINFO_hard_math, cpuinfo_x86, hard_math);
        OFFSET(CPUINFO_cpuid_level, cpuinfo_x86, cpuid_level);
        OFFSET(CPUINFO_x86_capability, cpuinfo_x86, x86_capability);
        OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id);
index b0684e4a73aa60ae8edee4d3b729de2b663b079c..47b56a7e99cbcf2e4387fd087cddbfb1c35060bc 100644 (file)
@@ -31,11 +31,15 @@ obj-$(CONFIG_PERF_EVENTS)           += perf_event.o
 
 ifdef CONFIG_PERF_EVENTS
 obj-$(CONFIG_CPU_SUP_AMD)              += perf_event_amd.o perf_event_amd_uncore.o
+ifdef CONFIG_AMD_IOMMU
+obj-$(CONFIG_CPU_SUP_AMD)              += perf_event_amd_iommu.o
+endif
 obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_p6.o perf_event_knc.o perf_event_p4.o
 obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o
 obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_uncore.o
 endif
 
+
 obj-$(CONFIG_X86_MCE)                  += mcheck/
 obj-$(CONFIG_MTRR)                     += mtrr/
 
index 5013a48d1aff7a2f859a4d2e28224d1da4d95ea4..c587a8757227b2b5297e1d5607218a2d96802608 100644 (file)
@@ -90,7 +90,7 @@ static void __cpuinit init_amd_k5(struct cpuinfo_x86 *c)
 static void __cpuinit init_amd_k6(struct cpuinfo_x86 *c)
 {
        u32 l, h;
-       int mbytes = num_physpages >> (20-PAGE_SHIFT);
+       int mbytes = get_num_physpages() >> (20-PAGE_SHIFT);
 
        if (c->x86_model < 6) {
                /* Based on AMD doc 20734R - June 2000 */
index 4112be9a46591209aae8169506f11e4eaf28fe7a..03445346ee0aae247f31ebf2aef6a48be0dfce8a 100644 (file)
 #include <asm/paravirt.h>
 #include <asm/alternative.h>
 
-static int __init no_387(char *s)
-{
-       boot_cpu_data.hard_math = 0;
-       write_cr0(X86_CR0_TS | X86_CR0_EM | X86_CR0_MP | read_cr0());
-       return 1;
-}
-
-__setup("no387", no_387);
-
 static double __initdata x = 4195835.0;
 static double __initdata y = 3145727.0;
 
@@ -44,15 +35,6 @@ static void __init check_fpu(void)
 {
        s32 fdiv_bug;
 
-       if (!boot_cpu_data.hard_math) {
-#ifndef CONFIG_MATH_EMULATION
-               pr_emerg("No coprocessor found and no math emulation present\n");
-               pr_emerg("Giving up\n");
-               for (;;) ;
-#endif
-               return;
-       }
-
        kernel_fpu_begin();
 
        /*
@@ -107,5 +89,6 @@ void __init check_bugs(void)
         * kernel_fpu_begin/end() in check_fpu() relies on the patched
         * alternative instructions.
         */
-       check_fpu();
+       if (cpu_has_fpu)
+               check_fpu();
 }
index 22018f70a6716e2f57012378c19df770ba607ca0..548bd039784e631570a7628137d16cb8213ec411 100644 (file)
@@ -711,10 +711,9 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
                return;
 
        cpu_detect(c);
-
        get_cpu_vendor(c);
-
        get_cpu_cap(c);
+       fpu_detect(c);
 
        if (this_cpu->c_early_init)
                this_cpu->c_early_init(c);
@@ -724,6 +723,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 
        if (this_cpu->c_bsp_init)
                this_cpu->c_bsp_init(c);
+
+       setup_force_cpu_cap(X86_FEATURE_ALWAYS);
 }
 
 void __init early_cpu_init(void)
@@ -1071,8 +1072,8 @@ __setup("clearcpuid=", setup_disablecpuid);
 
 #ifdef CONFIG_X86_64
 struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table };
-struct desc_ptr nmi_idt_descr = { NR_VECTORS * 16 - 1,
-                                   (unsigned long) nmi_idt_table };
+struct desc_ptr debug_idt_descr = { NR_VECTORS * 16 - 1,
+                                   (unsigned long) debug_idt_table };
 
 DEFINE_PER_CPU_FIRST(union irq_stack_union,
                     irq_stack_union) __aligned(PAGE_SIZE);
@@ -1148,20 +1149,20 @@ int is_debug_stack(unsigned long addr)
                 addr > (__get_cpu_var(debug_stack_addr) - DEBUG_STKSZ));
 }
 
-static DEFINE_PER_CPU(u32, debug_stack_use_ctr);
+DEFINE_PER_CPU(u32, debug_idt_ctr);
 
 void debug_stack_set_zero(void)
 {
-       this_cpu_inc(debug_stack_use_ctr);
-       load_idt((const struct desc_ptr *)&nmi_idt_descr);
+       this_cpu_inc(debug_idt_ctr);
+       load_current_idt();
 }
 
 void debug_stack_reset(void)
 {
-       if (WARN_ON(!this_cpu_read(debug_stack_use_ctr)))
+       if (WARN_ON(!this_cpu_read(debug_idt_ctr)))
                return;
-       if (this_cpu_dec_return(debug_stack_use_ctr) == 0)
-               load_idt((const struct desc_ptr *)&idt_descr);
+       if (this_cpu_dec_return(debug_idt_ctr) == 0)
+               load_current_idt();
 }
 
 #else  /* CONFIG_X86_64 */
@@ -1257,7 +1258,7 @@ void __cpuinit cpu_init(void)
        switch_to_new_gdt(cpu);
        loadsegment(fs, 0);
 
-       load_idt((const struct desc_ptr *)&idt_descr);
+       load_current_idt();
 
        memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
        syscall_init();
@@ -1334,7 +1335,7 @@ void __cpuinit cpu_init(void)
        if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
                clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
 
-       load_idt(&idt_descr);
+       load_current_idt();
        switch_to_new_gdt(cpu);
 
        /*
@@ -1363,3 +1364,17 @@ void __cpuinit cpu_init(void)
        fpu_init();
 }
 #endif
+
+#ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
+void warn_pre_alternatives(void)
+{
+       WARN(1, "You're using static_cpu_has before alternatives have run!\n");
+}
+EXPORT_SYMBOL_GPL(warn_pre_alternatives);
+#endif
+
+inline bool __static_cpu_has_safe(u16 bit)
+{
+       return boot_cpu_has(bit);
+}
+EXPORT_SYMBOL_GPL(__static_cpu_has_safe);
index d048d5ca43c1c8d04772e11206f5c9a41db9dead..7582f475b1637479e9125843475f326fe05e5f71 100644 (file)
@@ -333,7 +333,7 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
                switch (dir0_lsn) {
                case 0xd:  /* either a 486SLC or DLC w/o DEVID */
                        dir0_msn = 0;
-                       p = Cx486_name[(c->hard_math) ? 1 : 0];
+                       p = Cx486_name[(cpu_has_fpu ? 1 : 0)];
                        break;
 
                case 0xe:  /* a 486S A step */
index 7c6f7d548c0f94d76c094a950f7ef29fc1356b32..8dc72dda66fe0a301a8eb87ab3fd9ac078bd5200 100644 (file)
@@ -618,36 +618,34 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
                 * parameters cpuid leaf to find the cache details
                 */
                for (i = 0; i < num_cache_leaves; i++) {
-                       struct _cpuid4_info_regs this_leaf;
+                       struct _cpuid4_info_regs this_leaf = {};
                        int retval;
 
                        retval = cpuid4_cache_lookup_regs(i, &this_leaf);
-                       if (retval >= 0) {
-                               switch (this_leaf.eax.split.level) {
-                               case 1:
-                                       if (this_leaf.eax.split.type ==
-                                                       CACHE_TYPE_DATA)
-                                               new_l1d = this_leaf.size/1024;
-                                       else if (this_leaf.eax.split.type ==
-                                                       CACHE_TYPE_INST)
-                                               new_l1i = this_leaf.size/1024;
-                                       break;
-                               case 2:
-                                       new_l2 = this_leaf.size/1024;
-                                       num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
-                                       index_msb = get_count_order(num_threads_sharing);
-                                       l2_id = c->apicid & ~((1 << index_msb) - 1);
-                                       break;
-                               case 3:
-                                       new_l3 = this_leaf.size/1024;
-                                       num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
-                                       index_msb = get_count_order(
-                                                       num_threads_sharing);
-                                       l3_id = c->apicid & ~((1 << index_msb) - 1);
-                                       break;
-                               default:
-                                       break;
-                               }
+                       if (retval < 0)
+                               continue;
+
+                       switch (this_leaf.eax.split.level) {
+                       case 1:
+                               if (this_leaf.eax.split.type == CACHE_TYPE_DATA)
+                                       new_l1d = this_leaf.size/1024;
+                               else if (this_leaf.eax.split.type == CACHE_TYPE_INST)
+                                       new_l1i = this_leaf.size/1024;
+                               break;
+                       case 2:
+                               new_l2 = this_leaf.size/1024;
+                               num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
+                               index_msb = get_count_order(num_threads_sharing);
+                               l2_id = c->apicid & ~((1 << index_msb) - 1);
+                               break;
+                       case 3:
+                               new_l3 = this_leaf.size/1024;
+                               num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
+                               index_msb = get_count_order(num_threads_sharing);
+                               l3_id = c->apicid & ~((1 << index_msb) - 1);
+                               break;
+                       default:
+                               break;
                        }
                }
        }
index ddc72f8393321de0ca989d2476f7ccd96eed3639..5ac2d1fb28bc590bd9403aea70d8641d3b05e03b 100644 (file)
@@ -153,7 +153,7 @@ static void raise_mce(struct mce *m)
                return;
 
 #ifdef CONFIG_X86_LOCAL_APIC
-       if (m->inject_flags & (MCJ_IRQ_BRAODCAST | MCJ_NMI_BROADCAST)) {
+       if (m->inject_flags & (MCJ_IRQ_BROADCAST | MCJ_NMI_BROADCAST)) {
                unsigned long start;
                int cpu;
 
@@ -167,7 +167,7 @@ static void raise_mce(struct mce *m)
                                cpumask_clear_cpu(cpu, mce_inject_cpumask);
                }
                if (!cpumask_empty(mce_inject_cpumask)) {
-                       if (m->inject_flags & MCJ_IRQ_BRAODCAST) {
+                       if (m->inject_flags & MCJ_IRQ_BROADCAST) {
                                /*
                                 * don't wait because mce_irq_ipi is necessary
                                 * to be sync with following raise_local
index beb1f1689e5261b1dca299ea3cd442133843ca40..e2703520d1208539d21447d6f570a767b7e51f48 100644 (file)
@@ -110,22 +110,17 @@ static struct severity {
        /* known AR MCACODs: */
 #ifdef CONFIG_MEMORY_FAILURE
        MCESEV(
-               KEEP, "HT thread notices Action required: data load error",
-               SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
-               MCGMASK(MCG_STATUS_EIPV, 0)
+               KEEP, "Action required but unaffected thread is continuable",
+               SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR),
+               MCGMASK(MCG_STATUS_RIPV, MCG_STATUS_RIPV)
                ),
        MCESEV(
-               AR, "Action required: data load error",
+               AR, "Action required: data load error in a user process",
                SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
                USER
                ),
        MCESEV(
-               KEEP, "HT thread notices Action required: instruction fetch error",
-               SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR),
-               MCGMASK(MCG_STATUS_EIPV, 0)
-               ),
-       MCESEV(
-               AR, "Action required: instruction fetch error",
+               AR, "Action required: instruction fetch error in a user process",
                SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR),
                USER
                ),
index 9239504b41cbc6f2564cef5c42c325ebb2c63286..bf49cdbb010f3d519fa7f33eb07ba396877960d5 100644 (file)
@@ -89,7 +89,10 @@ static DECLARE_WAIT_QUEUE_HEAD(mce_chrdev_wait);
 static DEFINE_PER_CPU(struct mce, mces_seen);
 static int                     cpu_missing;
 
-/* MCA banks polled by the period polling timer for corrected events */
+/*
+ * MCA banks polled by the period polling timer for corrected events.
+ * With Intel CMCI, this only has MCA banks which do not support CMCI (if any).
+ */
 DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
        [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
 };
index ae1697c2afe39291da914894f0b036352571ef34..d56405309dc16a3a5deb9798ff2b0656f1afc0e1 100644 (file)
  * Also supports reliable discovery of shared banks.
  */
 
+/*
+ * CMCI can be delivered to multiple cpus that share a machine check bank
+ * so we need to designate a single cpu to process errors logged in each bank
+ * in the interrupt handler (otherwise we would have many races and potential
+ * double reporting of the same error).
+ * Note that this can change when a cpu is offlined or brought online since
+ * some MCA banks are shared across cpus. When a cpu is offlined, cmci_clear()
+ * disables CMCI on all banks owned by the cpu and clears this bitfield. At
+ * this point, cmci_rediscover() kicks in and a different cpu may end up
+ * taking ownership of some of the shared MCA banks that were previously
+ * owned by the offlined cpu.
+ */
 static DEFINE_PER_CPU(mce_banks_t, mce_banks_owned);
 
 /*
index 47a1870279aadc5607171737c0df7c3f54d2b25f..98f2083832ebec3c5b6fe65300603fa1777b3180 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/idle.h>
 #include <asm/mce.h>
 #include <asm/msr.h>
+#include <asm/trace/irq_vectors.h>
 
 /* How long to wait between reporting thermal events */
 #define CHECK_INTERVAL         (300 * HZ)
@@ -181,11 +182,6 @@ static int therm_throt_process(bool new_event, int event, int level)
                                this_cpu,
                                level == CORE_LEVEL ? "Core" : "Package",
                                state->count);
-               else
-                       printk(KERN_CRIT "CPU%d: %s power limit notification (total events = %lu)\n",
-                               this_cpu,
-                               level == CORE_LEVEL ? "Core" : "Package",
-                               state->count);
                return 1;
        }
        if (old_event) {
@@ -193,10 +189,6 @@ static int therm_throt_process(bool new_event, int event, int level)
                        printk(KERN_INFO "CPU%d: %s temperature/speed normal\n",
                                this_cpu,
                                level == CORE_LEVEL ? "Core" : "Package");
-               else
-                       printk(KERN_INFO "CPU%d: %s power limit normal\n",
-                               this_cpu,
-                               level == CORE_LEVEL ? "Core" : "Package");
                return 1;
        }
 
@@ -219,6 +211,15 @@ static int thresh_event_valid(int event)
        return 1;
 }
 
+static bool int_pln_enable;
+static int __init int_pln_enable_setup(char *s)
+{
+       int_pln_enable = true;
+
+       return 1;
+}
+__setup("int_pln_enable", int_pln_enable_setup);
+
 #ifdef CONFIG_SYSFS
 /* Add/Remove thermal_throttle interface for CPU device: */
 static __cpuinit int thermal_throttle_add_dev(struct device *dev,
@@ -231,7 +232,7 @@ static __cpuinit int thermal_throttle_add_dev(struct device *dev,
        if (err)
                return err;
 
-       if (cpu_has(c, X86_FEATURE_PLN))
+       if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
                err = sysfs_add_file_to_group(&dev->kobj,
                                              &dev_attr_core_power_limit_count.attr,
                                              thermal_attr_group.name);
@@ -239,7 +240,7 @@ static __cpuinit int thermal_throttle_add_dev(struct device *dev,
                err = sysfs_add_file_to_group(&dev->kobj,
                                              &dev_attr_package_throttle_count.attr,
                                              thermal_attr_group.name);
-               if (cpu_has(c, X86_FEATURE_PLN))
+               if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
                        err = sysfs_add_file_to_group(&dev->kobj,
                                        &dev_attr_package_power_limit_count.attr,
                                        thermal_attr_group.name);
@@ -352,7 +353,7 @@ static void intel_thermal_interrupt(void)
                                CORE_LEVEL) != 0)
                mce_log_therm_throt_event(msr_val);
 
-       if (this_cpu_has(X86_FEATURE_PLN))
+       if (this_cpu_has(X86_FEATURE_PLN) && int_pln_enable)
                therm_throt_process(msr_val & THERM_STATUS_POWER_LIMIT,
                                        POWER_LIMIT_EVENT,
                                        CORE_LEVEL);
@@ -362,7 +363,7 @@ static void intel_thermal_interrupt(void)
                therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
                                        THERMAL_THROTTLING_EVENT,
                                        PACKAGE_LEVEL);
-               if (this_cpu_has(X86_FEATURE_PLN))
+               if (this_cpu_has(X86_FEATURE_PLN) && int_pln_enable)
                        therm_throt_process(msr_val &
                                        PACKAGE_THERM_STATUS_POWER_LIMIT,
                                        POWER_LIMIT_EVENT,
@@ -378,15 +379,26 @@ static void unexpected_thermal_interrupt(void)
 
 static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt;
 
-asmlinkage void smp_thermal_interrupt(struct pt_regs *regs)
+static inline void __smp_thermal_interrupt(void)
 {
-       irq_enter();
-       exit_idle();
        inc_irq_stat(irq_thermal_count);
        smp_thermal_vector();
-       irq_exit();
-       /* Ack only at the end to avoid potential reentry */
-       ack_APIC_irq();
+}
+
+asmlinkage void smp_thermal_interrupt(struct pt_regs *regs)
+{
+       entering_irq();
+       __smp_thermal_interrupt();
+       exiting_ack_irq();
+}
+
+asmlinkage void smp_trace_thermal_interrupt(struct pt_regs *regs)
+{
+       entering_irq();
+       trace_thermal_apic_entry(THERMAL_APIC_VECTOR);
+       __smp_thermal_interrupt();
+       trace_thermal_apic_exit(THERMAL_APIC_VECTOR);
+       exiting_ack_irq();
 }
 
 /* Thermal monitoring depends on APIC, ACPI and clock modulation */
@@ -470,9 +482,13 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
        apic_write(APIC_LVTTHMR, h);
 
        rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
-       if (cpu_has(c, X86_FEATURE_PLN))
+       if (cpu_has(c, X86_FEATURE_PLN) && !int_pln_enable)
+               wrmsr(MSR_IA32_THERM_INTERRUPT,
+                       (l | (THERM_INT_LOW_ENABLE
+                       | THERM_INT_HIGH_ENABLE)) & ~THERM_INT_PLN_ENABLE, h);
+       else if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
                wrmsr(MSR_IA32_THERM_INTERRUPT,
-                     l | (THERM_INT_LOW_ENABLE
+                       l | (THERM_INT_LOW_ENABLE
                        | THERM_INT_HIGH_ENABLE | THERM_INT_PLN_ENABLE), h);
        else
                wrmsr(MSR_IA32_THERM_INTERRUPT,
@@ -480,9 +496,14 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
 
        if (cpu_has(c, X86_FEATURE_PTS)) {
                rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
-               if (cpu_has(c, X86_FEATURE_PLN))
+               if (cpu_has(c, X86_FEATURE_PLN) && !int_pln_enable)
                        wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
-                             l | (PACKAGE_THERM_INT_LOW_ENABLE
+                               (l | (PACKAGE_THERM_INT_LOW_ENABLE
+                               | PACKAGE_THERM_INT_HIGH_ENABLE))
+                               & ~PACKAGE_THERM_INT_PLN_ENABLE, h);
+               else if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
+                       wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
+                               l | (PACKAGE_THERM_INT_LOW_ENABLE
                                | PACKAGE_THERM_INT_HIGH_ENABLE
                                | PACKAGE_THERM_INT_PLN_ENABLE), h);
                else
index aa578cadb9407df3448fb7de5633a92bc2e77562..fe6b1c86645b668758331b78d93ab8c549ab09c2 100644 (file)
@@ -8,6 +8,7 @@
 #include <asm/apic.h>
 #include <asm/idle.h>
 #include <asm/mce.h>
+#include <asm/trace/irq_vectors.h>
 
 static void default_threshold_interrupt(void)
 {
@@ -17,13 +18,24 @@ static void default_threshold_interrupt(void)
 
 void (*mce_threshold_vector)(void) = default_threshold_interrupt;
 
-asmlinkage void smp_threshold_interrupt(void)
+static inline void __smp_threshold_interrupt(void)
 {
-       irq_enter();
-       exit_idle();
        inc_irq_stat(irq_threshold_count);
        mce_threshold_vector();
-       irq_exit();
-       /* Ack only at the end to avoid potential reentry */
-       ack_APIC_irq();
+}
+
+asmlinkage void smp_threshold_interrupt(void)
+{
+       entering_irq();
+       __smp_threshold_interrupt();
+       exiting_ack_irq();
+}
+
+asmlinkage void smp_trace_threshold_interrupt(void)
+{
+       entering_irq();
+       trace_threshold_apic_entry(THRESHOLD_APIC_VECTOR);
+       __smp_threshold_interrupt();
+       trace_threshold_apic_exit(THRESHOLD_APIC_VECTOR);
+       exiting_ack_irq();
 }
index 68a3343e57980a4149a00a4f9d609b69b67eba35..9e451b0876b513ff34c38ba5cad0862b1f5fc3db 100644 (file)
@@ -167,7 +167,7 @@ static void post_set(void)
        setCx86(CX86_CCR3, ccr3);
 
        /* Enable caches */
-       write_cr0(read_cr0() & 0xbfffffff);
+       write_cr0(read_cr0() & ~X86_CR0_CD);
 
        /* Restore value of CR4 */
        if (cpu_has_pge)
index fa72a39e5d463a248a5b5a4a18f7860a1cbb8a77..d4cdfa67509ec266b787ec7a284e04065bb01c60 100644 (file)
@@ -510,8 +510,9 @@ generic_get_free_region(unsigned long base, unsigned long size, int replace_reg)
 static void generic_get_mtrr(unsigned int reg, unsigned long *base,
                             unsigned long *size, mtrr_type *type)
 {
-       unsigned int mask_lo, mask_hi, base_lo, base_hi;
-       unsigned int tmp, hi;
+       u32 mask_lo, mask_hi, base_lo, base_hi;
+       unsigned int hi;
+       u64 tmp, mask;
 
        /*
         * get_mtrr doesn't need to update mtrr_state, also it could be called
@@ -532,18 +533,18 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
        rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);
 
        /* Work out the shifted address mask: */
-       tmp = mask_hi << (32 - PAGE_SHIFT) | mask_lo >> PAGE_SHIFT;
-       mask_lo = size_or_mask | tmp;
+       tmp = (u64)mask_hi << (32 - PAGE_SHIFT) | mask_lo >> PAGE_SHIFT;
+       mask = size_or_mask | tmp;
 
        /* Expand tmp with high bits to all 1s: */
-       hi = fls(tmp);
+       hi = fls64(tmp);
        if (hi > 0) {
-               tmp |= ~((1<<(hi - 1)) - 1);
+               tmp |= ~((1ULL<<(hi - 1)) - 1);
 
-               if (tmp != mask_lo) {
+               if (tmp != mask) {
                        printk(KERN_WARNING "mtrr: your BIOS has configured an incorrect mask, fixing it.\n");
                        add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
-                       mask_lo = tmp;
+                       mask = tmp;
                }
        }
 
@@ -551,8 +552,8 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
         * This works correctly if size is a power of two, i.e. a
         * contiguous range:
         */
-       *size = -mask_lo;
-       *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
+       *size = -mask;
+       *base = (u64)base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
        *type = base_lo & 0xff;
 
 out_put_cpu:
@@ -701,7 +702,7 @@ static void post_set(void) __releases(set_atomicity_lock)
        mtrr_wrmsr(MSR_MTRRdefType, deftype_lo, deftype_hi);
 
        /* Enable caches */
-       write_cr0(read_cr0() & 0xbfffffff);
+       write_cr0(read_cr0() & ~X86_CR0_CD);
 
        /* Restore value of CR4 */
        if (cpu_has_pge)
index 726bf963c2276569c39c67377b64fd7a74fb539e..ca22b73aaa25f8c4d512a62161bf6af92ec0807f 100644 (file)
@@ -305,7 +305,8 @@ int mtrr_add_page(unsigned long base, unsigned long size,
                return -EINVAL;
        }
 
-       if (base & size_or_mask || size & size_or_mask) {
+       if ((base | (base + size - 1)) >>
+           (boot_cpu_data.x86_phys_bits - PAGE_SHIFT)) {
                pr_warning("mtrr: base or size exceeds the MTRR width\n");
                return -EINVAL;
        }
@@ -583,6 +584,7 @@ static struct syscore_ops mtrr_syscore_ops = {
 
 int __initdata changed_by_mtrr_cleanup;
 
+#define SIZE_OR_MASK_BITS(n)  (~((1ULL << ((n) - PAGE_SHIFT)) - 1))
 /**
  * mtrr_bp_init - initialize mtrrs on the boot CPU
  *
@@ -600,7 +602,7 @@ void __init mtrr_bp_init(void)
 
        if (cpu_has_mtrr) {
                mtrr_if = &generic_mtrr_ops;
-               size_or_mask = 0xff000000;                      /* 36 bits */
+               size_or_mask = SIZE_OR_MASK_BITS(36);
                size_and_mask = 0x00f00000;
                phys_addr = 36;
 
@@ -619,7 +621,7 @@ void __init mtrr_bp_init(void)
                             boot_cpu_data.x86_mask == 0x4))
                                phys_addr = 36;
 
-                       size_or_mask = ~((1ULL << (phys_addr - PAGE_SHIFT)) - 1);
+                       size_or_mask = SIZE_OR_MASK_BITS(phys_addr);
                        size_and_mask = ~size_or_mask & 0xfffff00000ULL;
                } else if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR &&
                           boot_cpu_data.x86 == 6) {
@@ -627,7 +629,7 @@ void __init mtrr_bp_init(void)
                         * VIA C* family have Intel style MTRRs,
                         * but don't support PAE
                         */
-                       size_or_mask = 0xfff00000;              /* 32 bits */
+                       size_or_mask = SIZE_OR_MASK_BITS(32);
                        size_and_mask = 0;
                        phys_addr = 32;
                }
@@ -637,21 +639,21 @@ void __init mtrr_bp_init(void)
                        if (cpu_has_k6_mtrr) {
                                /* Pre-Athlon (K6) AMD CPU MTRRs */
                                mtrr_if = mtrr_ops[X86_VENDOR_AMD];
-                               size_or_mask = 0xfff00000;      /* 32 bits */
+                               size_or_mask = SIZE_OR_MASK_BITS(32);
                                size_and_mask = 0;
                        }
                        break;
                case X86_VENDOR_CENTAUR:
                        if (cpu_has_centaur_mcr) {
                                mtrr_if = mtrr_ops[X86_VENDOR_CENTAUR];
-                               size_or_mask = 0xfff00000;      /* 32 bits */
+                               size_or_mask = SIZE_OR_MASK_BITS(32);
                                size_and_mask = 0;
                        }
                        break;
                case X86_VENDOR_CYRIX:
                        if (cpu_has_cyrix_arr) {
                                mtrr_if = mtrr_ops[X86_VENDOR_CYRIX];
-                               size_or_mask = 0xfff00000;      /* 32 bits */
+                               size_or_mask = SIZE_OR_MASK_BITS(32);
                                size_and_mask = 0;
                        }
                        break;
index 1025f3c99d2065167b0b1484fb5410829344b7f1..9e581c5cf6d0db026e524a1dd881abe6cc61e7bb 100644 (file)
@@ -403,7 +403,8 @@ int x86_pmu_hw_config(struct perf_event *event)
                 * check that PEBS LBR correction does not conflict with
                 * whatever the user is asking with attr->branch_sample_type
                 */
-               if (event->attr.precise_ip > 1) {
+               if (event->attr.precise_ip > 1 &&
+                   x86_pmu.intel_cap.pebs_format < 2) {
                        u64 *br_type = &event->attr.branch_sample_type;
 
                        if (has_branch_stack(event)) {
@@ -568,7 +569,7 @@ struct sched_state {
 struct perf_sched {
        int                     max_weight;
        int                     max_events;
-       struct event_constraint **constraints;
+       struct perf_event       **events;
        struct sched_state      state;
        int                     saved_states;
        struct sched_state      saved[SCHED_STATES_MAX];
@@ -577,7 +578,7 @@ struct perf_sched {
 /*
  * Initialize interator that runs through all events and counters.
  */
-static void perf_sched_init(struct perf_sched *sched, struct event_constraint **c,
+static void perf_sched_init(struct perf_sched *sched, struct perf_event **events,
                            int num, int wmin, int wmax)
 {
        int idx;
@@ -585,10 +586,10 @@ static void perf_sched_init(struct perf_sched *sched, struct event_constraint **
        memset(sched, 0, sizeof(*sched));
        sched->max_events       = num;
        sched->max_weight       = wmax;
-       sched->constraints      = c;
+       sched->events           = events;
 
        for (idx = 0; idx < num; idx++) {
-               if (c[idx]->weight == wmin)
+               if (events[idx]->hw.constraint->weight == wmin)
                        break;
        }
 
@@ -635,8 +636,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched)
        if (sched->state.event >= sched->max_events)
                return false;
 
-       c = sched->constraints[sched->state.event];
-
+       c = sched->events[sched->state.event]->hw.constraint;
        /* Prefer fixed purpose counters */
        if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) {
                idx = INTEL_PMC_IDX_FIXED;
@@ -694,7 +694,7 @@ static bool perf_sched_next_event(struct perf_sched *sched)
                        if (sched->state.weight > sched->max_weight)
                                return false;
                }
-               c = sched->constraints[sched->state.event];
+               c = sched->events[sched->state.event]->hw.constraint;
        } while (c->weight != sched->state.weight);
 
        sched->state.counter = 0;       /* start with first counter */
@@ -705,12 +705,12 @@ static bool perf_sched_next_event(struct perf_sched *sched)
 /*
  * Assign a counter for each event.
  */
-int perf_assign_events(struct event_constraint **constraints, int n,
+int perf_assign_events(struct perf_event **events, int n,
                        int wmin, int wmax, int *assign)
 {
        struct perf_sched sched;
 
-       perf_sched_init(&sched, constraints, n, wmin, wmax);
+       perf_sched_init(&sched, events, n, wmin, wmax);
 
        do {
                if (!perf_sched_find_counter(&sched))
@@ -724,16 +724,19 @@ int perf_assign_events(struct event_constraint **constraints, int n,
 
 int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 {
-       struct event_constraint *c, *constraints[X86_PMC_IDX_MAX];
+       struct event_constraint *c;
        unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
+       struct perf_event *e;
        int i, wmin, wmax, num = 0;
        struct hw_perf_event *hwc;
 
        bitmap_zero(used_mask, X86_PMC_IDX_MAX);
 
        for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) {
+               hwc = &cpuc->event_list[i]->hw;
                c = x86_pmu.get_event_constraints(cpuc, cpuc->event_list[i]);
-               constraints[i] = c;
+               hwc->constraint = c;
+
                wmin = min(wmin, c->weight);
                wmax = max(wmax, c->weight);
        }
@@ -743,7 +746,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
         */
        for (i = 0; i < n; i++) {
                hwc = &cpuc->event_list[i]->hw;
-               c = constraints[i];
+               c = hwc->constraint;
 
                /* never assigned */
                if (hwc->idx == -1)
@@ -764,16 +767,35 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
 
        /* slow path */
        if (i != n)
-               num = perf_assign_events(constraints, n, wmin, wmax, assign);
+               num = perf_assign_events(cpuc->event_list, n, wmin,
+                                        wmax, assign);
 
+       /*
+        * Mark the event as committed, so we do not put_constraint()
+        * in case new events are added and fail scheduling.
+        */
+       if (!num && assign) {
+               for (i = 0; i < n; i++) {
+                       e = cpuc->event_list[i];
+                       e->hw.flags |= PERF_X86_EVENT_COMMITTED;
+               }
+       }
        /*
         * scheduling failed or is just a simulation,
         * free resources if necessary
         */
        if (!assign || num) {
                for (i = 0; i < n; i++) {
+                       e = cpuc->event_list[i];
+                       /*
+                        * do not put_constraint() on comitted events,
+                        * because they are good to go
+                        */
+                       if ((e->hw.flags & PERF_X86_EVENT_COMMITTED))
+                               continue;
+
                        if (x86_pmu.put_event_constraints)
-                               x86_pmu.put_event_constraints(cpuc, cpuc->event_list[i]);
+                               x86_pmu.put_event_constraints(cpuc, e);
                }
        }
        return num ? -EINVAL : 0;
@@ -1152,6 +1174,11 @@ static void x86_pmu_del(struct perf_event *event, int flags)
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        int i;
 
+       /*
+        * event is descheduled
+        */
+       event->hw.flags &= ~PERF_X86_EVENT_COMMITTED;
+
        /*
         * If we're called during a txn, we don't need to do anything.
         * The events never got scheduled and ->cancel_txn will truncate
@@ -1249,10 +1276,20 @@ void perf_events_lapic_init(void)
 static int __kprobes
 perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs)
 {
+       int ret;
+       u64 start_clock;
+       u64 finish_clock;
+
        if (!atomic_read(&active_events))
                return NMI_DONE;
 
-       return x86_pmu.handle_irq(regs);
+       start_clock = local_clock();
+       ret = x86_pmu.handle_irq(regs);
+       finish_clock = local_clock();
+
+       perf_sample_event_took(finish_clock - start_clock);
+
+       return ret;
 }
 
 struct event_constraint emptyconstraint;
index ba9aadfa683b5f3eb393bf365ba3cba50f9daa8c..97e557bc4c91f8fe646421e29882c9dcfbf9a832 100644 (file)
@@ -63,10 +63,12 @@ struct event_constraint {
        int     flags;
 };
 /*
- * struct event_constraint flags
+ * struct hw_perf_event.flags flags
  */
 #define PERF_X86_EVENT_PEBS_LDLAT      0x1 /* ld+ldlat data address sampling */
 #define PERF_X86_EVENT_PEBS_ST         0x2 /* st data address sampling */
+#define PERF_X86_EVENT_PEBS_ST_HSW     0x4 /* haswell style st data sampling */
+#define PERF_X86_EVENT_COMMITTED       0x8 /* event passed commit_txn */
 
 struct amd_nb {
        int nb_id;  /* NorthBridge id */
@@ -227,11 +229,14 @@ struct cpu_hw_events {
  *  - inv
  *  - edge
  *  - cnt-mask
+ *  - in_tx
+ *  - in_tx_checkpointed
  *  The other filters are supported by fixed counters.
  *  The any-thread option is supported starting with v3.
  */
+#define FIXED_EVENT_FLAGS (X86_RAW_EVENT_MASK|HSW_IN_TX|HSW_IN_TX_CHECKPOINTED)
 #define FIXED_EVENT_CONSTRAINT(c, n)   \
-       EVENT_CONSTRAINT(c, (1ULL << (32+n)), X86_RAW_EVENT_MASK)
+       EVENT_CONSTRAINT(c, (1ULL << (32+n)), FIXED_EVENT_FLAGS)
 
 /*
  * Constraint on the Event code + UMask
@@ -247,6 +252,11 @@ struct cpu_hw_events {
        __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
                          HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST)
 
+/* DataLA version of store sampling without extra enable bit. */
+#define INTEL_PST_HSW_CONSTRAINT(c, n) \
+       __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
+                         HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST_HSW)
+
 #define EVENT_CONSTRAINT_END           \
        EVENT_CONSTRAINT(0, 0, 0)
 
@@ -301,6 +311,11 @@ union perf_capabilities {
                u64     pebs_arch_reg:1;
                u64     pebs_format:4;
                u64     smm_freeze:1;
+               /*
+                * PMU supports separate counter range for writing
+                * values > 32bit.
+                */
+               u64     full_width_write:1;
        };
        u64     capabilities;
 };
@@ -375,6 +390,7 @@ struct x86_pmu {
        struct event_constraint *event_constraints;
        struct x86_pmu_quirk *quirks;
        int             perfctr_second_write;
+       bool            late_ack;
 
        /*
         * sysfs attrs
@@ -528,7 +544,7 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
 
 void x86_pmu_enable_all(int added);
 
-int perf_assign_events(struct event_constraint **constraints, int n,
+int perf_assign_events(struct perf_event **events, int n,
                        int wmin, int wmax, int *assign);
 int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign);
 
@@ -633,6 +649,8 @@ extern struct event_constraint intel_snb_pebs_event_constraints[];
 
 extern struct event_constraint intel_ivb_pebs_event_constraints[];
 
+extern struct event_constraint intel_hsw_pebs_event_constraints[];
+
 struct event_constraint *intel_pebs_constraints(struct perf_event *event);
 
 void intel_pmu_pebs_enable(struct perf_event *event);
index 7e28d9467bb491e61a51c827b1582f16cb2cc30a..4cbe03287b0892594f4c84fca58746f82e5acdbd 100644 (file)
@@ -648,48 +648,48 @@ static __initconst const struct x86_pmu amd_pmu = {
        .cpu_dead               = amd_pmu_cpu_dead,
 };
 
-static int setup_event_constraints(void)
+static int __init amd_core_pmu_init(void)
 {
-       if (boot_cpu_data.x86 == 0x15)
+       if (!cpu_has_perfctr_core)
+               return 0;
+
+       switch (boot_cpu_data.x86) {
+       case 0x15:
+               pr_cont("Fam15h ");
                x86_pmu.get_event_constraints = amd_get_event_constraints_f15h;
-       return 0;
-}
+               break;
 
-static int setup_perfctr_core(void)
-{
-       if (!cpu_has_perfctr_core) {
-               WARN(x86_pmu.get_event_constraints == amd_get_event_constraints_f15h,
-                    KERN_ERR "Odd, counter constraints enabled but no core perfctrs detected!");
+       default:
+               pr_err("core perfctr but no constraints; unknown hardware!\n");
                return -ENODEV;
        }
 
-       WARN(x86_pmu.get_event_constraints == amd_get_event_constraints,
-            KERN_ERR "hw perf events core counters need constraints handler!");
-
        /*
         * If core performance counter extensions exists, we must use
         * MSR_F15H_PERF_CTL/MSR_F15H_PERF_CTR msrs. See also
-        * x86_pmu_addr_offset().
+        * amd_pmu_addr_offset().
         */
        x86_pmu.eventsel        = MSR_F15H_PERF_CTL;
        x86_pmu.perfctr         = MSR_F15H_PERF_CTR;
        x86_pmu.num_counters    = AMD64_NUM_COUNTERS_CORE;
 
-       printk(KERN_INFO "perf: AMD core performance counters detected\n");
-
+       pr_cont("core perfctr, ");
        return 0;
 }
 
 __init int amd_pmu_init(void)
 {
+       int ret;
+
        /* Performance-monitoring supported from K7 and later: */
        if (boot_cpu_data.x86 < 6)
                return -ENODEV;
 
        x86_pmu = amd_pmu;
 
-       setup_event_constraints();
-       setup_perfctr_core();
+       ret = amd_core_pmu_init();
+       if (ret)
+               return ret;
 
        /* Events are common for all AMDs */
        memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
diff --git a/arch/x86/kernel/cpu/perf_event_amd_iommu.c b/arch/x86/kernel/cpu/perf_event_amd_iommu.c
new file mode 100644 (file)
index 0000000..0db655e
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ *
+ * Author: Steven Kinney <Steven.Kinney@amd.com>
+ * Author: Suravee Suthikulpanit <Suraveee.Suthikulpanit@amd.com>
+ *
+ * Perf: amd_iommu - AMD IOMMU Performance Counter PMU implementation
+ *
+ * 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/perf_event.h>
+#include <linux/module.h>
+#include <linux/cpumask.h>
+#include <linux/slab.h>
+
+#include "perf_event.h"
+#include "perf_event_amd_iommu.h"
+
+#define COUNTER_SHIFT          16
+
+#define _GET_BANK(ev)       ((u8)(ev->hw.extra_reg.reg >> 8))
+#define _GET_CNTR(ev)       ((u8)(ev->hw.extra_reg.reg))
+
+/* iommu pmu config masks */
+#define _GET_CSOURCE(ev)    ((ev->hw.config & 0xFFULL))
+#define _GET_DEVID(ev)      ((ev->hw.config >> 8)  & 0xFFFFULL)
+#define _GET_PASID(ev)      ((ev->hw.config >> 24) & 0xFFFFULL)
+#define _GET_DOMID(ev)      ((ev->hw.config >> 40) & 0xFFFFULL)
+#define _GET_DEVID_MASK(ev) ((ev->hw.extra_reg.config)  & 0xFFFFULL)
+#define _GET_PASID_MASK(ev) ((ev->hw.extra_reg.config >> 16) & 0xFFFFULL)
+#define _GET_DOMID_MASK(ev) ((ev->hw.extra_reg.config >> 32) & 0xFFFFULL)
+
+static struct perf_amd_iommu __perf_iommu;
+
+struct perf_amd_iommu {
+       struct pmu pmu;
+       u8 max_banks;
+       u8 max_counters;
+       u64 cntr_assign_mask;
+       raw_spinlock_t lock;
+       const struct attribute_group *attr_groups[4];
+};
+
+#define format_group   attr_groups[0]
+#define cpumask_group  attr_groups[1]
+#define events_group   attr_groups[2]
+#define null_group     attr_groups[3]
+
+/*---------------------------------------------
+ * sysfs format attributes
+ *---------------------------------------------*/
+PMU_FORMAT_ATTR(csource,    "config:0-7");
+PMU_FORMAT_ATTR(devid,      "config:8-23");
+PMU_FORMAT_ATTR(pasid,      "config:24-39");
+PMU_FORMAT_ATTR(domid,      "config:40-55");
+PMU_FORMAT_ATTR(devid_mask, "config1:0-15");
+PMU_FORMAT_ATTR(pasid_mask, "config1:16-31");
+PMU_FORMAT_ATTR(domid_mask, "config1:32-47");
+
+static struct attribute *iommu_format_attrs[] = {
+       &format_attr_csource.attr,
+       &format_attr_devid.attr,
+       &format_attr_pasid.attr,
+       &format_attr_domid.attr,
+       &format_attr_devid_mask.attr,
+       &format_attr_pasid_mask.attr,
+       &format_attr_domid_mask.attr,
+       NULL,
+};
+
+static struct attribute_group amd_iommu_format_group = {
+       .name = "format",
+       .attrs = iommu_format_attrs,
+};
+
+/*---------------------------------------------
+ * sysfs events attributes
+ *---------------------------------------------*/
+struct amd_iommu_event_desc {
+       struct kobj_attribute attr;
+       const char *event;
+};
+
+static ssize_t _iommu_event_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *buf)
+{
+       struct amd_iommu_event_desc *event =
+               container_of(attr, struct amd_iommu_event_desc, attr);
+       return sprintf(buf, "%s\n", event->event);
+}
+
+#define AMD_IOMMU_EVENT_DESC(_name, _event)                    \
+{                                                              \
+       .attr  = __ATTR(_name, 0444, _iommu_event_show, NULL),  \
+       .event = _event,                                        \
+}
+
+static struct amd_iommu_event_desc amd_iommu_v2_event_descs[] = {
+       AMD_IOMMU_EVENT_DESC(mem_pass_untrans,        "csource=0x01"),
+       AMD_IOMMU_EVENT_DESC(mem_pass_pretrans,       "csource=0x02"),
+       AMD_IOMMU_EVENT_DESC(mem_pass_excl,           "csource=0x03"),
+       AMD_IOMMU_EVENT_DESC(mem_target_abort,        "csource=0x04"),
+       AMD_IOMMU_EVENT_DESC(mem_trans_total,         "csource=0x05"),
+       AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pte_hit,   "csource=0x06"),
+       AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pte_mis,   "csource=0x07"),
+       AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pde_hit,   "csource=0x08"),
+       AMD_IOMMU_EVENT_DESC(mem_iommu_tlb_pde_mis,   "csource=0x09"),
+       AMD_IOMMU_EVENT_DESC(mem_dte_hit,             "csource=0x0a"),
+       AMD_IOMMU_EVENT_DESC(mem_dte_mis,             "csource=0x0b"),
+       AMD_IOMMU_EVENT_DESC(page_tbl_read_tot,       "csource=0x0c"),
+       AMD_IOMMU_EVENT_DESC(page_tbl_read_nst,       "csource=0x0d"),
+       AMD_IOMMU_EVENT_DESC(page_tbl_read_gst,       "csource=0x0e"),
+       AMD_IOMMU_EVENT_DESC(int_dte_hit,             "csource=0x0f"),
+       AMD_IOMMU_EVENT_DESC(int_dte_mis,             "csource=0x10"),
+       AMD_IOMMU_EVENT_DESC(cmd_processed,           "csource=0x11"),
+       AMD_IOMMU_EVENT_DESC(cmd_processed_inv,       "csource=0x12"),
+       AMD_IOMMU_EVENT_DESC(tlb_inv,                 "csource=0x13"),
+       { /* end: all zeroes */ },
+};
+
+/*---------------------------------------------
+ * sysfs cpumask attributes
+ *---------------------------------------------*/
+static cpumask_t iommu_cpumask;
+
+static ssize_t _iommu_cpumask_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       int n = cpulist_scnprintf(buf, PAGE_SIZE - 2, &iommu_cpumask);
+       buf[n++] = '\n';
+       buf[n] = '\0';
+       return n;
+}
+static DEVICE_ATTR(cpumask, S_IRUGO, _iommu_cpumask_show, NULL);
+
+static struct attribute *iommu_cpumask_attrs[] = {
+       &dev_attr_cpumask.attr,
+       NULL,
+};
+
+static struct attribute_group amd_iommu_cpumask_group = {
+       .attrs = iommu_cpumask_attrs,
+};
+
+/*---------------------------------------------*/
+
+static int get_next_avail_iommu_bnk_cntr(struct perf_amd_iommu *perf_iommu)
+{
+       unsigned long flags;
+       int shift, bank, cntr, retval;
+       int max_banks = perf_iommu->max_banks;
+       int max_cntrs = perf_iommu->max_counters;
+
+       raw_spin_lock_irqsave(&perf_iommu->lock, flags);
+
+       for (bank = 0, shift = 0; bank < max_banks; bank++) {
+               for (cntr = 0; cntr < max_cntrs; cntr++) {
+                       shift = bank + (bank*3) + cntr;
+                       if (perf_iommu->cntr_assign_mask & (1ULL<<shift)) {
+                               continue;
+                       } else {
+                               perf_iommu->cntr_assign_mask |= (1ULL<<shift);
+                               retval = ((u16)((u16)bank<<8) | (u8)(cntr));
+                               goto out;
+                       }
+               }
+       }
+       retval = -ENOSPC;
+out:
+       raw_spin_unlock_irqrestore(&perf_iommu->lock, flags);
+       return retval;
+}
+
+static int clear_avail_iommu_bnk_cntr(struct perf_amd_iommu *perf_iommu,
+                                       u8 bank, u8 cntr)
+{
+       unsigned long flags;
+       int max_banks, max_cntrs;
+       int shift = 0;
+
+       max_banks = perf_iommu->max_banks;
+       max_cntrs = perf_iommu->max_counters;
+
+       if ((bank > max_banks) || (cntr > max_cntrs))
+               return -EINVAL;
+
+       shift = bank + cntr + (bank*3);
+
+       raw_spin_lock_irqsave(&perf_iommu->lock, flags);
+       perf_iommu->cntr_assign_mask &= ~(1ULL<<shift);
+       raw_spin_unlock_irqrestore(&perf_iommu->lock, flags);
+
+       return 0;
+}
+
+static int perf_iommu_event_init(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct perf_amd_iommu *perf_iommu;
+       u64 config, config1;
+
+       /* test the event attr type check for PMU enumeration */
+       if (event->attr.type != event->pmu->type)
+               return -ENOENT;
+
+       /*
+        * IOMMU counters are shared across all cores.
+        * Therefore, it does not support per-process mode.
+        * Also, it does not support event sampling mode.
+        */
+       if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+               return -EINVAL;
+
+       /* IOMMU counters do not have usr/os/guest/host bits */
+       if (event->attr.exclude_user || event->attr.exclude_kernel ||
+           event->attr.exclude_host || event->attr.exclude_guest)
+               return -EINVAL;
+
+       if (event->cpu < 0)
+               return -EINVAL;
+
+       perf_iommu = &__perf_iommu;
+
+       if (event->pmu != &perf_iommu->pmu)
+               return -ENOENT;
+
+       if (perf_iommu) {
+               config = event->attr.config;
+               config1 = event->attr.config1;
+       } else {
+               return -EINVAL;
+       }
+
+       /* integrate with iommu base devid (0000), assume one iommu */
+       perf_iommu->max_banks =
+               amd_iommu_pc_get_max_banks(IOMMU_BASE_DEVID);
+       perf_iommu->max_counters =
+               amd_iommu_pc_get_max_counters(IOMMU_BASE_DEVID);
+       if ((perf_iommu->max_banks == 0) || (perf_iommu->max_counters == 0))
+               return -EINVAL;
+
+       /* update the hw_perf_event struct with the iommu config data */
+       hwc->config = config;
+       hwc->extra_reg.config = config1;
+
+       return 0;
+}
+
+static void perf_iommu_enable_event(struct perf_event *ev)
+{
+       u8 csource = _GET_CSOURCE(ev);
+       u16 devid = _GET_DEVID(ev);
+       u64 reg = 0ULL;
+
+       reg = csource;
+       amd_iommu_pc_get_set_reg_val(devid,
+                       _GET_BANK(ev), _GET_CNTR(ev) ,
+                        IOMMU_PC_COUNTER_SRC_REG, &reg, true);
+
+       reg = 0ULL | devid | (_GET_DEVID_MASK(ev) << 32);
+       if (reg)
+               reg |= (1UL << 31);
+       amd_iommu_pc_get_set_reg_val(devid,
+                       _GET_BANK(ev), _GET_CNTR(ev) ,
+                        IOMMU_PC_DEVID_MATCH_REG, &reg, true);
+
+       reg = 0ULL | _GET_PASID(ev) | (_GET_PASID_MASK(ev) << 32);
+       if (reg)
+               reg |= (1UL << 31);
+       amd_iommu_pc_get_set_reg_val(devid,
+                       _GET_BANK(ev), _GET_CNTR(ev) ,
+                        IOMMU_PC_PASID_MATCH_REG, &reg, true);
+
+       reg = 0ULL | _GET_DOMID(ev) | (_GET_DOMID_MASK(ev) << 32);
+       if (reg)
+               reg |= (1UL << 31);
+       amd_iommu_pc_get_set_reg_val(devid,
+                       _GET_BANK(ev), _GET_CNTR(ev) ,
+                        IOMMU_PC_DOMID_MATCH_REG, &reg, true);
+}
+
+static void perf_iommu_disable_event(struct perf_event *event)
+{
+       u64 reg = 0ULL;
+
+       amd_iommu_pc_get_set_reg_val(_GET_DEVID(event),
+                       _GET_BANK(event), _GET_CNTR(event),
+                       IOMMU_PC_COUNTER_SRC_REG, &reg, true);
+}
+
+static void perf_iommu_start(struct perf_event *event, int flags)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       pr_debug("perf: amd_iommu:perf_iommu_start\n");
+       if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+               return;
+
+       WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+       hwc->state = 0;
+
+       if (flags & PERF_EF_RELOAD) {
+               u64 prev_raw_count =  local64_read(&hwc->prev_count);
+               amd_iommu_pc_get_set_reg_val(_GET_DEVID(event),
+                               _GET_BANK(event), _GET_CNTR(event),
+                               IOMMU_PC_COUNTER_REG, &prev_raw_count, true);
+       }
+
+       perf_iommu_enable_event(event);
+       perf_event_update_userpage(event);
+
+}
+
+static void perf_iommu_read(struct perf_event *event)
+{
+       u64 count = 0ULL;
+       u64 prev_raw_count = 0ULL;
+       u64 delta = 0ULL;
+       struct hw_perf_event *hwc = &event->hw;
+       pr_debug("perf: amd_iommu:perf_iommu_read\n");
+
+       amd_iommu_pc_get_set_reg_val(_GET_DEVID(event),
+                               _GET_BANK(event), _GET_CNTR(event),
+                               IOMMU_PC_COUNTER_REG, &count, false);
+
+       /* IOMMU pc counter register is only 48 bits */
+       count &= 0xFFFFFFFFFFFFULL;
+
+       prev_raw_count =  local64_read(&hwc->prev_count);
+       if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+                                       count) != prev_raw_count)
+               return;
+
+       /* Handling 48-bit counter overflowing */
+       delta = (count << COUNTER_SHIFT) - (prev_raw_count << COUNTER_SHIFT);
+       delta >>= COUNTER_SHIFT;
+       local64_add(delta, &event->count);
+
+}
+
+static void perf_iommu_stop(struct perf_event *event, int flags)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       u64 config;
+
+       pr_debug("perf: amd_iommu:perf_iommu_stop\n");
+
+       if (hwc->state & PERF_HES_UPTODATE)
+               return;
+
+       perf_iommu_disable_event(event);
+       WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+       hwc->state |= PERF_HES_STOPPED;
+
+       if (hwc->state & PERF_HES_UPTODATE)
+               return;
+
+       config = hwc->config;
+       perf_iommu_read(event);
+       hwc->state |= PERF_HES_UPTODATE;
+}
+
+static int perf_iommu_add(struct perf_event *event, int flags)
+{
+       int retval;
+       struct perf_amd_iommu *perf_iommu =
+                       container_of(event->pmu, struct perf_amd_iommu, pmu);
+
+       pr_debug("perf: amd_iommu:perf_iommu_add\n");
+       event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+       /* request an iommu bank/counter */
+       retval = get_next_avail_iommu_bnk_cntr(perf_iommu);
+       if (retval != -ENOSPC)
+               event->hw.extra_reg.reg = (u16)retval;
+       else
+               return retval;
+
+       if (flags & PERF_EF_START)
+               perf_iommu_start(event, PERF_EF_RELOAD);
+
+       return 0;
+}
+
+static void perf_iommu_del(struct perf_event *event, int flags)
+{
+       struct perf_amd_iommu *perf_iommu =
+                       container_of(event->pmu, struct perf_amd_iommu, pmu);
+
+       pr_debug("perf: amd_iommu:perf_iommu_del\n");
+       perf_iommu_stop(event, PERF_EF_UPDATE);
+
+       /* clear the assigned iommu bank/counter */
+       clear_avail_iommu_bnk_cntr(perf_iommu,
+                                    _GET_BANK(event),
+                                    _GET_CNTR(event));
+
+       perf_event_update_userpage(event);
+}
+
+static __init int _init_events_attrs(struct perf_amd_iommu *perf_iommu)
+{
+       struct attribute **attrs;
+       struct attribute_group *attr_group;
+       int i = 0, j;
+
+       while (amd_iommu_v2_event_descs[i].attr.attr.name)
+               i++;
+
+       attr_group = kzalloc(sizeof(struct attribute *)
+               * (i + 1) + sizeof(*attr_group), GFP_KERNEL);
+       if (!attr_group)
+               return -ENOMEM;
+
+       attrs = (struct attribute **)(attr_group + 1);
+       for (j = 0; j < i; j++)
+               attrs[j] = &amd_iommu_v2_event_descs[j].attr.attr;
+
+       attr_group->name = "events";
+       attr_group->attrs = attrs;
+       perf_iommu->events_group = attr_group;
+
+       return 0;
+}
+
+static __init void amd_iommu_pc_exit(void)
+{
+       if (__perf_iommu.events_group != NULL) {
+               kfree(__perf_iommu.events_group);
+               __perf_iommu.events_group = NULL;
+       }
+}
+
+static __init int _init_perf_amd_iommu(
+       struct perf_amd_iommu *perf_iommu, char *name)
+{
+       int ret;
+
+       raw_spin_lock_init(&perf_iommu->lock);
+
+       /* Init format attributes */
+       perf_iommu->format_group = &amd_iommu_format_group;
+
+       /* Init cpumask attributes to only core 0 */
+       cpumask_set_cpu(0, &iommu_cpumask);
+       perf_iommu->cpumask_group = &amd_iommu_cpumask_group;
+
+       /* Init events attributes */
+       if (_init_events_attrs(perf_iommu) != 0)
+               pr_err("perf: amd_iommu: Only support raw events.\n");
+
+       /* Init null attributes */
+       perf_iommu->null_group = NULL;
+       perf_iommu->pmu.attr_groups = perf_iommu->attr_groups;
+
+       ret = perf_pmu_register(&perf_iommu->pmu, name, -1);
+       if (ret) {
+               pr_err("perf: amd_iommu: Failed to initialized.\n");
+               amd_iommu_pc_exit();
+       } else {
+               pr_info("perf: amd_iommu: Detected. (%d banks, %d counters/bank)\n",
+                       amd_iommu_pc_get_max_banks(IOMMU_BASE_DEVID),
+                       amd_iommu_pc_get_max_counters(IOMMU_BASE_DEVID));
+       }
+
+       return ret;
+}
+
+static struct perf_amd_iommu __perf_iommu = {
+       .pmu = {
+               .event_init     = perf_iommu_event_init,
+               .add            = perf_iommu_add,
+               .del            = perf_iommu_del,
+               .start          = perf_iommu_start,
+               .stop           = perf_iommu_stop,
+               .read           = perf_iommu_read,
+       },
+       .max_banks              = 0x00,
+       .max_counters           = 0x00,
+       .cntr_assign_mask       = 0ULL,
+       .format_group           = NULL,
+       .cpumask_group          = NULL,
+       .events_group           = NULL,
+       .null_group             = NULL,
+};
+
+static __init int amd_iommu_pc_init(void)
+{
+       /* Make sure the IOMMU PC resource is available */
+       if (!amd_iommu_pc_supported()) {
+               pr_err("perf: amd_iommu PMU not installed. No support!\n");
+               return -ENODEV;
+       }
+
+       _init_perf_amd_iommu(&__perf_iommu, "amd_iommu");
+
+       return 0;
+}
+
+device_initcall(amd_iommu_pc_init);
diff --git a/arch/x86/kernel/cpu/perf_event_amd_iommu.h b/arch/x86/kernel/cpu/perf_event_amd_iommu.h
new file mode 100644 (file)
index 0000000..845d173
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ *
+ * Author: Steven Kinney <Steven.Kinney@amd.com>
+ * Author: Suravee Suthikulpanit <Suraveee.Suthikulpanit@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PERF_EVENT_AMD_IOMMU_H_
+#define _PERF_EVENT_AMD_IOMMU_H_
+
+/* iommu pc mmio region register indexes */
+#define IOMMU_PC_COUNTER_REG                   0x00
+#define IOMMU_PC_COUNTER_SRC_REG               0x08
+#define IOMMU_PC_PASID_MATCH_REG               0x10
+#define IOMMU_PC_DOMID_MATCH_REG               0x18
+#define IOMMU_PC_DEVID_MATCH_REG               0x20
+#define IOMMU_PC_COUNTER_REPORT_REG            0x28
+
+/* maximun specified bank/counters */
+#define PC_MAX_SPEC_BNKS                       64
+#define PC_MAX_SPEC_CNTRS                      16
+
+/* iommu pc reg masks*/
+#define IOMMU_BASE_DEVID                       0x0000
+
+/* amd_iommu_init.c external support functions */
+extern bool amd_iommu_pc_supported(void);
+
+extern u8 amd_iommu_pc_get_max_banks(u16 devid);
+
+extern u8 amd_iommu_pc_get_max_counters(u16 devid);
+
+extern int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr,
+                       u8 fxn, u64 *value, bool is_write);
+
+#endif /*_PERF_EVENT_AMD_IOMMU_H_*/
index a9e22073bd56a755ea1952dea202eba63e350f7f..fbc9210b45bcbe62fd2c1b765a46701c2eb21212 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 
+#include <asm/cpufeature.h>
 #include <asm/hardirq.h>
 #include <asm/apic.h>
 
@@ -190,6 +191,22 @@ struct attribute *snb_events_attrs[] = {
        NULL,
 };
 
+static struct event_constraint intel_hsw_event_constraints[] = {
+       FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+       FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+       FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
+       INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.* */
+       INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
+       INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
+       /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
+       INTEL_EVENT_CONSTRAINT(0x08a3, 0x4),
+       /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */
+       INTEL_EVENT_CONSTRAINT(0x0ca3, 0x4),
+       /* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */
+       INTEL_EVENT_CONSTRAINT(0x04a3, 0xf),
+       EVENT_CONSTRAINT_END
+};
+
 static u64 intel_pmu_event_map(int hw_event)
 {
        return intel_perfmon_event_map[hw_event];
@@ -872,7 +889,8 @@ static inline bool intel_pmu_needs_lbr_smpl(struct perf_event *event)
                return true;
 
        /* implicit branch sampling to correct PEBS skid */
-       if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip > 1)
+       if (x86_pmu.intel_cap.pebs_trap && event->attr.precise_ip > 1 &&
+           x86_pmu.intel_cap.pebs_format < 2)
                return true;
 
        return false;
@@ -1167,15 +1185,11 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
        cpuc = &__get_cpu_var(cpu_hw_events);
 
        /*
-        * Some chipsets need to unmask the LVTPC in a particular spot
-        * inside the nmi handler.  As a result, the unmasking was pushed
-        * into all the nmi handlers.
-        *
-        * This handler doesn't seem to have any issues with the unmasking
-        * so it was left at the top.
+        * No known reason to not always do late ACK,
+        * but just in case do it opt-in.
         */
-       apic_write(APIC_LVTPC, APIC_DM_NMI);
-
+       if (!x86_pmu.late_ack)
+               apic_write(APIC_LVTPC, APIC_DM_NMI);
        intel_pmu_disable_all();
        handled = intel_pmu_drain_bts_buffer();
        status = intel_pmu_get_status();
@@ -1188,8 +1202,12 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
 again:
        intel_pmu_ack_status(status);
        if (++loops > 100) {
-               WARN_ONCE(1, "perfevents: irq loop stuck!\n");
-               perf_event_print_debug();
+               static bool warned = false;
+               if (!warned) {
+                       WARN(1, "perfevents: irq loop stuck!\n");
+                       perf_event_print_debug();
+                       warned = true;
+               }
                intel_pmu_reset();
                goto done;
        }
@@ -1235,6 +1253,13 @@ again:
 
 done:
        intel_pmu_enable_all(0);
+       /*
+        * Only unmask the NMI after the overflow counters
+        * have been reset. This avoids spurious NMIs on
+        * Haswell CPUs.
+        */
+       if (x86_pmu.late_ack)
+               apic_write(APIC_LVTPC, APIC_DM_NMI);
        return handled;
 }
 
@@ -1425,7 +1450,6 @@ x86_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
        if (x86_pmu.event_constraints) {
                for_each_event_constraint(c, x86_pmu.event_constraints) {
                        if ((event->hw.config & c->cmask) == c->code) {
-                               /* hw.flags zeroed at initialization */
                                event->hw.flags |= c->flags;
                                return c;
                        }
@@ -1473,7 +1497,6 @@ intel_put_shared_regs_event_constraints(struct cpu_hw_events *cpuc,
 static void intel_put_event_constraints(struct cpu_hw_events *cpuc,
                                        struct perf_event *event)
 {
-       event->hw.flags = 0;
        intel_put_shared_regs_event_constraints(cpuc, event);
 }
 
@@ -1646,6 +1669,47 @@ static void core_pmu_enable_all(int added)
        }
 }
 
+static int hsw_hw_config(struct perf_event *event)
+{
+       int ret = intel_pmu_hw_config(event);
+
+       if (ret)
+               return ret;
+       if (!boot_cpu_has(X86_FEATURE_RTM) && !boot_cpu_has(X86_FEATURE_HLE))
+               return 0;
+       event->hw.config |= event->attr.config & (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED);
+
+       /*
+        * IN_TX/IN_TX-CP filters are not supported by the Haswell PMU with
+        * PEBS or in ANY thread mode. Since the results are non-sensical forbid
+        * this combination.
+        */
+       if ((event->hw.config & (HSW_IN_TX|HSW_IN_TX_CHECKPOINTED)) &&
+            ((event->hw.config & ARCH_PERFMON_EVENTSEL_ANY) ||
+             event->attr.precise_ip > 0))
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
+static struct event_constraint counter2_constraint =
+                       EVENT_CONSTRAINT(0, 0x4, 0);
+
+static struct event_constraint *
+hsw_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
+{
+       struct event_constraint *c = intel_get_event_constraints(cpuc, event);
+
+       /* Handle special quirk on in_tx_checkpointed only in counter 2 */
+       if (event->hw.config & HSW_IN_TX_CHECKPOINTED) {
+               if (c->idxmsk64 & (1U << 2))
+                       return &counter2_constraint;
+               return &emptyconstraint;
+       }
+
+       return c;
+}
+
 PMU_FORMAT_ATTR(event, "config:0-7"    );
 PMU_FORMAT_ATTR(umask, "config:8-15"   );
 PMU_FORMAT_ATTR(edge,  "config:18"     );
@@ -1653,6 +1717,8 @@ PMU_FORMAT_ATTR(pc,       "config:19"     );
 PMU_FORMAT_ATTR(any,   "config:21"     ); /* v3 + */
 PMU_FORMAT_ATTR(inv,   "config:23"     );
 PMU_FORMAT_ATTR(cmask, "config:24-31"  );
+PMU_FORMAT_ATTR(in_tx,  "config:32");
+PMU_FORMAT_ATTR(in_tx_cp, "config:33");
 
 static struct attribute *intel_arch_formats_attr[] = {
        &format_attr_event.attr,
@@ -1807,6 +1873,8 @@ static struct attribute *intel_arch3_formats_attr[] = {
        &format_attr_any.attr,
        &format_attr_inv.attr,
        &format_attr_cmask.attr,
+       &format_attr_in_tx.attr,
+       &format_attr_in_tx_cp.attr,
 
        &format_attr_offcore_rsp.attr, /* XXX do NHM/WSM + SNB breakout */
        &format_attr_ldlat.attr, /* PEBS load latency */
@@ -1966,6 +2034,15 @@ static __init void intel_nehalem_quirk(void)
        }
 }
 
+EVENT_ATTR_STR(mem-loads,      mem_ld_hsw,     "event=0xcd,umask=0x1,ldlat=3");
+EVENT_ATTR_STR(mem-stores,     mem_st_hsw,     "event=0xd0,umask=0x82")
+
+static struct attribute *hsw_events_attrs[] = {
+       EVENT_PTR(mem_ld_hsw),
+       EVENT_PTR(mem_st_hsw),
+       NULL
+};
+
 __init int intel_pmu_init(void)
 {
        union cpuid10_edx edx;
@@ -2189,6 +2266,30 @@ __init int intel_pmu_init(void)
                break;
 
 
+       case 60: /* Haswell Client */
+       case 70:
+       case 71:
+       case 63:
+               x86_pmu.late_ack = true;
+               memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+               memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+
+               intel_pmu_lbr_init_snb();
+
+               x86_pmu.event_constraints = intel_hsw_event_constraints;
+               x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
+               x86_pmu.extra_regs = intel_snb_extra_regs;
+               x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+               /* all extra regs are per-cpu when HT is on */
+               x86_pmu.er_flags |= ERF_HAS_RSP_1;
+               x86_pmu.er_flags |= ERF_NO_HT_SHARING;
+
+               x86_pmu.hw_config = hsw_hw_config;
+               x86_pmu.get_event_constraints = hsw_get_event_constraints;
+               x86_pmu.cpu_events = hsw_events_attrs;
+               pr_cont("Haswell events, ");
+               break;
+
        default:
                switch (x86_pmu.version) {
                case 1:
@@ -2227,7 +2328,7 @@ __init int intel_pmu_init(void)
                 * counter, so do not extend mask to generic counters
                 */
                for_each_event_constraint(c, x86_pmu.event_constraints) {
-                       if (c->cmask != X86_RAW_EVENT_MASK
+                       if (c->cmask != FIXED_EVENT_FLAGS
                            || c->idxmsk64 == INTEL_PMC_MSK_FIXED_REF_CYCLES) {
                                continue;
                        }
@@ -2237,5 +2338,12 @@ __init int intel_pmu_init(void)
                }
        }
 
+       /* Support full width counters using alternative MSR range */
+       if (x86_pmu.intel_cap.full_width_write) {
+               x86_pmu.max_period = x86_pmu.cntval_mask;
+               x86_pmu.perfctr = MSR_IA32_PMC0;
+               pr_cont("full-width counters, ");
+       }
+
        return 0;
 }
index 60250f68705291d539cf562b4c5f507b7d0e5a43..3065c57a63c19873e07d18e13122f04704e2de96 100644 (file)
@@ -107,6 +107,19 @@ static u64 precise_store_data(u64 status)
        return val;
 }
 
+static u64 precise_store_data_hsw(u64 status)
+{
+       union perf_mem_data_src dse;
+
+       dse.val = 0;
+       dse.mem_op = PERF_MEM_OP_STORE;
+       dse.mem_lvl = PERF_MEM_LVL_NA;
+       if (status & 1)
+               dse.mem_lvl = PERF_MEM_LVL_L1;
+       /* Nothing else supported. Sorry. */
+       return dse.val;
+}
+
 static u64 load_latency_data(u64 status)
 {
        union intel_x86_pebs_dse dse;
@@ -165,6 +178,22 @@ struct pebs_record_nhm {
        u64 status, dla, dse, lat;
 };
 
+/*
+ * Same as pebs_record_nhm, with two additional fields.
+ */
+struct pebs_record_hsw {
+       struct pebs_record_nhm nhm;
+       /*
+        * Real IP of the event. In the Intel documentation this
+        * is called eventingrip.
+        */
+       u64 real_ip;
+       /*
+        * TSX tuning information field: abort cycles and abort flags.
+        */
+       u64 tsx_tuning;
+};
+
 void init_debug_store_on_cpu(int cpu)
 {
        struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
@@ -548,6 +577,42 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = {
         EVENT_CONSTRAINT_END
 };
 
+struct event_constraint intel_hsw_pebs_event_constraints[] = {
+       INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
+       INTEL_PST_HSW_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
+       INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
+       INTEL_EVENT_CONSTRAINT(0xc4, 0xf),    /* BR_INST_RETIRED.* */
+       INTEL_UEVENT_CONSTRAINT(0x01c5, 0xf), /* BR_MISP_RETIRED.CONDITIONAL */
+       INTEL_UEVENT_CONSTRAINT(0x04c5, 0xf), /* BR_MISP_RETIRED.ALL_BRANCHES */
+       INTEL_UEVENT_CONSTRAINT(0x20c5, 0xf), /* BR_MISP_RETIRED.NEAR_TAKEN */
+       INTEL_PLD_CONSTRAINT(0x01cd, 0x8),    /* MEM_TRANS_RETIRED.* */
+       /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */
+       INTEL_UEVENT_CONSTRAINT(0x11d0, 0xf),
+       /* MEM_UOPS_RETIRED.STLB_MISS_STORES */
+       INTEL_UEVENT_CONSTRAINT(0x12d0, 0xf),
+       INTEL_UEVENT_CONSTRAINT(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */
+       INTEL_UEVENT_CONSTRAINT(0x41d0, 0xf), /* MEM_UOPS_RETIRED.SPLIT_LOADS */
+       /* MEM_UOPS_RETIRED.SPLIT_STORES */
+       INTEL_UEVENT_CONSTRAINT(0x42d0, 0xf),
+       INTEL_UEVENT_CONSTRAINT(0x81d0, 0xf), /* MEM_UOPS_RETIRED.ALL_LOADS */
+       INTEL_PST_HSW_CONSTRAINT(0x82d0, 0xf), /* MEM_UOPS_RETIRED.ALL_STORES */
+       INTEL_UEVENT_CONSTRAINT(0x01d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L1_HIT */
+       INTEL_UEVENT_CONSTRAINT(0x02d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L2_HIT */
+       INTEL_UEVENT_CONSTRAINT(0x04d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L3_HIT */
+       /* MEM_LOAD_UOPS_RETIRED.HIT_LFB */
+       INTEL_UEVENT_CONSTRAINT(0x40d1, 0xf),
+       /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS */
+       INTEL_UEVENT_CONSTRAINT(0x01d2, 0xf),
+       /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT */
+       INTEL_UEVENT_CONSTRAINT(0x02d2, 0xf),
+       /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM */
+       INTEL_UEVENT_CONSTRAINT(0x01d3, 0xf),
+       INTEL_UEVENT_CONSTRAINT(0x04c8, 0xf), /* HLE_RETIRED.Abort */
+       INTEL_UEVENT_CONSTRAINT(0x04c9, 0xf), /* RTM_RETIRED.Abort */
+
+       EVENT_CONSTRAINT_END
+};
+
 struct event_constraint *intel_pebs_constraints(struct perf_event *event)
 {
        struct event_constraint *c;
@@ -588,6 +653,12 @@ void intel_pmu_pebs_disable(struct perf_event *event)
        struct hw_perf_event *hwc = &event->hw;
 
        cpuc->pebs_enabled &= ~(1ULL << hwc->idx);
+
+       if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_LDLAT)
+               cpuc->pebs_enabled &= ~(1ULL << (hwc->idx + 32));
+       else if (event->hw.constraint->flags & PERF_X86_EVENT_PEBS_ST)
+               cpuc->pebs_enabled &= ~(1ULL << 63);
+
        if (cpuc->enabled)
                wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled);
 
@@ -697,6 +768,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
         */
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct pebs_record_nhm *pebs = __pebs;
+       struct pebs_record_hsw *pebs_hsw = __pebs;
        struct perf_sample_data data;
        struct pt_regs regs;
        u64 sample_type;
@@ -706,7 +778,8 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
                return;
 
        fll = event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT;
-       fst = event->hw.flags & PERF_X86_EVENT_PEBS_ST;
+       fst = event->hw.flags & (PERF_X86_EVENT_PEBS_ST |
+                                PERF_X86_EVENT_PEBS_ST_HSW);
 
        perf_sample_data_init(&data, 0, event->hw.last_period);
 
@@ -717,9 +790,6 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
         * if PEBS-LL or PreciseStore
         */
        if (fll || fst) {
-               if (sample_type & PERF_SAMPLE_ADDR)
-                       data.addr = pebs->dla;
-
                /*
                 * Use latency for weight (only avail with PEBS-LL)
                 */
@@ -732,6 +802,9 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
                if (sample_type & PERF_SAMPLE_DATA_SRC) {
                        if (fll)
                                data.data_src.val = load_latency_data(pebs->dse);
+                       else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW)
+                               data.data_src.val =
+                                       precise_store_data_hsw(pebs->dse);
                        else
                                data.data_src.val = precise_store_data(pebs->dse);
                }
@@ -753,11 +826,18 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
        regs.bp = pebs->bp;
        regs.sp = pebs->sp;
 
-       if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(&regs))
+       if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) {
+               regs.ip = pebs_hsw->real_ip;
+               regs.flags |= PERF_EFLAGS_EXACT;
+       } else if (event->attr.precise_ip > 1 && intel_pmu_pebs_fixup_ip(&regs))
                regs.flags |= PERF_EFLAGS_EXACT;
        else
                regs.flags &= ~PERF_EFLAGS_EXACT;
 
+       if ((event->attr.sample_type & PERF_SAMPLE_ADDR) &&
+               x86_pmu.intel_cap.pebs_format >= 1)
+               data.addr = pebs->dla;
+
        if (has_branch_stack(event))
                data.br_stack = &cpuc->lbr_stack;
 
@@ -806,35 +886,22 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
        __intel_pmu_pebs_event(event, iregs, at);
 }
 
-static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
+static void __intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, void *at,
+                                       void *top)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct debug_store *ds = cpuc->ds;
-       struct pebs_record_nhm *at, *top;
        struct perf_event *event = NULL;
        u64 status = 0;
-       int bit, n;
-
-       if (!x86_pmu.pebs_active)
-               return;
-
-       at  = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
-       top = (struct pebs_record_nhm *)(unsigned long)ds->pebs_index;
+       int bit;
 
        ds->pebs_index = ds->pebs_buffer_base;
 
-       n = top - at;
-       if (n <= 0)
-               return;
-
-       /*
-        * Should not happen, we program the threshold at 1 and do not
-        * set a reset value.
-        */
-       WARN_ONCE(n > x86_pmu.max_pebs_events, "Unexpected number of pebs records %d\n", n);
+       for (; at < top; at += x86_pmu.pebs_record_size) {
+               struct pebs_record_nhm *p = at;
 
-       for ( ; at < top; at++) {
-               for_each_set_bit(bit, (unsigned long *)&at->status, x86_pmu.max_pebs_events) {
+               for_each_set_bit(bit, (unsigned long *)&p->status,
+                                x86_pmu.max_pebs_events) {
                        event = cpuc->events[bit];
                        if (!test_bit(bit, cpuc->active_mask))
                                continue;
@@ -857,6 +924,61 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
        }
 }
 
+static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct debug_store *ds = cpuc->ds;
+       struct pebs_record_nhm *at, *top;
+       int n;
+
+       if (!x86_pmu.pebs_active)
+               return;
+
+       at  = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
+       top = (struct pebs_record_nhm *)(unsigned long)ds->pebs_index;
+
+       ds->pebs_index = ds->pebs_buffer_base;
+
+       n = top - at;
+       if (n <= 0)
+               return;
+
+       /*
+        * Should not happen, we program the threshold at 1 and do not
+        * set a reset value.
+        */
+       WARN_ONCE(n > x86_pmu.max_pebs_events,
+                 "Unexpected number of pebs records %d\n", n);
+
+       return __intel_pmu_drain_pebs_nhm(iregs, at, top);
+}
+
+static void intel_pmu_drain_pebs_hsw(struct pt_regs *iregs)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct debug_store *ds = cpuc->ds;
+       struct pebs_record_hsw *at, *top;
+       int n;
+
+       if (!x86_pmu.pebs_active)
+               return;
+
+       at  = (struct pebs_record_hsw *)(unsigned long)ds->pebs_buffer_base;
+       top = (struct pebs_record_hsw *)(unsigned long)ds->pebs_index;
+
+       n = top - at;
+       if (n <= 0)
+               return;
+       /*
+        * Should not happen, we program the threshold at 1 and do not
+        * set a reset value.
+        */
+       WARN_ONCE(n > x86_pmu.max_pebs_events,
+                 "Unexpected number of pebs records %d\n", n);
+
+       return __intel_pmu_drain_pebs_nhm(iregs, at, top);
+}
+
 /*
  * BTS, PEBS probe and setup
  */
@@ -888,6 +1010,12 @@ void intel_ds_init(void)
                        x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm;
                        break;
 
+               case 2:
+                       pr_cont("PEBS fmt2%c, ", pebs_type);
+                       x86_pmu.pebs_record_size = sizeof(struct pebs_record_hsw);
+                       x86_pmu.drain_pebs = intel_pmu_drain_pebs_hsw;
+                       break;
+
                default:
                        printk(KERN_CONT "no PEBS fmt%d%c, ", format, pebs_type);
                        x86_pmu.pebs = 0;
index d978353c939bba235a29e76fda02d1f8eb97f84a..d5be06a5005e99eb9ac8dbe808f565013bddc929 100644 (file)
@@ -12,6 +12,16 @@ enum {
        LBR_FORMAT_LIP          = 0x01,
        LBR_FORMAT_EIP          = 0x02,
        LBR_FORMAT_EIP_FLAGS    = 0x03,
+       LBR_FORMAT_EIP_FLAGS2   = 0x04,
+       LBR_FORMAT_MAX_KNOWN    = LBR_FORMAT_EIP_FLAGS2,
+};
+
+static enum {
+       LBR_EIP_FLAGS           = 1,
+       LBR_TSX                 = 2,
+} lbr_desc[LBR_FORMAT_MAX_KNOWN + 1] = {
+       [LBR_FORMAT_EIP_FLAGS]  = LBR_EIP_FLAGS,
+       [LBR_FORMAT_EIP_FLAGS2] = LBR_EIP_FLAGS | LBR_TSX,
 };
 
 /*
@@ -56,6 +66,8 @@ enum {
         LBR_FAR)
 
 #define LBR_FROM_FLAG_MISPRED  (1ULL << 63)
+#define LBR_FROM_FLAG_IN_TX    (1ULL << 62)
+#define LBR_FROM_FLAG_ABORT    (1ULL << 61)
 
 #define for_each_branch_sample_type(x) \
        for ((x) = PERF_SAMPLE_BRANCH_USER; \
@@ -81,9 +93,13 @@ enum {
        X86_BR_JMP      = 1 << 9, /* jump */
        X86_BR_IRQ      = 1 << 10,/* hw interrupt or trap or fault */
        X86_BR_IND_CALL = 1 << 11,/* indirect calls */
+       X86_BR_ABORT    = 1 << 12,/* transaction abort */
+       X86_BR_IN_TX    = 1 << 13,/* in transaction */
+       X86_BR_NO_TX    = 1 << 14,/* not in transaction */
 };
 
 #define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL)
+#define X86_BR_ANYTX (X86_BR_NO_TX | X86_BR_IN_TX)
 
 #define X86_BR_ANY       \
        (X86_BR_CALL    |\
@@ -95,6 +111,7 @@ enum {
         X86_BR_JCC     |\
         X86_BR_JMP      |\
         X86_BR_IRQ      |\
+        X86_BR_ABORT    |\
         X86_BR_IND_CALL)
 
 #define X86_BR_ALL (X86_BR_PLM | X86_BR_ANY)
@@ -270,21 +287,31 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
 
        for (i = 0; i < x86_pmu.lbr_nr; i++) {
                unsigned long lbr_idx = (tos - i) & mask;
-               u64 from, to, mis = 0, pred = 0;
+               u64 from, to, mis = 0, pred = 0, in_tx = 0, abort = 0;
+               int skip = 0;
+               int lbr_flags = lbr_desc[lbr_format];
 
                rdmsrl(x86_pmu.lbr_from + lbr_idx, from);
                rdmsrl(x86_pmu.lbr_to   + lbr_idx, to);
 
-               if (lbr_format == LBR_FORMAT_EIP_FLAGS) {
+               if (lbr_flags & LBR_EIP_FLAGS) {
                        mis = !!(from & LBR_FROM_FLAG_MISPRED);
                        pred = !mis;
-                       from = (u64)((((s64)from) << 1) >> 1);
+                       skip = 1;
+               }
+               if (lbr_flags & LBR_TSX) {
+                       in_tx = !!(from & LBR_FROM_FLAG_IN_TX);
+                       abort = !!(from & LBR_FROM_FLAG_ABORT);
+                       skip = 3;
                }
+               from = (u64)((((s64)from) << skip) >> skip);
 
                cpuc->lbr_entries[i].from       = from;
                cpuc->lbr_entries[i].to         = to;
                cpuc->lbr_entries[i].mispred    = mis;
                cpuc->lbr_entries[i].predicted  = pred;
+               cpuc->lbr_entries[i].in_tx      = in_tx;
+               cpuc->lbr_entries[i].abort      = abort;
                cpuc->lbr_entries[i].reserved   = 0;
        }
        cpuc->lbr_stack.nr = i;
@@ -310,7 +337,7 @@ void intel_pmu_lbr_read(void)
  * - in case there is no HW filter
  * - in case the HW filter has errata or limitations
  */
-static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
+static void intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
 {
        u64 br_type = event->attr.branch_sample_type;
        int mask = 0;
@@ -318,11 +345,8 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
        if (br_type & PERF_SAMPLE_BRANCH_USER)
                mask |= X86_BR_USER;
 
-       if (br_type & PERF_SAMPLE_BRANCH_KERNEL) {
-               if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN))
-                       return -EACCES;
+       if (br_type & PERF_SAMPLE_BRANCH_KERNEL)
                mask |= X86_BR_KERNEL;
-       }
 
        /* we ignore BRANCH_HV here */
 
@@ -337,13 +361,21 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event)
 
        if (br_type & PERF_SAMPLE_BRANCH_IND_CALL)
                mask |= X86_BR_IND_CALL;
+
+       if (br_type & PERF_SAMPLE_BRANCH_ABORT_TX)
+               mask |= X86_BR_ABORT;
+
+       if (br_type & PERF_SAMPLE_BRANCH_IN_TX)
+               mask |= X86_BR_IN_TX;
+
+       if (br_type & PERF_SAMPLE_BRANCH_NO_TX)
+               mask |= X86_BR_NO_TX;
+
        /*
         * stash actual user request into reg, it may
         * be used by fixup code for some CPU
         */
        event->hw.branch_reg.reg = mask;
-
-       return 0;
 }
 
 /*
@@ -391,9 +423,7 @@ int intel_pmu_setup_lbr_filter(struct perf_event *event)
        /*
         * setup SW LBR filter
         */
-       ret = intel_pmu_setup_sw_lbr_filter(event);
-       if (ret)
-               return ret;
+       intel_pmu_setup_sw_lbr_filter(event);
 
        /*
         * setup HW LBR filter, if any
@@ -415,7 +445,7 @@ int intel_pmu_setup_lbr_filter(struct perf_event *event)
  * decoded (e.g., text page not present), then X86_BR_NONE is
  * returned.
  */
-static int branch_type(unsigned long from, unsigned long to)
+static int branch_type(unsigned long from, unsigned long to, int abort)
 {
        struct insn insn;
        void *addr;
@@ -435,6 +465,9 @@ static int branch_type(unsigned long from, unsigned long to)
        if (from == 0 || to == 0)
                return X86_BR_NONE;
 
+       if (abort)
+               return X86_BR_ABORT | to_plm;
+
        if (from_plm == X86_BR_USER) {
                /*
                 * can happen if measuring at the user level only
@@ -581,7 +614,13 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
                from = cpuc->lbr_entries[i].from;
                to = cpuc->lbr_entries[i].to;
 
-               type = branch_type(from, to);
+               type = branch_type(from, to, cpuc->lbr_entries[i].abort);
+               if (type != X86_BR_NONE && (br_sel & X86_BR_ANYTX)) {
+                       if (cpuc->lbr_entries[i].in_tx)
+                               type |= X86_BR_IN_TX;
+                       else
+                               type |= X86_BR_NO_TX;
+               }
 
                /* if type does not correspond, then discard */
                if (type == X86_BR_NONE || (br_sel & type) != type) {
index 52441a2af5380d1d44bbee24001b81ea63d53362..9dd99751ccf9eb205643a539d3b654e7a0867d26 100644 (file)
@@ -536,7 +536,7 @@ __snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *eve
        if (!uncore_box_is_fake(box))
                reg1->alloc |= alloc;
 
-       return 0;
+       return NULL;
 fail:
        for (; i >= 0; i--) {
                if (alloc & (0x1 << i))
@@ -644,7 +644,7 @@ snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
            (!uncore_box_is_fake(box) && reg1->alloc))
                return NULL;
 again:
-       mask = 0xff << (idx * 8);
+       mask = 0xffULL << (idx * 8);
        raw_spin_lock_irqsave(&er->lock, flags);
        if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) ||
            !((config1 ^ er->config) & mask)) {
@@ -1923,7 +1923,7 @@ static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modif
 {
        struct hw_perf_event *hwc = &event->hw;
        struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-       int idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8);
+       u64 idx, orig_idx = __BITS_VALUE(reg1->idx, 0, 8);
        u64 config = reg1->config;
 
        /* get the non-shared control bits and shift them */
@@ -2723,15 +2723,16 @@ static void uncore_put_event_constraint(struct intel_uncore_box *box, struct per
 static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int n)
 {
        unsigned long used_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)];
-       struct event_constraint *c, *constraints[UNCORE_PMC_IDX_MAX];
+       struct event_constraint *c;
        int i, wmin, wmax, ret = 0;
        struct hw_perf_event *hwc;
 
        bitmap_zero(used_mask, UNCORE_PMC_IDX_MAX);
 
        for (i = 0, wmin = UNCORE_PMC_IDX_MAX, wmax = 0; i < n; i++) {
+               hwc = &box->event_list[i]->hw;
                c = uncore_get_event_constraint(box, box->event_list[i]);
-               constraints[i] = c;
+               hwc->constraint = c;
                wmin = min(wmin, c->weight);
                wmax = max(wmax, c->weight);
        }
@@ -2739,7 +2740,7 @@ static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int
        /* fastpath, try to reuse previous register */
        for (i = 0; i < n; i++) {
                hwc = &box->event_list[i]->hw;
-               c = constraints[i];
+               c = hwc->constraint;
 
                /* never assigned */
                if (hwc->idx == -1)
@@ -2759,7 +2760,8 @@ static int uncore_assign_events(struct intel_uncore_box *box, int assign[], int
        }
        /* slow path */
        if (i != n)
-               ret = perf_assign_events(constraints, n, wmin, wmax, assign);
+               ret = perf_assign_events(box->event_list, n,
+                                        wmin, wmax, assign);
 
        if (!assign || ret) {
                for (i = 0; i < n; i++)
index f9528917f6e8047083d61ec9c396b4330251ac32..47b3d00c9d896255d1cd00ca5706e5dd565975c4 100644 (file)
                 NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
 
 #define NHMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 11) - 1) | (1 << 23))
-#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7 << (11 + 3 * (n)))
+#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (11 + 3 * (n)))
 
 #define WSMEX_M_PMON_ZDP_CTL_FVC_MASK          (((1 << 12) - 1) | (1 << 24))
-#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7 << (12 + 3 * (n)))
+#define WSMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7ULL << (12 + 3 * (n)))
 
 /*
  * use the 9~13 bits to select event If the 7th bit is not set,
index 37a198bd48c8f1defb7a5a256c3ec433b13b2758..aee6317b902fb490dbc13673dce0a89ea88e2a4b 100644 (file)
@@ -37,8 +37,8 @@ static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c)
                   static_cpu_has_bug(X86_BUG_FDIV) ? "yes" : "no",
                   static_cpu_has_bug(X86_BUG_F00F) ? "yes" : "no",
                   static_cpu_has_bug(X86_BUG_COMA) ? "yes" : "no",
-                  c->hard_math ? "yes" : "no",
-                  c->hard_math ? "yes" : "no",
+                  static_cpu_has(X86_FEATURE_FPU) ? "yes" : "no",
+                  static_cpu_has(X86_FEATURE_FPU) ? "yes" : "no",
                   c->cpuid_level,
                   c->wp_works_ok ? "yes" : "no");
 }
similarity index 84%
rename from arch/x86/kernel/doublefault_32.c
rename to arch/x86/kernel/doublefault.c
index 155a13f33ed8aa60f58d2aef7856dd0eb419ecf7..5d3fe8d36e4ac71fb262f94bef68417d3e782c42 100644 (file)
@@ -9,6 +9,8 @@
 #include <asm/processor.h>
 #include <asm/desc.h>
 
+#ifdef CONFIG_X86_32
+
 #define DOUBLEFAULT_STACKSIZE (1024)
 static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
 #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
@@ -67,3 +69,16 @@ struct tss_struct doublefault_tss __cacheline_aligned = {
                .__cr3          = __pa_nodebug(swapper_pg_dir),
        }
 };
+
+/* dummy for do_double_fault() call */
+void df_debug(struct pt_regs *regs, long error_code) {}
+
+#else /* !CONFIG_X86_32 */
+
+void df_debug(struct pt_regs *regs, long error_code)
+{
+       pr_emerg("PANIC: double fault, error_code: 0x%lx\n", error_code);
+       show_regs(regs);
+       panic("Machine halted.");
+}
+#endif
index 8f3e2dec1df32aa2bafa5cfbd1dbd0ce35e7cdf2..2cfbc3a3a2dd61055bccc6633a80a5910c293529 100644 (file)
@@ -801,7 +801,17 @@ ENTRY(name)                                \
        CFI_ENDPROC;                    \
 ENDPROC(name)
 
-#define BUILD_INTERRUPT(name, nr)      BUILD_INTERRUPT3(name, nr, smp_##name)
+
+#ifdef CONFIG_TRACING
+#define TRACE_BUILD_INTERRUPT(name, nr)                \
+       BUILD_INTERRUPT3(trace_##name, nr, smp_trace_##name)
+#else
+#define TRACE_BUILD_INTERRUPT(name, nr)
+#endif
+
+#define BUILD_INTERRUPT(name, nr) \
+       BUILD_INTERRUPT3(name, nr, smp_##name); \
+       TRACE_BUILD_INTERRUPT(name, nr)
 
 /* The include is where all of the SMP etc. interrupts come from */
 #include <asm/entry_arch.h>
index 727208941030943370fde4160b6f9ad54e62b68b..1b69951a81e2b61bff752621872d5750736f96d4 100644 (file)
@@ -365,7 +365,7 @@ ENDPROC(native_usergs_sysret64)
        /*CFI_REL_OFFSET        ss,0*/
        pushq_cfi %rax /* rsp */
        CFI_REL_OFFSET  rsp,0
-       pushq_cfi $(X86_EFLAGS_IF|X86_EFLAGS_BIT1) /* eflags - interrupts on */
+       pushq_cfi $(X86_EFLAGS_IF|X86_EFLAGS_FIXED) /* eflags - interrupts on */
        /*CFI_REL_OFFSET        rflags,0*/
        pushq_cfi $__KERNEL_CS /* cs */
        /*CFI_REL_OFFSET        cs,0*/
@@ -1138,7 +1138,7 @@ END(common_interrupt)
 /*
  * APIC interrupts.
  */
-.macro apicinterrupt num sym do_sym
+.macro apicinterrupt3 num sym do_sym
 ENTRY(\sym)
        INTR_FRAME
        ASM_CLAC
@@ -1150,15 +1150,32 @@ ENTRY(\sym)
 END(\sym)
 .endm
 
+#ifdef CONFIG_TRACING
+#define trace(sym) trace_##sym
+#define smp_trace(sym) smp_trace_##sym
+
+.macro trace_apicinterrupt num sym
+apicinterrupt3 \num trace(\sym) smp_trace(\sym)
+.endm
+#else
+.macro trace_apicinterrupt num sym do_sym
+.endm
+#endif
+
+.macro apicinterrupt num sym do_sym
+apicinterrupt3 \num \sym \do_sym
+trace_apicinterrupt \num \sym
+.endm
+
 #ifdef CONFIG_SMP
-apicinterrupt IRQ_MOVE_CLEANUP_VECTOR \
+apicinterrupt3 IRQ_MOVE_CLEANUP_VECTOR \
        irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt
-apicinterrupt REBOOT_VECTOR \
+apicinterrupt3 REBOOT_VECTOR \
        reboot_interrupt smp_reboot_interrupt
 #endif
 
 #ifdef CONFIG_X86_UV
-apicinterrupt UV_BAU_MESSAGE \
+apicinterrupt3 UV_BAU_MESSAGE \
        uv_bau_message_intr1 uv_bau_message_interrupt
 #endif
 apicinterrupt LOCAL_TIMER_VECTOR \
@@ -1167,14 +1184,19 @@ apicinterrupt X86_PLATFORM_IPI_VECTOR \
        x86_platform_ipi smp_x86_platform_ipi
 
 #ifdef CONFIG_HAVE_KVM
-apicinterrupt POSTED_INTR_VECTOR \
+apicinterrupt3 POSTED_INTR_VECTOR \
        kvm_posted_intr_ipi smp_kvm_posted_intr_ipi
 #endif
 
+#ifdef CONFIG_X86_MCE_THRESHOLD
 apicinterrupt THRESHOLD_APIC_VECTOR \
        threshold_interrupt smp_threshold_interrupt
+#endif
+
+#ifdef CONFIG_X86_THERMAL_VECTOR
 apicinterrupt THERMAL_APIC_VECTOR \
        thermal_interrupt smp_thermal_interrupt
+#endif
 
 #ifdef CONFIG_SMP
 apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \
@@ -1451,13 +1473,13 @@ ENTRY(xen_failsafe_callback)
        CFI_ENDPROC
 END(xen_failsafe_callback)
 
-apicinterrupt HYPERVISOR_CALLBACK_VECTOR \
+apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \
        xen_hvm_callback_vector xen_evtchn_do_upcall
 
 #endif /* CONFIG_XEN */
 
 #if IS_ENABLED(CONFIG_HYPERV)
-apicinterrupt HYPERVISOR_CALLBACK_VECTOR \
+apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \
        hyperv_callback_vector hyperv_vector_handler
 #endif /* CONFIG_HYPERV */
 
index 73afd11799ca7c10cfa015a3b0c83435a7003e9d..e65ddc62e1137a8a6f6f4cab04bfe28b9482e905 100644 (file)
@@ -444,7 +444,6 @@ is486:
        orl %ecx,%eax
        movl %eax,%cr0
 
-       call check_x87
        lgdt early_gdt_descr
        lidt idt_descr
        ljmp $(__KERNEL_CS),$1f
@@ -467,26 +466,6 @@ is486:
        pushl $0                # fake return address for unwinder
        jmp *(initial_code)
 
-/*
- * We depend on ET to be correct. This checks for 287/387.
- */
-check_x87:
-       movb $0,X86_HARD_MATH
-       clts
-       fninit
-       fstsw %ax
-       cmpb $0,%al
-       je 1f
-       movl %cr0,%eax          /* no coprocessor: have to set bits */
-       xorl $4,%eax            /* set EM */
-       movl %eax,%cr0
-       ret
-       ALIGN
-1:     movb $1,X86_HARD_MATH
-       .byte 0xDB,0xE4         /* fsetpm for 287, ignored by 387 */
-       ret
-
-       
 #include "verify_cpu.S"
 
 /*
index 321d65ebaffe255bbb1dc1bc6aaf2ac217d55aaf..5e4d8a8a5c407b7cae67f3d7f86392962c506d0d 100644 (file)
@@ -518,9 +518,15 @@ ENTRY(idt_table)
        .skip IDT_ENTRIES * 16
 
        .align L1_CACHE_BYTES
-ENTRY(nmi_idt_table)
+ENTRY(debug_idt_table)
        .skip IDT_ENTRIES * 16
 
+#ifdef CONFIG_TRACING
+       .align L1_CACHE_BYTES
+ENTRY(trace_idt_table)
+       .skip IDT_ENTRIES * 16
+#endif
+
        __PAGE_ALIGNED_BSS
 NEXT_PAGE(empty_zero_page)
        .skip PAGE_SIZE
index cb339097b9ea0cf4f57b2b406fa308a489cee881..b627746f6b1a81a5fc0c6e9e30adb1bb502f0b87 100644 (file)
@@ -131,7 +131,7 @@ static void __cpuinit init_thread_xstate(void)
         * xsave_init().
         */
 
-       if (!HAVE_HWFP) {
+       if (!cpu_has_fpu) {
                /*
                 * Disable xsave as we do not support it if i387
                 * emulation is enabled.
@@ -158,6 +158,14 @@ void __cpuinit fpu_init(void)
        unsigned long cr0;
        unsigned long cr4_mask = 0;
 
+#ifndef CONFIG_MATH_EMULATION
+       if (!cpu_has_fpu) {
+               pr_emerg("No FPU found and no math emulation present\n");
+               pr_emerg("Giving up\n");
+               for (;;)
+                       asm volatile("hlt");
+       }
+#endif
        if (cpu_has_fxsr)
                cr4_mask |= X86_CR4_OSFXSR;
        if (cpu_has_xmm)
@@ -167,7 +175,7 @@ void __cpuinit fpu_init(void)
 
        cr0 = read_cr0();
        cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
-       if (!HAVE_HWFP)
+       if (!cpu_has_fpu)
                cr0 |= X86_CR0_EM;
        write_cr0(cr0);
 
@@ -185,7 +193,7 @@ void __cpuinit fpu_init(void)
 
 void fpu_finit(struct fpu *fpu)
 {
-       if (!HAVE_HWFP) {
+       if (!cpu_has_fpu) {
                finit_soft_fpu(&fpu->state->soft);
                return;
        }
@@ -214,7 +222,7 @@ int init_fpu(struct task_struct *tsk)
        int ret;
 
        if (tsk_used_math(tsk)) {
-               if (HAVE_HWFP && tsk == current)
+               if (cpu_has_fpu && tsk == current)
                        unlazy_fpu(tsk);
                tsk->thread.fpu.last_cpu = ~0;
                return 0;
@@ -511,14 +519,13 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset,
        if (ret)
                return ret;
 
-       if (!HAVE_HWFP)
+       if (!static_cpu_has(X86_FEATURE_FPU))
                return fpregs_soft_get(target, regset, pos, count, kbuf, ubuf);
 
-       if (!cpu_has_fxsr) {
+       if (!cpu_has_fxsr)
                return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
                                           &target->thread.fpu.state->fsave, 0,
                                           -1);
-       }
 
        sanitize_i387_state(target);
 
@@ -545,13 +552,13 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
 
        sanitize_i387_state(target);
 
-       if (!HAVE_HWFP)
+       if (!static_cpu_has(X86_FEATURE_FPU))
                return fpregs_soft_set(target, regset, pos, count, kbuf, ubuf);
 
-       if (!cpu_has_fxsr) {
+       if (!cpu_has_fxsr)
                return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                         &target->thread.fpu.state->fsave, 0, -1);
-       }
+                                         &target->thread.fpu.state->fsave, 0,
+                                         -1);
 
        if (pos > 0 || count < sizeof(env))
                convert_from_fxsr(&env, target);
@@ -592,3 +599,33 @@ int dump_fpu(struct pt_regs *regs, struct user_i387_struct *fpu)
 EXPORT_SYMBOL(dump_fpu);
 
 #endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
+
+static int __init no_387(char *s)
+{
+       setup_clear_cpu_cap(X86_FEATURE_FPU);
+       return 1;
+}
+
+__setup("no387", no_387);
+
+void __cpuinit fpu_detect(struct cpuinfo_x86 *c)
+{
+       unsigned long cr0;
+       u16 fsw, fcw;
+
+       fsw = fcw = 0xffff;
+
+       cr0 = read_cr0();
+       cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
+       write_cr0(cr0);
+
+       asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
+                    : "+m" (fsw), "+m" (fcw));
+
+       if (fsw == 0 && (fcw & 0x103f) == 0x003f)
+               set_cpu_cap(c, X86_FEATURE_FPU);
+       else
+               clear_cpu_cap(c, X86_FEATURE_FPU);
+
+       /* The final cr0 value is set in fpu_init() */
+}
index ac0631d8996ffe2085d5d57de3b5bde718c3359c..3a8185c042a29faf10f9ccfcb19ee35448681398 100644 (file)
@@ -18,6 +18,9 @@
 #include <asm/mce.h>
 #include <asm/hw_irq.h>
 
+#define CREATE_TRACE_POINTS
+#include <asm/trace/irq_vectors.h>
+
 atomic_t irq_err_count;
 
 /* Function pointer for generic interrupt vector handling */
@@ -204,23 +207,21 @@ unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
 /*
  * Handler for X86_PLATFORM_IPI_VECTOR.
  */
-void smp_x86_platform_ipi(struct pt_regs *regs)
+void __smp_x86_platform_ipi(void)
 {
-       struct pt_regs *old_regs = set_irq_regs(regs);
-
-       ack_APIC_irq();
-
-       irq_enter();
-
-       exit_idle();
-
        inc_irq_stat(x86_platform_ipis);
 
        if (x86_platform_ipi_callback)
                x86_platform_ipi_callback();
+}
 
-       irq_exit();
+void smp_x86_platform_ipi(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
 
+       entering_ack_irq();
+       __smp_x86_platform_ipi();
+       exiting_irq();
        set_irq_regs(old_regs);
 }
 
@@ -246,6 +247,18 @@ void smp_kvm_posted_intr_ipi(struct pt_regs *regs)
 }
 #endif
 
+void smp_trace_x86_platform_ipi(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
+
+       entering_ack_irq();
+       trace_x86_platform_ipi_entry(X86_PLATFORM_IPI_VECTOR);
+       __smp_x86_platform_ipi();
+       trace_x86_platform_ipi_exit(X86_PLATFORM_IPI_VECTOR);
+       exiting_irq();
+       set_irq_regs(old_regs);
+}
+
 EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq);
 
 #ifdef CONFIG_HOTPLUG_CPU
index ca8f703a1e70bdaf219bdcdd215ac2e1724bfda6..636a55e4a13caced32c109d80eba33821125c84c 100644 (file)
@@ -8,14 +8,34 @@
 #include <linux/irq_work.h>
 #include <linux/hardirq.h>
 #include <asm/apic.h>
+#include <asm/trace/irq_vectors.h>
 
-void smp_irq_work_interrupt(struct pt_regs *regs)
+static inline void irq_work_entering_irq(void)
 {
        irq_enter();
        ack_APIC_irq();
+}
+
+static inline void __smp_irq_work_interrupt(void)
+{
        inc_irq_stat(apic_irq_work_irqs);
        irq_work_run();
-       irq_exit();
+}
+
+void smp_irq_work_interrupt(struct pt_regs *regs)
+{
+       irq_work_entering_irq();
+       __smp_irq_work_interrupt();
+       exiting_irq();
+}
+
+void smp_trace_irq_work_interrupt(struct pt_regs *regs)
+{
+       irq_work_entering_irq();
+       trace_irq_work_entry(IRQ_WORK_VECTOR);
+       __smp_irq_work_interrupt();
+       trace_irq_work_exit(IRQ_WORK_VECTOR);
+       exiting_irq();
 }
 
 void arch_irq_work_raise(void)
index efdec7cd8e01057aeee63c95b16713c4803c7e61..47ebb1dbfbcb2413ddaf9d4cc86b7d8558eb3c72 100644 (file)
 #include <asm/microcode.h>
 #include <asm/processor.h>
 #include <asm/msr.h>
+#include <asm/microcode_amd.h>
 
 MODULE_DESCRIPTION("AMD Microcode Update Driver");
 MODULE_AUTHOR("Peter Oruba");
 MODULE_LICENSE("GPL v2");
 
-#define UCODE_MAGIC                0x00414d44
-#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
-#define UCODE_UCODE_TYPE           0x00000001
-
-struct equiv_cpu_entry {
-       u32     installed_cpu;
-       u32     fixed_errata_mask;
-       u32     fixed_errata_compare;
-       u16     equiv_cpu;
-       u16     res;
-} __attribute__((packed));
-
-struct microcode_header_amd {
-       u32     data_code;
-       u32     patch_id;
-       u16     mc_patch_data_id;
-       u8      mc_patch_data_len;
-       u8      init_flag;
-       u32     mc_patch_data_checksum;
-       u32     nb_dev_id;
-       u32     sb_dev_id;
-       u16     processor_rev_id;
-       u8      nb_rev_id;
-       u8      sb_rev_id;
-       u8      bios_api_rev;
-       u8      reserved1[3];
-       u32     match_reg[8];
-} __attribute__((packed));
-
-struct microcode_amd {
-       struct microcode_header_amd     hdr;
-       unsigned int                    mpb[0];
-};
-
-#define SECTION_HDR_SIZE       8
-#define CONTAINER_HDR_SZ       12
-
 static struct equiv_cpu_entry *equiv_cpu_table;
 
 struct ucode_patch {
@@ -84,21 +48,10 @@ struct ucode_patch {
 
 static LIST_HEAD(pcache);
 
-static u16 find_equiv_id(unsigned int cpu)
+static u16 __find_equiv_id(unsigned int cpu)
 {
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-       int i = 0;
-
-       if (!equiv_cpu_table)
-               return 0;
-
-       while (equiv_cpu_table[i].installed_cpu != 0) {
-               if (uci->cpu_sig.sig == equiv_cpu_table[i].installed_cpu)
-                       return equiv_cpu_table[i].equiv_cpu;
-
-               i++;
-       }
-       return 0;
+       return find_equiv_id(equiv_cpu_table, uci->cpu_sig.sig);
 }
 
 static u32 find_cpu_family_by_equiv_cpu(u16 equiv_cpu)
@@ -163,7 +116,7 @@ static struct ucode_patch *find_patch(unsigned int cpu)
 {
        u16 equiv_id;
 
-       equiv_id = find_equiv_id(cpu);
+       equiv_id = __find_equiv_id(cpu);
        if (!equiv_id)
                return NULL;
 
@@ -173,9 +126,20 @@ static struct ucode_patch *find_patch(unsigned int cpu)
 static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
 {
        struct cpuinfo_x86 *c = &cpu_data(cpu);
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       struct ucode_patch *p;
 
        csig->sig = cpuid_eax(0x00000001);
        csig->rev = c->microcode;
+
+       /*
+        * a patch could have been loaded early, set uci->mc so that
+        * mc_bp_resume() can call apply_microcode()
+        */
+       p = find_patch(cpu);
+       if (p && (p->patch_id == csig->rev))
+               uci->mc = p->data;
+
        pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev);
 
        return 0;
@@ -215,7 +179,21 @@ static unsigned int verify_patch_size(int cpu, u32 patch_size,
        return patch_size;
 }
 
-static int apply_microcode_amd(int cpu)
+int __apply_microcode_amd(struct microcode_amd *mc_amd)
+{
+       u32 rev, dummy;
+
+       wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);
+
+       /* verify patch application was successful */
+       rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
+       if (rev != mc_amd->hdr.patch_id)
+               return -1;
+
+       return 0;
+}
+
+int apply_microcode_amd(int cpu)
 {
        struct cpuinfo_x86 *c = &cpu_data(cpu);
        struct microcode_amd *mc_amd;
@@ -242,19 +220,15 @@ static int apply_microcode_amd(int cpu)
                return 0;
        }
 
-       wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);
-
-       /* verify patch application was successful */
-       rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
-       if (rev != mc_amd->hdr.patch_id) {
+       if (__apply_microcode_amd(mc_amd))
                pr_err("CPU%d: update failed for patch_level=0x%08x\n",
-                      cpu, mc_amd->hdr.patch_id);
-               return -1;
-       }
+                       cpu, mc_amd->hdr.patch_id);
+       else
+               pr_info("CPU%d: new patch_level=0x%08x\n", cpu,
+                       mc_amd->hdr.patch_id);
 
-       pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev);
-       uci->cpu_sig.rev = rev;
-       c->microcode = rev;
+       uci->cpu_sig.rev = mc_amd->hdr.patch_id;
+       c->microcode = mc_amd->hdr.patch_id;
 
        return 0;
 }
@@ -364,7 +338,7 @@ static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover)
        return crnt_size;
 }
 
-static enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
+static enum ucode_state __load_microcode_amd(int cpu, const u8 *data, size_t size)
 {
        enum ucode_state ret = UCODE_ERROR;
        unsigned int leftover;
@@ -398,6 +372,32 @@ static enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
        return UCODE_OK;
 }
 
+enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
+{
+       enum ucode_state ret;
+
+       /* free old equiv table */
+       free_equiv_cpu_table();
+
+       ret = __load_microcode_amd(cpu, data, size);
+
+       if (ret != UCODE_OK)
+               cleanup();
+
+#if defined(CONFIG_MICROCODE_AMD_EARLY) && defined(CONFIG_X86_32)
+       /* save BSP's matching patch for early load */
+       if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
+               struct ucode_patch *p = find_patch(cpu);
+               if (p) {
+                       memset(amd_bsp_mpb, 0, MPB_MAX_SIZE);
+                       memcpy(amd_bsp_mpb, p->data, min_t(u32, ksize(p->data),
+                                                          MPB_MAX_SIZE));
+               }
+       }
+#endif
+       return ret;
+}
+
 /*
  * AMD microcode firmware naming convention, up to family 15h they are in
  * the legacy file:
@@ -440,12 +440,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
                goto fw_release;
        }
 
-       /* free old equiv table */
-       free_equiv_cpu_table();
-
        ret = load_microcode_amd(cpu, fw->data, fw->size);
-       if (ret != UCODE_OK)
-               cleanup();
 
  fw_release:
        release_firmware(fw);
diff --git a/arch/x86/kernel/microcode_amd_early.c b/arch/x86/kernel/microcode_amd_early.c
new file mode 100644 (file)
index 0000000..1ac6e9a
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ *
+ * Author: Jacob Shin <jacob.shin@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/earlycpio.h>
+#include <linux/initrd.h>
+
+#include <asm/cpu.h>
+#include <asm/setup.h>
+#include <asm/microcode_amd.h>
+
+static bool ucode_loaded;
+static u32 ucode_new_rev;
+static unsigned long ucode_offset;
+static size_t ucode_size;
+
+/*
+ * Microcode patch container file is prepended to the initrd in cpio format.
+ * See Documentation/x86/early-microcode.txt
+ */
+static __initdata char ucode_path[] = "kernel/x86/microcode/AuthenticAMD.bin";
+
+static struct cpio_data __init find_ucode_in_initrd(void)
+{
+       long offset = 0;
+       char *path;
+       void *start;
+       size_t size;
+       unsigned long *uoffset;
+       size_t *usize;
+       struct cpio_data cd;
+
+#ifdef CONFIG_X86_32
+       struct boot_params *p;
+
+       /*
+        * On 32-bit, early load occurs before paging is turned on so we need
+        * to use physical addresses.
+        */
+       p       = (struct boot_params *)__pa_nodebug(&boot_params);
+       path    = (char *)__pa_nodebug(ucode_path);
+       start   = (void *)p->hdr.ramdisk_image;
+       size    = p->hdr.ramdisk_size;
+       uoffset = (unsigned long *)__pa_nodebug(&ucode_offset);
+       usize   = (size_t *)__pa_nodebug(&ucode_size);
+#else
+       path    = ucode_path;
+       start   = (void *)(boot_params.hdr.ramdisk_image + PAGE_OFFSET);
+       size    = boot_params.hdr.ramdisk_size;
+       uoffset = &ucode_offset;
+       usize   = &ucode_size;
+#endif
+
+       cd = find_cpio_data(path, start, size, &offset);
+       if (!cd.data)
+               return cd;
+
+       if (*(u32 *)cd.data != UCODE_MAGIC) {
+               cd.data = NULL;
+               cd.size = 0;
+               return cd;
+       }
+
+       *uoffset = (u8 *)cd.data - (u8 *)start;
+       *usize   = cd.size;
+
+       return cd;
+}
+
+/*
+ * Early load occurs before we can vmalloc(). So we look for the microcode
+ * patch container file in initrd, traverse equivalent cpu table, look for a
+ * matching microcode patch, and update, all in initrd memory in place.
+ * When vmalloc() is available for use later -- on 64-bit during first AP load,
+ * and on 32-bit during save_microcode_in_initrd_amd() -- we can call
+ * load_microcode_amd() to save equivalent cpu table and microcode patches in
+ * kernel heap memory.
+ */
+static void __cpuinit apply_ucode_in_initrd(void *ucode, size_t size)
+{
+       struct equiv_cpu_entry *eq;
+       u32 *header;
+       u8  *data;
+       u16 eq_id = 0;
+       int offset, left;
+       u32 rev, eax;
+       u32 *new_rev;
+       unsigned long *uoffset;
+       size_t *usize;
+
+#ifdef CONFIG_X86_32
+       new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
+       uoffset = (unsigned long *)__pa_nodebug(&ucode_offset);
+       usize   = (size_t *)__pa_nodebug(&ucode_size);
+#else
+       new_rev = &ucode_new_rev;
+       uoffset = &ucode_offset;
+       usize   = &ucode_size;
+#endif
+
+       data   = ucode;
+       left   = size;
+       header = (u32 *)data;
+
+       /* find equiv cpu table */
+
+       if (header[1] != UCODE_EQUIV_CPU_TABLE_TYPE || /* type */
+           header[2] == 0)                            /* size */
+               return;
+
+       eax = cpuid_eax(0x00000001);
+
+       while (left > 0) {
+               eq = (struct equiv_cpu_entry *)(data + CONTAINER_HDR_SZ);
+
+               offset = header[2] + CONTAINER_HDR_SZ;
+               data  += offset;
+               left  -= offset;
+
+               eq_id = find_equiv_id(eq, eax);
+               if (eq_id)
+                       break;
+
+               /*
+                * support multiple container files appended together. if this
+                * one does not have a matching equivalent cpu entry, we fast
+                * forward to the next container file.
+                */
+               while (left > 0) {
+                       header = (u32 *)data;
+                       if (header[0] == UCODE_MAGIC &&
+                           header[1] == UCODE_EQUIV_CPU_TABLE_TYPE)
+                               break;
+
+                       offset = header[1] + SECTION_HDR_SIZE;
+                       data  += offset;
+                       left  -= offset;
+               }
+
+               /* mark where the next microcode container file starts */
+               offset    = data - (u8 *)ucode;
+               *uoffset += offset;
+               *usize   -= offset;
+               ucode     = data;
+       }
+
+       if (!eq_id) {
+               *usize = 0;
+               return;
+       }
+
+       /* find ucode and update if needed */
+
+       rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
+
+       while (left > 0) {
+               struct microcode_amd *mc;
+
+               header = (u32 *)data;
+               if (header[0] != UCODE_UCODE_TYPE || /* type */
+                   header[1] == 0)                  /* size */
+                       break;
+
+               mc = (struct microcode_amd *)(data + SECTION_HDR_SIZE);
+               if (eq_id == mc->hdr.processor_rev_id && rev < mc->hdr.patch_id)
+                       if (__apply_microcode_amd(mc) == 0) {
+                               rev = mc->hdr.patch_id;
+                               *new_rev = rev;
+                       }
+
+               offset  = header[1] + SECTION_HDR_SIZE;
+               data   += offset;
+               left   -= offset;
+       }
+
+       /* mark where this microcode container file ends */
+       offset  = *usize - (data - (u8 *)ucode);
+       *usize -= offset;
+
+       if (!(*new_rev))
+               *usize = 0;
+}
+
+void __init load_ucode_amd_bsp(void)
+{
+       struct cpio_data cd = find_ucode_in_initrd();
+       if (!cd.data)
+               return;
+
+       apply_ucode_in_initrd(cd.data, cd.size);
+}
+
+#ifdef CONFIG_X86_32
+u8 amd_bsp_mpb[MPB_MAX_SIZE];
+
+/*
+ * On 32-bit, since AP's early load occurs before paging is turned on, we
+ * cannot traverse cpu_equiv_table and pcache in kernel heap memory. So during
+ * cold boot, AP will apply_ucode_in_initrd() just like the BSP. During
+ * save_microcode_in_initrd_amd() BSP's patch is copied to amd_bsp_mpb, which
+ * is used upon resume from suspend.
+ */
+void __cpuinit load_ucode_amd_ap(void)
+{
+       struct microcode_amd *mc;
+       unsigned long *initrd;
+       unsigned long *uoffset;
+       size_t *usize;
+       void *ucode;
+
+       mc = (struct microcode_amd *)__pa(amd_bsp_mpb);
+       if (mc->hdr.patch_id && mc->hdr.processor_rev_id) {
+               __apply_microcode_amd(mc);
+               return;
+       }
+
+       initrd  = (unsigned long *)__pa(&initrd_start);
+       uoffset = (unsigned long *)__pa(&ucode_offset);
+       usize   = (size_t *)__pa(&ucode_size);
+
+       if (!*usize || !*initrd)
+               return;
+
+       ucode = (void *)((unsigned long)__pa(*initrd) + *uoffset);
+       apply_ucode_in_initrd(ucode, *usize);
+}
+
+static void __init collect_cpu_sig_on_bsp(void *arg)
+{
+       unsigned int cpu = smp_processor_id();
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       uci->cpu_sig.sig = cpuid_eax(0x00000001);
+}
+#else
+static void __cpuinit collect_cpu_info_amd_early(struct cpuinfo_x86 *c,
+                                                struct ucode_cpu_info *uci)
+{
+       u32 rev, eax;
+
+       rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
+       eax = cpuid_eax(0x00000001);
+
+       uci->cpu_sig.sig = eax;
+       uci->cpu_sig.rev = rev;
+       c->microcode = rev;
+       c->x86 = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
+}
+
+void __cpuinit load_ucode_amd_ap(void)
+{
+       unsigned int cpu = smp_processor_id();
+
+       collect_cpu_info_amd_early(&cpu_data(cpu), ucode_cpu_info + cpu);
+
+       if (cpu && !ucode_loaded) {
+               void *ucode;
+
+               if (!ucode_size || !initrd_start)
+                       return;
+
+               ucode = (void *)(initrd_start + ucode_offset);
+               if (load_microcode_amd(0, ucode, ucode_size) != UCODE_OK)
+                       return;
+               ucode_loaded = true;
+       }
+
+       apply_microcode_amd(cpu);
+}
+#endif
+
+int __init save_microcode_in_initrd_amd(void)
+{
+       enum ucode_state ret;
+       void *ucode;
+#ifdef CONFIG_X86_32
+       unsigned int bsp = boot_cpu_data.cpu_index;
+       struct ucode_cpu_info *uci = ucode_cpu_info + bsp;
+
+       if (!uci->cpu_sig.sig)
+               smp_call_function_single(bsp, collect_cpu_sig_on_bsp, NULL, 1);
+#endif
+       if (ucode_new_rev)
+               pr_info("microcode: updated early to new patch_level=0x%08x\n",
+                       ucode_new_rev);
+
+       if (ucode_loaded || !ucode_size || !initrd_start)
+               return 0;
+
+       ucode = (void *)(initrd_start + ucode_offset);
+       ret = load_microcode_amd(0, ucode, ucode_size);
+       if (ret != UCODE_OK)
+               return -EINVAL;
+
+       ucode_loaded = true;
+       return 0;
+}
index 833d51d6ee065b908fa70ac1075a3acf6d2721a4..86119f63db0ce0fbecc41b7357fa108f37860416 100644 (file)
@@ -18,6 +18,7 @@
  */
 #include <linux/module.h>
 #include <asm/microcode_intel.h>
+#include <asm/microcode_amd.h>
 #include <asm/processor.h>
 
 #define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
@@ -81,8 +82,18 @@ void __init load_ucode_bsp(void)
        vendor = x86_vendor();
        x86 = x86_family();
 
-       if (vendor == X86_VENDOR_INTEL && x86 >= 6)
-               load_ucode_intel_bsp();
+       switch (vendor) {
+       case X86_VENDOR_INTEL:
+               if (x86 >= 6)
+                       load_ucode_intel_bsp();
+               break;
+       case X86_VENDOR_AMD:
+               if (x86 >= 0x10)
+                       load_ucode_amd_bsp();
+               break;
+       default:
+               break;
+       }
 }
 
 void __cpuinit load_ucode_ap(void)
@@ -95,6 +106,36 @@ void __cpuinit load_ucode_ap(void)
        vendor = x86_vendor();
        x86 = x86_family();
 
-       if (vendor == X86_VENDOR_INTEL && x86 >= 6)
-               load_ucode_intel_ap();
+       switch (vendor) {
+       case X86_VENDOR_INTEL:
+               if (x86 >= 6)
+                       load_ucode_intel_ap();
+               break;
+       case X86_VENDOR_AMD:
+               if (x86 >= 0x10)
+                       load_ucode_amd_ap();
+               break;
+       default:
+               break;
+       }
+}
+
+int __init save_microcode_in_initrd(void)
+{
+       struct cpuinfo_x86 *c = &boot_cpu_data;
+
+       switch (c->x86_vendor) {
+       case X86_VENDOR_INTEL:
+               if (c->x86 >= 6)
+                       save_microcode_in_initrd_intel();
+               break;
+       case X86_VENDOR_AMD:
+               if (c->x86 >= 0x10)
+                       save_microcode_in_initrd_amd();
+               break;
+       default:
+               break;
+       }
+
+       return 0;
 }
index 2e9e12871c2b51a9fe48068369f8dd4346a4db51..dabef95506f39e23c58fa74a177736eccd62ccb6 100644 (file)
@@ -529,7 +529,7 @@ int save_mc_for_early(u8 *mc)
         */
        ret = save_microcode(&mc_saved_data, mc_saved_tmp, mc_saved_count);
        if (ret) {
-               pr_err("Can not save microcode patch.\n");
+               pr_err("Cannot save microcode patch.\n");
                goto out;
        }
 
@@ -699,7 +699,7 @@ static int __cpuinit apply_microcode_early(struct mc_saved_data *mc_saved_data,
  * This function converts microcode patch offsets previously stored in
  * mc_saved_in_initrd to pointers and stores the pointers in mc_saved_data.
  */
-int __init save_microcode_in_initrd(void)
+int __init save_microcode_in_initrd_intel(void)
 {
        unsigned int count = mc_saved_data.mc_saved_count;
        struct microcode_intel *mc_saved[MAX_UCODE_COUNT];
@@ -711,7 +711,7 @@ int __init save_microcode_in_initrd(void)
        microcode_pointer(mc_saved, mc_saved_in_initrd, initrd_start, count);
        ret = save_microcode(&mc_saved_data, mc_saved, count);
        if (ret)
-               pr_err("Can not save microcod patches from initrd");
+               pr_err("Cannot save microcode patches from initrd.\n");
 
        show_saved_mc();
 
index 60308053fdb2aeb2aaaa35112096e3b23a8dc2f8..0920212e6159a27b552925e7f26d5efa584d0440 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 #include <linux/nmi.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/hardirq.h>
 #include <linux/slab.h>
@@ -29,6 +30,9 @@
 #include <asm/nmi.h>
 #include <asm/x86_init.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/nmi.h>
+
 struct nmi_desc {
        spinlock_t lock;
        struct list_head head;
@@ -82,6 +86,15 @@ __setup("unknown_nmi_panic", setup_unknown_nmi_panic);
 
 #define nmi_to_desc(type) (&nmi_desc[type])
 
+static u64 nmi_longest_ns = 1 * NSEC_PER_MSEC;
+static int __init nmi_warning_debugfs(void)
+{
+       debugfs_create_u64("nmi_longest_ns", 0644,
+                       arch_debugfs_dir, &nmi_longest_ns);
+       return 0;
+}
+fs_initcall(nmi_warning_debugfs);
+
 static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b)
 {
        struct nmi_desc *desc = nmi_to_desc(type);
@@ -96,8 +109,27 @@ static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2
         * can be latched at any given time.  Walk the whole list
         * to handle those situations.
         */
-       list_for_each_entry_rcu(a, &desc->head, list)
-               handled += a->handler(type, regs);
+       list_for_each_entry_rcu(a, &desc->head, list) {
+               u64 before, delta, whole_msecs;
+               int decimal_msecs, thishandled;
+
+               before = local_clock();
+               thishandled = a->handler(type, regs);
+               handled += thishandled;
+               delta = local_clock() - before;
+               trace_nmi_handler(a->handler, (int)delta, thishandled);
+
+               if (delta < nmi_longest_ns)
+                       continue;
+
+               nmi_longest_ns = delta;
+               whole_msecs = do_div(delta, (1000 * 1000));
+               decimal_msecs = do_div(delta, 1000) % 1000;
+               printk_ratelimited(KERN_INFO
+                       "INFO: NMI handler (%ps) took too long to run: "
+                       "%lld.%03d msecs\n", a->handler, whole_msecs,
+                       decimal_msecs);
+       }
 
        rcu_read_unlock();
 
index 7305f7dfc7abe7ef46875a9028556de99f73e79e..f8adefca71dc34e4eb800f76689eb38003e5e07e 100644 (file)
@@ -110,11 +110,16 @@ void __show_regs(struct pt_regs *regs, int all)
        get_debugreg(d1, 1);
        get_debugreg(d2, 2);
        get_debugreg(d3, 3);
-       printk(KERN_DEFAULT "DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n",
-                       d0, d1, d2, d3);
-
        get_debugreg(d6, 6);
        get_debugreg(d7, 7);
+
+       /* Only print out debug registers if they are in their non-default state. */
+       if ((d0 == 0) && (d1 == 0) && (d2 == 0) && (d3 == 0) &&
+           (d6 == DR6_RESERVED) && (d7 == 0x400))
+               return;
+
+       printk(KERN_DEFAULT "DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n",
+                       d0, d1, d2, d3);
        printk(KERN_DEFAULT "DR6: %08lx DR7: %08lx\n",
                        d6, d7);
 }
@@ -147,7 +152,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
                childregs->bp = arg;
                childregs->orig_ax = -1;
                childregs->cs = __KERNEL_CS | get_kernel_rpl();
-               childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;
+               childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
                p->fpu_counter = 0;
                p->thread.io_bitmap_ptr = NULL;
                memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
index 355ae06dbf94f4fb6de52a126a73f2570a8dad72..05646bab4ca6addf3a4026ce40685480a4336582 100644 (file)
@@ -105,11 +105,18 @@ void __show_regs(struct pt_regs *regs, int all)
        get_debugreg(d0, 0);
        get_debugreg(d1, 1);
        get_debugreg(d2, 2);
-       printk(KERN_DEFAULT "DR0: %016lx DR1: %016lx DR2: %016lx\n", d0, d1, d2);
        get_debugreg(d3, 3);
        get_debugreg(d6, 6);
        get_debugreg(d7, 7);
+
+       /* Only print out debug registers if they are in their non-default state. */
+       if ((d0 == 0) && (d1 == 0) && (d2 == 0) && (d3 == 0) &&
+           (d6 == DR6_RESERVED) && (d7 == 0x400))
+               return;
+
+       printk(KERN_DEFAULT "DR0: %016lx DR1: %016lx DR2: %016lx\n", d0, d1, d2);
        printk(KERN_DEFAULT "DR3: %016lx DR6: %016lx DR7: %016lx\n", d3, d6, d7);
+
 }
 
 void release_thread(struct task_struct *dead_task)
@@ -176,7 +183,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
                childregs->bp = arg;
                childregs->orig_ax = -1;
                childregs->cs = __KERNEL_CS | get_kernel_rpl();
-               childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;
+               childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
                return 0;
        }
        *childregs = *current_pt_regs();
index 36818f8ec2be08dd8ccdc6872992e5877eba40cd..e13f8e7c22a68c3d9590b8deb69e116d2f625f68 100644 (file)
@@ -186,7 +186,7 @@ identity_mapped:
        movl    CP_PA_PGD(%ebx), %eax
        movl    %eax, %cr3
        movl    %cr0, %eax
-       orl     $(1<<31), %eax
+       orl     $X86_CR0_PG, %eax
        movl    %eax, %cr0
        lea     PAGE_SIZE(%edi), %esp
        movl    %edi, %eax
index f2bb9c96720ace7ac54b6a1fc713cb5a002d7379..3fd2c693e4752d01e071de68ef57e2db8b47b605 100644 (file)
@@ -151,21 +151,21 @@ identity_mapped:
 
        testq   %r11, %r11
        jnz 1f
-       xorq    %rax, %rax
-       xorq    %rbx, %rbx
-       xorq    %rcx, %rcx
-       xorq    %rdx, %rdx
-       xorq    %rsi, %rsi
-       xorq    %rdi, %rdi
-       xorq    %rbp, %rbp
-       xorq    %r8,  %r8
-       xorq    %r9,  %r9
-       xorq    %r10, %r10
-       xorq    %r11, %r11
-       xorq    %r12, %r12
-       xorq    %r13, %r13
-       xorq    %r14, %r14
-       xorq    %r15, %r15
+       xorl    %eax, %eax
+       xorl    %ebx, %ebx
+       xorl    %ecx, %ecx
+       xorl    %edx, %edx
+       xorl    %esi, %esi
+       xorl    %edi, %edi
+       xorl    %ebp, %ebp
+       xorl    %r8d, %r8d
+       xorl    %r9d, %r9d
+       xorl    %r10d, %r10d
+       xorl    %r11d, %r11d
+       xorl    %r12d, %r12d
+       xorl    %r13d, %r13d
+       xorl    %r14d, %r14d
+       xorl    %r15d, %r15d
 
        ret
 
@@ -212,8 +212,8 @@ virtual_mapped:
        /* Do the copies */
 swap_pages:
        movq    %rdi, %rcx      /* Put the page_list in %rcx */
-       xorq    %rdi, %rdi
-       xorq    %rsi, %rsi
+       xorl    %edi, %edi
+       xorl    %esi, %esi
        jmp     1f
 
 0:     /* top, read another word for the indirection page */
index 56f7fcfe7fa268d558b6032fdc52643add1d1232..e68709da8251b4b7b559e4d73b8db05cdff0d47d 100644 (file)
@@ -1040,8 +1040,6 @@ void __init setup_arch(char **cmdline_p)
        /* max_low_pfn get updated here */
        find_low_pfn_range();
 #else
-       num_physpages = max_pfn;
-
        check_x2apic();
 
        /* How many end-of-memory variables you have, grandma! */
index 69562992e457456eaa4a861de85f6faf4eba8278..cf913587d4dd3674fe1f04ab8588e805fc7caa85 100644 (file)
 
 #include <asm/sigframe.h>
 
-#ifdef CONFIG_X86_32
-# define FIX_EFLAGS    (__FIX_EFLAGS | X86_EFLAGS_RF)
-#else
-# define FIX_EFLAGS    __FIX_EFLAGS
-#endif
-
 #define COPY(x)                        do {                    \
        get_user_ex(regs->x, &sc->x);                   \
 } while (0)
@@ -668,15 +662,17 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
        if (!failed) {
                /*
                 * Clear the direction flag as per the ABI for function entry.
-                */
-               regs->flags &= ~X86_EFLAGS_DF;
-               /*
+                *
+                * Clear RF when entering the signal handler, because
+                * it might disable possible debug exception from the
+                * signal handler.
+                *
                 * Clear TF when entering the signal handler, but
                 * notify any tracer that was single-stepping it.
                 * The tracer may want to single-step inside the
                 * handler too.
                 */
-               regs->flags &= ~X86_EFLAGS_TF;
+               regs->flags &= ~(X86_EFLAGS_DF|X86_EFLAGS_RF|X86_EFLAGS_TF);
        }
        signal_setup_done(failed, ksig, test_thread_flag(TIF_SINGLESTEP));
 }
index 48d2b7ded4222cfc008a997f5e2d054830c023a1..f4fe0b8879e0e79eaecf1c4aeda245d6d0ab0b70 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/proto.h>
 #include <asm/apic.h>
 #include <asm/nmi.h>
+#include <asm/trace/irq_vectors.h>
 /*
  *     Some notes on x86 processor bugs affecting SMP operation:
  *
@@ -249,32 +250,80 @@ finish:
 /*
  * Reschedule call back.
  */
-void smp_reschedule_interrupt(struct pt_regs *regs)
+static inline void __smp_reschedule_interrupt(void)
 {
-       ack_APIC_irq();
        inc_irq_stat(irq_resched_count);
        scheduler_ipi();
+}
+
+void smp_reschedule_interrupt(struct pt_regs *regs)
+{
+       ack_APIC_irq();
+       __smp_reschedule_interrupt();
        /*
         * KVM uses this interrupt to force a cpu out of guest mode
         */
 }
 
-void smp_call_function_interrupt(struct pt_regs *regs)
+void smp_trace_reschedule_interrupt(struct pt_regs *regs)
+{
+       ack_APIC_irq();
+       trace_reschedule_entry(RESCHEDULE_VECTOR);
+       __smp_reschedule_interrupt();
+       trace_reschedule_exit(RESCHEDULE_VECTOR);
+       /*
+        * KVM uses this interrupt to force a cpu out of guest mode
+        */
+}
+
+static inline void call_function_entering_irq(void)
 {
        ack_APIC_irq();
        irq_enter();
+}
+
+static inline void __smp_call_function_interrupt(void)
+{
        generic_smp_call_function_interrupt();
        inc_irq_stat(irq_call_count);
-       irq_exit();
 }
 
-void smp_call_function_single_interrupt(struct pt_regs *regs)
+void smp_call_function_interrupt(struct pt_regs *regs)
+{
+       call_function_entering_irq();
+       __smp_call_function_interrupt();
+       exiting_irq();
+}
+
+void smp_trace_call_function_interrupt(struct pt_regs *regs)
+{
+       call_function_entering_irq();
+       trace_call_function_entry(CALL_FUNCTION_VECTOR);
+       __smp_call_function_interrupt();
+       trace_call_function_exit(CALL_FUNCTION_VECTOR);
+       exiting_irq();
+}
+
+static inline void __smp_call_function_single_interrupt(void)
 {
-       ack_APIC_irq();
-       irq_enter();
        generic_smp_call_function_single_interrupt();
        inc_irq_stat(irq_call_count);
-       irq_exit();
+}
+
+void smp_call_function_single_interrupt(struct pt_regs *regs)
+{
+       call_function_entering_irq();
+       __smp_call_function_single_interrupt();
+       exiting_irq();
+}
+
+void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
+{
+       call_function_entering_irq();
+       trace_call_function_single_entry(CALL_FUNCTION_SINGLE_VECTOR);
+       __smp_call_function_single_interrupt();
+       trace_call_function_single_exit(CALL_FUNCTION_SINGLE_VECTOR);
+       exiting_irq();
 }
 
 static int __init nonmi_ipi_setup(char *str)
index f84fe00fad48a4e1c2273a9f46a18b47af96204c..3ff42d2f046d0dd0b73475fabcc3b82979675254 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/pfn.h>
 #include <linux/mm.h>
 #include <linux/tboot.h>
+#include <linux/debugfs.h>
 
 #include <asm/realmode.h>
 #include <asm/processor.h>
@@ -338,6 +339,73 @@ static struct notifier_block tboot_cpu_notifier __cpuinitdata =
        .notifier_call = tboot_cpu_callback,
 };
 
+#ifdef CONFIG_DEBUG_FS
+
+#define TBOOT_LOG_UUID { 0x26, 0x25, 0x19, 0xc0, 0x30, 0x6b, 0xb4, 0x4d, \
+                         0x4c, 0x84, 0xa3, 0xe9, 0x53, 0xb8, 0x81, 0x74 }
+
+#define TBOOT_SERIAL_LOG_ADDR  0x60000
+#define TBOOT_SERIAL_LOG_SIZE  0x08000
+#define LOG_MAX_SIZE_OFF       16
+#define LOG_BUF_OFF            24
+
+static uint8_t tboot_log_uuid[16] = TBOOT_LOG_UUID;
+
+static ssize_t tboot_log_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
+{
+       void __iomem *log_base;
+       u8 log_uuid[16];
+       u32 max_size;
+       void *kbuf;
+       int ret = -EFAULT;
+
+       log_base = ioremap_nocache(TBOOT_SERIAL_LOG_ADDR, TBOOT_SERIAL_LOG_SIZE);
+       if (!log_base)
+               return ret;
+
+       memcpy_fromio(log_uuid, log_base, sizeof(log_uuid));
+       if (memcmp(&tboot_log_uuid, log_uuid, sizeof(log_uuid)))
+               goto err_iounmap;
+
+       max_size = readl(log_base + LOG_MAX_SIZE_OFF);
+       if (*ppos >= max_size) {
+               ret = 0;
+               goto err_iounmap;
+       }
+
+       if (*ppos + count > max_size)
+               count = max_size - *ppos;
+
+       kbuf = kmalloc(count, GFP_KERNEL);
+       if (!kbuf) {
+               ret = -ENOMEM;
+               goto err_iounmap;
+       }
+
+       memcpy_fromio(kbuf, log_base + LOG_BUF_OFF + *ppos, count);
+       if (copy_to_user(user_buf, kbuf, count))
+               goto err_kfree;
+
+       *ppos += count;
+
+       ret = count;
+
+err_kfree:
+       kfree(kbuf);
+
+err_iounmap:
+       iounmap(log_base);
+
+       return ret;
+}
+
+static const struct file_operations tboot_log_fops = {
+       .read   = tboot_log_read,
+       .llseek = default_llseek,
+};
+
+#endif /* CONFIG_DEBUG_FS */
+
 static __init int tboot_late_init(void)
 {
        if (!tboot_enabled())
@@ -348,6 +416,11 @@ static __init int tboot_late_init(void)
        atomic_set(&ap_wfs_count, 0);
        register_hotcpu_notifier(&tboot_cpu_notifier);
 
+#ifdef CONFIG_DEBUG_FS
+       debugfs_create_file("tboot_log", S_IRUSR,
+                       arch_debugfs_dir, NULL, &tboot_log_fops);
+#endif
+
        acpi_os_set_prepare_sleep(&tboot_sleep);
        return 0;
 }
diff --git a/arch/x86/kernel/tracepoint.c b/arch/x86/kernel/tracepoint.c
new file mode 100644 (file)
index 0000000..4e584a8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Code for supporting irq vector tracepoints.
+ *
+ * Copyright (C) 2013 Seiji Aguchi <seiji.aguchi@hds.com>
+ *
+ */
+#include <asm/hw_irq.h>
+#include <asm/desc.h>
+#include <linux/atomic.h>
+
+atomic_t trace_idt_ctr = ATOMIC_INIT(0);
+struct desc_ptr trace_idt_descr = { NR_VECTORS * 16 - 1,
+                               (unsigned long) trace_idt_table };
+
+#ifndef CONFIG_X86_64
+gate_desc trace_idt_table[NR_VECTORS] __page_aligned_data
+                                       = { { { { 0, 0 } } }, };
+#endif
+
+static int trace_irq_vector_refcount;
+static DEFINE_MUTEX(irq_vector_mutex);
+
+static void set_trace_idt_ctr(int val)
+{
+       atomic_set(&trace_idt_ctr, val);
+       /* Ensure the trace_idt_ctr is set before sending IPI */
+       wmb();
+}
+
+static void switch_idt(void *arg)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       load_current_idt();
+       local_irq_restore(flags);
+}
+
+void trace_irq_vector_regfunc(void)
+{
+       mutex_lock(&irq_vector_mutex);
+       if (!trace_irq_vector_refcount) {
+               set_trace_idt_ctr(1);
+               smp_call_function(switch_idt, NULL, 0);
+               switch_idt(NULL);
+       }
+       trace_irq_vector_refcount++;
+       mutex_unlock(&irq_vector_mutex);
+}
+
+void trace_irq_vector_unregfunc(void)
+{
+       mutex_lock(&irq_vector_mutex);
+       trace_irq_vector_refcount--;
+       if (!trace_irq_vector_refcount) {
+               set_trace_idt_ctr(0);
+               smp_call_function(switch_idt, NULL, 0);
+               switch_idt(NULL);
+       }
+       mutex_unlock(&irq_vector_mutex);
+}
index 772e2a846deca5a125e06a694a6dd3ae58ceb364..b0865e88d3ccf4e272e5dbf654ff5de25492e672 100644 (file)
@@ -254,6 +254,9 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
        tsk->thread.error_code = error_code;
        tsk->thread.trap_nr = X86_TRAP_DF;
 
+#ifdef CONFIG_DOUBLEFAULT
+       df_debug(regs, error_code);
+#endif
        /*
         * This is always a kernel trap and never fixable (and thus must
         * never return).
@@ -437,7 +440,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
        /* Store the virtualized DR6 value */
        tsk->thread.debugreg6 = dr6;
 
-       if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code,
+       if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, error_code,
                                                        SIGTRAP) == NOTIFY_STOP)
                goto exit;
 
@@ -785,7 +788,7 @@ void __init trap_init(void)
        x86_init.irqs.trap_init();
 
 #ifdef CONFIG_X86_64
-       memcpy(&nmi_idt_table, &idt_table, IDT_ENTRIES * 16);
+       memcpy(&debug_idt_table, &idt_table, IDT_ENTRIES * 16);
        set_nmi_gate(X86_TRAP_DB, &debug);
        set_nmi_gate(X86_TRAP_BP, &int3);
 #endif
index ada87a329edcde71763601e19b1fc4a8c9062f3d..d6c28acdf99c19abd1f5554561b1b3030c057b3b 100644 (file)
@@ -243,7 +243,7 @@ int save_xstate_sig(void __user *buf, void __user *buf_fx, int size)
        if (!access_ok(VERIFY_WRITE, buf, size))
                return -EACCES;
 
-       if (!HAVE_HWFP)
+       if (!static_cpu_has(X86_FEATURE_FPU))
                return fpregs_soft_get(current, NULL, 0,
                        sizeof(struct user_i387_ia32_struct), NULL,
                        (struct _fpstate_ia32 __user *) buf) ? -1 : 1;
@@ -350,11 +350,10 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
        if (!used_math() && init_fpu(tsk))
                return -1;
 
-       if (!HAVE_HWFP) {
+       if (!static_cpu_has(X86_FEATURE_FPU))
                return fpregs_soft_set(current, NULL,
                                       0, sizeof(struct user_i387_ia32_struct),
                                       NULL, buf) != 0;
-       }
 
        if (use_xsave()) {
                struct _fpx_sw_bytes fx_sw_user;
index d609e1d8404852d02b9fdfeed0aa2103580b7cda..bf4fb04d011217bb13ab86661866c859ec790261 100644 (file)
@@ -5,12 +5,13 @@ CFLAGS_x86.o := -I.
 CFLAGS_svm.o := -I.
 CFLAGS_vmx.o := -I.
 
-kvm-y                  += $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
-                               coalesced_mmio.o irq_comm.o eventfd.o \
-                               irqchip.o)
-kvm-$(CONFIG_KVM_DEVICE_ASSIGNMENT)    += $(addprefix ../../../virt/kvm/, \
-                               assigned-dev.o iommu.o)
-kvm-$(CONFIG_KVM_ASYNC_PF)     += $(addprefix ../../../virt/kvm/, async_pf.o)
+KVM := ../../../virt/kvm
+
+kvm-y                  += $(KVM)/kvm_main.o $(KVM)/ioapic.o \
+                               $(KVM)/coalesced_mmio.o $(KVM)/irq_comm.o \
+                               $(KVM)/eventfd.o $(KVM)/irqchip.o
+kvm-$(CONFIG_KVM_DEVICE_ASSIGNMENT)    += $(KVM)/assigned-dev.o $(KVM)/iommu.o
+kvm-$(CONFIG_KVM_ASYNC_PF)     += $(KVM)/async_pf.o
 
 kvm-y                  += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \
                           i8254.o cpuid.o pmu.o
index 5953dcea752d08e950d62293abbdec94ae95f62b..2bc1e81045b0f20f90ad2500c3acae318de1e8ee 100644 (file)
@@ -61,6 +61,8 @@
 #define OpMem8            26ull  /* 8-bit zero extended memory operand */
 #define OpImm64           27ull  /* Sign extended 16/32/64-bit immediate */
 #define OpXLat            28ull  /* memory at BX/EBX/RBX + zero-extended AL */
+#define OpAccLo           29ull  /* Low part of extended acc (AX/AX/EAX/RAX) */
+#define OpAccHi           30ull  /* High part of extended acc (-/DX/EDX/RDX) */
 
 #define OpBits             5  /* Width of operand field */
 #define OpMask             ((1ull << OpBits) - 1)
@@ -86,6 +88,7 @@
 #define DstMem64    (OpMem64 << DstShift)
 #define DstImmUByte (OpImmUByte << DstShift)
 #define DstDX       (OpDX << DstShift)
+#define DstAccLo    (OpAccLo << DstShift)
 #define DstMask     (OpMask << DstShift)
 /* Source operand type. */
 #define SrcShift    6
 #define SrcImm64    (OpImm64 << SrcShift)
 #define SrcDX       (OpDX << SrcShift)
 #define SrcMem8     (OpMem8 << SrcShift)
+#define SrcAccHi    (OpAccHi << SrcShift)
 #define SrcMask     (OpMask << SrcShift)
 #define BitOp       (1<<11)
 #define MemAbs      (1<<12)      /* Memory operand is absolute displacement */
 /* Source 2 operand type */
 #define Src2Shift   (31)
 #define Src2None    (OpNone << Src2Shift)
+#define Src2Mem     (OpMem << Src2Shift)
 #define Src2CL      (OpCL << Src2Shift)
 #define Src2ImmByte (OpImmByte << Src2Shift)
 #define Src2One     (OpOne << Src2Shift)
 #define Avx         ((u64)1 << 43)  /* Advanced Vector Extensions */
 #define Fastop      ((u64)1 << 44)  /* Use opcode::u.fastop */
 #define NoWrite     ((u64)1 << 45)  /* No writeback */
+#define SrcWrite    ((u64)1 << 46)  /* Write back src operand */
+
+#define DstXacc     (DstAccLo | SrcAccHi | SrcWrite)
 
 #define X2(x...) x, x
 #define X3(x...) X2(x), x
 /*
  * fastop functions have a special calling convention:
  *
- * dst:    [rdx]:rax  (in/out)
- * src:    rbx        (in/out)
+ * dst:    rax        (in/out)
+ * src:    rdx        (in/out)
  * src2:   rcx        (in)
  * flags:  rflags     (in/out)
+ * ex:     rsi        (in:fastop pointer, out:zero if exception)
  *
  * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for
  * different operand sizes can be reached by calculation, rather than a jump
@@ -275,175 +284,18 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
        ctxt->regs_valid = 0;
 }
 
-/*
- * Instruction emulation:
- * Most instructions are emulated directly via a fragment of inline assembly
- * code. This allows us to save/restore EFLAGS and thus very easily pick up
- * any modified flags.
- */
-
-#if defined(CONFIG_X86_64)
-#define _LO32 "k"              /* force 32-bit operand */
-#define _STK  "%%rsp"          /* stack pointer */
-#elif defined(__i386__)
-#define _LO32 ""               /* force 32-bit operand */
-#define _STK  "%%esp"          /* stack pointer */
-#endif
-
 /*
  * These EFLAGS bits are restored from saved value during emulation, and
  * any changes are written back to the saved value after emulation.
  */
 #define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF)
 
-/* Before executing instruction: restore necessary bits in EFLAGS. */
-#define _PRE_EFLAGS(_sav, _msk, _tmp)                                  \
-       /* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); _sav &= ~_msk; */ \
-       "movl %"_sav",%"_LO32 _tmp"; "                                  \
-       "push %"_tmp"; "                                                \
-       "push %"_tmp"; "                                                \
-       "movl %"_msk",%"_LO32 _tmp"; "                                  \
-       "andl %"_LO32 _tmp",("_STK"); "                                 \
-       "pushf; "                                                       \
-       "notl %"_LO32 _tmp"; "                                          \
-       "andl %"_LO32 _tmp",("_STK"); "                                 \
-       "andl %"_LO32 _tmp","__stringify(BITS_PER_LONG/4)"("_STK"); "   \
-       "pop  %"_tmp"; "                                                \
-       "orl  %"_LO32 _tmp",("_STK"); "                                 \
-       "popf; "                                                        \
-       "pop  %"_sav"; "
-
-/* After executing instruction: write-back necessary bits in EFLAGS. */
-#define _POST_EFLAGS(_sav, _msk, _tmp) \
-       /* _sav |= EFLAGS & _msk; */            \
-       "pushf; "                               \
-       "pop  %"_tmp"; "                        \
-       "andl %"_msk",%"_LO32 _tmp"; "          \
-       "orl  %"_LO32 _tmp",%"_sav"; "
-
 #ifdef CONFIG_X86_64
 #define ON64(x) x
 #else
 #define ON64(x)
 #endif
 
-#define ____emulate_2op(ctxt, _op, _x, _y, _suffix, _dsttype)  \
-       do {                                                            \
-               __asm__ __volatile__ (                                  \
-                       _PRE_EFLAGS("0", "4", "2")                      \
-                       _op _suffix " %"_x"3,%1; "                      \
-                       _POST_EFLAGS("0", "4", "2")                     \
-                       : "=m" ((ctxt)->eflags),                        \
-                         "+q" (*(_dsttype*)&(ctxt)->dst.val),          \
-                         "=&r" (_tmp)                                  \
-                       : _y ((ctxt)->src.val), "i" (EFLAGS_MASK));     \
-       } while (0)
-
-
-/* Raw emulation: instruction has two explicit operands. */
-#define __emulate_2op_nobyte(ctxt,_op,_wx,_wy,_lx,_ly,_qx,_qy)         \
-       do {                                                            \
-               unsigned long _tmp;                                     \
-                                                                       \
-               switch ((ctxt)->dst.bytes) {                            \
-               case 2:                                                 \
-                       ____emulate_2op(ctxt,_op,_wx,_wy,"w",u16);      \
-                       break;                                          \
-               case 4:                                                 \
-                       ____emulate_2op(ctxt,_op,_lx,_ly,"l",u32);      \
-                       break;                                          \
-               case 8:                                                 \
-                       ON64(____emulate_2op(ctxt,_op,_qx,_qy,"q",u64)); \
-                       break;                                          \
-               }                                                       \
-       } while (0)
-
-#define __emulate_2op(ctxt,_op,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy)                     \
-       do {                                                                 \
-               unsigned long _tmp;                                          \
-               switch ((ctxt)->dst.bytes) {                                 \
-               case 1:                                                      \
-                       ____emulate_2op(ctxt,_op,_bx,_by,"b",u8);            \
-                       break;                                               \
-               default:                                                     \
-                       __emulate_2op_nobyte(ctxt, _op,                      \
-                                            _wx, _wy, _lx, _ly, _qx, _qy);  \
-                       break;                                               \
-               }                                                            \
-       } while (0)
-
-/* Source operand is byte-sized and may be restricted to just %cl. */
-#define emulate_2op_SrcB(ctxt, _op)                                    \
-       __emulate_2op(ctxt, _op, "b", "c", "b", "c", "b", "c", "b", "c")
-
-/* Source operand is byte, word, long or quad sized. */
-#define emulate_2op_SrcV(ctxt, _op)                                    \
-       __emulate_2op(ctxt, _op, "b", "q", "w", "r", _LO32, "r", "", "r")
-
-/* Source operand is word, long or quad sized. */
-#define emulate_2op_SrcV_nobyte(ctxt, _op)                             \
-       __emulate_2op_nobyte(ctxt, _op, "w", "r", _LO32, "r", "", "r")
-
-/* Instruction has three operands and one operand is stored in ECX register */
-#define __emulate_2op_cl(ctxt, _op, _suffix, _type)            \
-       do {                                                            \
-               unsigned long _tmp;                                     \
-               _type _clv  = (ctxt)->src2.val;                         \
-               _type _srcv = (ctxt)->src.val;                          \
-               _type _dstv = (ctxt)->dst.val;                          \
-                                                                       \
-               __asm__ __volatile__ (                                  \
-                       _PRE_EFLAGS("0", "5", "2")                      \
-                       _op _suffix " %4,%1 \n"                         \
-                       _POST_EFLAGS("0", "5", "2")                     \
-                       : "=m" ((ctxt)->eflags), "+r" (_dstv), "=&r" (_tmp) \
-                       : "c" (_clv) , "r" (_srcv), "i" (EFLAGS_MASK)   \
-                       );                                              \
-                                                                       \
-               (ctxt)->src2.val  = (unsigned long) _clv;               \
-               (ctxt)->src2.val = (unsigned long) _srcv;               \
-               (ctxt)->dst.val = (unsigned long) _dstv;                \
-       } while (0)
-
-#define emulate_2op_cl(ctxt, _op)                                      \
-       do {                                                            \
-               switch ((ctxt)->dst.bytes) {                            \
-               case 2:                                                 \
-                       __emulate_2op_cl(ctxt, _op, "w", u16);          \
-                       break;                                          \
-               case 4:                                                 \
-                       __emulate_2op_cl(ctxt, _op, "l", u32);          \
-                       break;                                          \
-               case 8:                                                 \
-                       ON64(__emulate_2op_cl(ctxt, _op, "q", ulong));  \
-                       break;                                          \
-               }                                                       \
-       } while (0)
-
-#define __emulate_1op(ctxt, _op, _suffix)                              \
-       do {                                                            \
-               unsigned long _tmp;                                     \
-                                                                       \
-               __asm__ __volatile__ (                                  \
-                       _PRE_EFLAGS("0", "3", "2")                      \
-                       _op _suffix " %1; "                             \
-                       _POST_EFLAGS("0", "3", "2")                     \
-                       : "=m" ((ctxt)->eflags), "+m" ((ctxt)->dst.val), \
-                         "=&r" (_tmp)                                  \
-                       : "i" (EFLAGS_MASK));                           \
-       } while (0)
-
-/* Instruction has only one explicit operand (no source operand). */
-#define emulate_1op(ctxt, _op)                                         \
-       do {                                                            \
-               switch ((ctxt)->dst.bytes) {                            \
-               case 1: __emulate_1op(ctxt, _op, "b"); break;           \
-               case 2: __emulate_1op(ctxt, _op, "w"); break;           \
-               case 4: __emulate_1op(ctxt, _op, "l"); break;           \
-               case 8: ON64(__emulate_1op(ctxt, _op, "q")); break;     \
-               }                                                       \
-       } while (0)
-
 static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
 
 #define FOP_ALIGN ".align " __stringify(FASTOP_SIZE) " \n\t"
@@ -462,7 +314,10 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
 #define FOPNOP() FOP_ALIGN FOP_RET
 
 #define FOP1E(op,  dst) \
-       FOP_ALIGN #op " %" #dst " \n\t" FOP_RET
+       FOP_ALIGN "10: " #op " %" #dst " \n\t" FOP_RET
+
+#define FOP1EEX(op,  dst) \
+       FOP1E(op, dst) _ASM_EXTABLE(10b, kvm_fastop_exception)
 
 #define FASTOP1(op) \
        FOP_START(op) \
@@ -472,24 +327,42 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
        ON64(FOP1E(op##q, rax)) \
        FOP_END
 
+/* 1-operand, using src2 (for MUL/DIV r/m) */
+#define FASTOP1SRC2(op, name) \
+       FOP_START(name) \
+       FOP1E(op, cl) \
+       FOP1E(op, cx) \
+       FOP1E(op, ecx) \
+       ON64(FOP1E(op, rcx)) \
+       FOP_END
+
+/* 1-operand, using src2 (for MUL/DIV r/m), with exceptions */
+#define FASTOP1SRC2EX(op, name) \
+       FOP_START(name) \
+       FOP1EEX(op, cl) \
+       FOP1EEX(op, cx) \
+       FOP1EEX(op, ecx) \
+       ON64(FOP1EEX(op, rcx)) \
+       FOP_END
+
 #define FOP2E(op,  dst, src)      \
        FOP_ALIGN #op " %" #src ", %" #dst " \n\t" FOP_RET
 
 #define FASTOP2(op) \
        FOP_START(op) \
-       FOP2E(op##b, al, bl) \
-       FOP2E(op##w, ax, bx) \
-       FOP2E(op##l, eax, ebx) \
-       ON64(FOP2E(op##q, rax, rbx)) \
+       FOP2E(op##b, al, dl) \
+       FOP2E(op##w, ax, dx) \
+       FOP2E(op##l, eax, edx) \
+       ON64(FOP2E(op##q, rax, rdx)) \
        FOP_END
 
 /* 2 operand, word only */
 #define FASTOP2W(op) \
        FOP_START(op) \
        FOPNOP() \
-       FOP2E(op##w, ax, bx) \
-       FOP2E(op##l, eax, ebx) \
-       ON64(FOP2E(op##q, rax, rbx)) \
+       FOP2E(op##w, ax, dx) \
+       FOP2E(op##l, eax, edx) \
+       ON64(FOP2E(op##q, rax, rdx)) \
        FOP_END
 
 /* 2 operand, src is CL */
@@ -508,14 +381,17 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
 #define FASTOP3WCL(op) \
        FOP_START(op) \
        FOPNOP() \
-       FOP3E(op##w, ax, bx, cl) \
-       FOP3E(op##l, eax, ebx, cl) \
-       ON64(FOP3E(op##q, rax, rbx, cl)) \
+       FOP3E(op##w, ax, dx, cl) \
+       FOP3E(op##l, eax, edx, cl) \
+       ON64(FOP3E(op##q, rax, rdx, cl)) \
        FOP_END
 
 /* Special case for SETcc - 1 instruction per cc */
 #define FOP_SETCC(op) ".align 4; " #op " %al; ret \n\t"
 
+asm(".global kvm_fastop_exception \n"
+    "kvm_fastop_exception: xor %esi, %esi; ret");
+
 FOP_START(setcc)
 FOP_SETCC(seto)
 FOP_SETCC(setno)
@@ -538,47 +414,6 @@ FOP_END;
 FOP_START(salc) "pushf; sbb %al, %al; popf \n\t" FOP_RET
 FOP_END;
 
-#define __emulate_1op_rax_rdx(ctxt, _op, _suffix, _ex)                 \
-       do {                                                            \
-               unsigned long _tmp;                                     \
-               ulong *rax = reg_rmw((ctxt), VCPU_REGS_RAX);            \
-               ulong *rdx = reg_rmw((ctxt), VCPU_REGS_RDX);            \
-                                                                       \
-               __asm__ __volatile__ (                                  \
-                       _PRE_EFLAGS("0", "5", "1")                      \
-                       "1: \n\t"                                       \
-                       _op _suffix " %6; "                             \
-                       "2: \n\t"                                       \
-                       _POST_EFLAGS("0", "5", "1")                     \
-                       ".pushsection .fixup,\"ax\" \n\t"               \
-                       "3: movb $1, %4 \n\t"                           \
-                       "jmp 2b \n\t"                                   \
-                       ".popsection \n\t"                              \
-                       _ASM_EXTABLE(1b, 3b)                            \
-                       : "=m" ((ctxt)->eflags), "=&r" (_tmp),          \
-                         "+a" (*rax), "+d" (*rdx), "+qm"(_ex)          \
-                       : "i" (EFLAGS_MASK), "m" ((ctxt)->src.val));    \
-       } while (0)
-
-/* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */
-#define emulate_1op_rax_rdx(ctxt, _op, _ex)    \
-       do {                                                            \
-               switch((ctxt)->src.bytes) {                             \
-               case 1:                                                 \
-                       __emulate_1op_rax_rdx(ctxt, _op, "b", _ex);     \
-                       break;                                          \
-               case 2:                                                 \
-                       __emulate_1op_rax_rdx(ctxt, _op, "w", _ex);     \
-                       break;                                          \
-               case 4:                                                 \
-                       __emulate_1op_rax_rdx(ctxt, _op, "l", _ex);     \
-                       break;                                          \
-               case 8: ON64(                                           \
-                       __emulate_1op_rax_rdx(ctxt, _op, "q", _ex));    \
-                       break;                                          \
-               }                                                       \
-       } while (0)
-
 static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
                                    enum x86_intercept intercept,
                                    enum x86_intercept_stage stage)
@@ -988,6 +823,11 @@ FASTOP2(xor);
 FASTOP2(cmp);
 FASTOP2(test);
 
+FASTOP1SRC2(mul, mul_ex);
+FASTOP1SRC2(imul, imul_ex);
+FASTOP1SRC2EX(div, div_ex);
+FASTOP1SRC2EX(idiv, idiv_ex);
+
 FASTOP3WCL(shld);
 FASTOP3WCL(shrd);
 
@@ -1013,6 +853,8 @@ FASTOP2W(bts);
 FASTOP2W(btr);
 FASTOP2W(btc);
 
+FASTOP2(xadd);
+
 static u8 test_cc(unsigned int condition, unsigned long flags)
 {
        u8 rc;
@@ -1726,45 +1568,42 @@ static void write_register_operand(struct operand *op)
        }
 }
 
-static int writeback(struct x86_emulate_ctxt *ctxt)
+static int writeback(struct x86_emulate_ctxt *ctxt, struct operand *op)
 {
        int rc;
 
-       if (ctxt->d & NoWrite)
-               return X86EMUL_CONTINUE;
-
-       switch (ctxt->dst.type) {
+       switch (op->type) {
        case OP_REG:
-               write_register_operand(&ctxt->dst);
+               write_register_operand(op);
                break;
        case OP_MEM:
                if (ctxt->lock_prefix)
                        rc = segmented_cmpxchg(ctxt,
-                                              ctxt->dst.addr.mem,
-                                              &ctxt->dst.orig_val,
-                                              &ctxt->dst.val,
-                                              ctxt->dst.bytes);
+                                              op->addr.mem,
+                                              &op->orig_val,
+                                              &op->val,
+                                              op->bytes);
                else
                        rc = segmented_write(ctxt,
-                                            ctxt->dst.addr.mem,
-                                            &ctxt->dst.val,
-                                            ctxt->dst.bytes);
+                                            op->addr.mem,
+                                            &op->val,
+                                            op->bytes);
                if (rc != X86EMUL_CONTINUE)
                        return rc;
                break;
        case OP_MEM_STR:
                rc = segmented_write(ctxt,
-                               ctxt->dst.addr.mem,
-                               ctxt->dst.data,
-                               ctxt->dst.bytes * ctxt->dst.count);
+                               op->addr.mem,
+                               op->data,
+                               op->bytes * op->count);
                if (rc != X86EMUL_CONTINUE)
                        return rc;
                break;
        case OP_XMM:
-               write_sse_reg(ctxt, &ctxt->dst.vec_val, ctxt->dst.addr.xmm);
+               write_sse_reg(ctxt, &op->vec_val, op->addr.xmm);
                break;
        case OP_MM:
-               write_mmx_reg(ctxt, &ctxt->dst.mm_val, ctxt->dst.addr.mm);
+               write_mmx_reg(ctxt, &op->mm_val, op->addr.mm);
                break;
        case OP_NONE:
                /* no writeback */
@@ -2117,42 +1956,6 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
        return X86EMUL_CONTINUE;
 }
 
-static int em_mul_ex(struct x86_emulate_ctxt *ctxt)
-{
-       u8 ex = 0;
-
-       emulate_1op_rax_rdx(ctxt, "mul", ex);
-       return X86EMUL_CONTINUE;
-}
-
-static int em_imul_ex(struct x86_emulate_ctxt *ctxt)
-{
-       u8 ex = 0;
-
-       emulate_1op_rax_rdx(ctxt, "imul", ex);
-       return X86EMUL_CONTINUE;
-}
-
-static int em_div_ex(struct x86_emulate_ctxt *ctxt)
-{
-       u8 de = 0;
-
-       emulate_1op_rax_rdx(ctxt, "div", de);
-       if (de)
-               return emulate_de(ctxt);
-       return X86EMUL_CONTINUE;
-}
-
-static int em_idiv_ex(struct x86_emulate_ctxt *ctxt)
-{
-       u8 de = 0;
-
-       emulate_1op_rax_rdx(ctxt, "idiv", de);
-       if (de)
-               return emulate_de(ctxt);
-       return X86EMUL_CONTINUE;
-}
-
 static int em_grp45(struct x86_emulate_ctxt *ctxt)
 {
        int rc = X86EMUL_CONTINUE;
@@ -3734,10 +3537,10 @@ static const struct opcode group3[] = {
        F(DstMem | SrcImm | NoWrite, em_test),
        F(DstMem | SrcNone | Lock, em_not),
        F(DstMem | SrcNone | Lock, em_neg),
-       I(SrcMem, em_mul_ex),
-       I(SrcMem, em_imul_ex),
-       I(SrcMem, em_div_ex),
-       I(SrcMem, em_idiv_ex),
+       F(DstXacc | Src2Mem, em_mul_ex),
+       F(DstXacc | Src2Mem, em_imul_ex),
+       F(DstXacc | Src2Mem, em_div_ex),
+       F(DstXacc | Src2Mem, em_idiv_ex),
 };
 
 static const struct opcode group4[] = {
@@ -4064,7 +3867,7 @@ static const struct opcode twobyte_table[256] = {
        F(DstReg | SrcMem | ModRM, em_bsf), F(DstReg | SrcMem | ModRM, em_bsr),
        D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
        /* 0xC0 - 0xC7 */
-       D2bv(DstMem | SrcReg | ModRM | Lock),
+       F2bv(DstMem | SrcReg | ModRM | SrcWrite | Lock, em_xadd),
        N, D(DstMem | SrcReg | ModRM | Mov),
        N, N, N, GD(0, &group9),
        /* 0xC8 - 0xCF */
@@ -4172,6 +3975,24 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op,
                fetch_register_operand(op);
                op->orig_val = op->val;
                break;
+       case OpAccLo:
+               op->type = OP_REG;
+               op->bytes = (ctxt->d & ByteOp) ? 2 : ctxt->op_bytes;
+               op->addr.reg = reg_rmw(ctxt, VCPU_REGS_RAX);
+               fetch_register_operand(op);
+               op->orig_val = op->val;
+               break;
+       case OpAccHi:
+               if (ctxt->d & ByteOp) {
+                       op->type = OP_NONE;
+                       break;
+               }
+               op->type = OP_REG;
+               op->bytes = ctxt->op_bytes;
+               op->addr.reg = reg_rmw(ctxt, VCPU_REGS_RDX);
+               fetch_register_operand(op);
+               op->orig_val = op->val;
+               break;
        case OpDI:
                op->type = OP_MEM;
                op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
@@ -4553,11 +4374,15 @@ static void fetch_possible_mmx_operand(struct x86_emulate_ctxt *ctxt,
 static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *))
 {
        ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF;
-       fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE;
+       if (!(ctxt->d & ByteOp))
+               fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE;
        asm("push %[flags]; popf; call *%[fastop]; pushf; pop %[flags]\n"
-           : "+a"(ctxt->dst.val), "+b"(ctxt->src.val), [flags]"+D"(flags)
-       : "c"(ctxt->src2.val), [fastop]"S"(fop));
+           : "+a"(ctxt->dst.val), "+d"(ctxt->src.val), [flags]"+D"(flags),
+             [fastop]"+S"(fop)
+           : "c"(ctxt->src2.val));
        ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK);
+       if (!fop) /* exception is returned in fop variable */
+               return emulate_de(ctxt);
        return X86EMUL_CONTINUE;
 }
 
@@ -4773,9 +4598,17 @@ special_insn:
                goto done;
 
 writeback:
-       rc = writeback(ctxt);
-       if (rc != X86EMUL_CONTINUE)
-               goto done;
+       if (!(ctxt->d & NoWrite)) {
+               rc = writeback(ctxt, &ctxt->dst);
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
+       }
+       if (ctxt->d & SrcWrite) {
+               BUG_ON(ctxt->src.type == OP_MEM || ctxt->src.type == OP_MEM_STR);
+               rc = writeback(ctxt, &ctxt->src);
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
+       }
 
        /*
         * restore dst type in case the decoding will be reused
@@ -4872,12 +4705,6 @@ twobyte_insn:
                ctxt->dst.val = (ctxt->src.bytes == 1) ? (s8) ctxt->src.val :
                                                        (s16) ctxt->src.val;
                break;
-       case 0xc0 ... 0xc1:     /* xadd */
-               fastop(ctxt, em_add);
-               /* Write back the register source. */
-               ctxt->src.val = ctxt->dst.orig_val;
-               write_register_operand(&ctxt->src);
-               break;
        case 0xc3:              /* movnti */
                ctxt->dst.bytes = ctxt->op_bytes;
                ctxt->dst.val = (ctxt->op_bytes == 4) ? (u32) ctxt->src.val :
index 0eee2c8b64d1cafecdf7f587dbeef5566b4449df..afc11245827cf2f39b56d14d50dacd6ea9aeb374 100644 (file)
@@ -1608,8 +1608,8 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
                return;
 
        if (atomic_read(&apic->lapic_timer.pending) > 0) {
-               if (kvm_apic_local_deliver(apic, APIC_LVTT))
-                       atomic_dec(&apic->lapic_timer.pending);
+               kvm_apic_local_deliver(apic, APIC_LVTT);
+               atomic_set(&apic->lapic_timer.pending, 0);
        }
 }
 
index 004cc87b781c2694a0f6428ef8b6614ff60711b7..0d094da49541d171e7218c7340e63dce6d35674c 100644 (file)
@@ -197,15 +197,63 @@ void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask)
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_set_mmio_spte_mask);
 
-static void mark_mmio_spte(u64 *sptep, u64 gfn, unsigned access)
+/*
+ * spte bits of bit 3 ~ bit 11 are used as low 9 bits of generation number,
+ * the bits of bits 52 ~ bit 61 are used as high 10 bits of generation
+ * number.
+ */
+#define MMIO_SPTE_GEN_LOW_SHIFT                3
+#define MMIO_SPTE_GEN_HIGH_SHIFT       52
+
+#define MMIO_GEN_SHIFT                 19
+#define MMIO_GEN_LOW_SHIFT             9
+#define MMIO_GEN_LOW_MASK              ((1 << MMIO_GEN_LOW_SHIFT) - 1)
+#define MMIO_GEN_MASK                  ((1 << MMIO_GEN_SHIFT) - 1)
+#define MMIO_MAX_GEN                   ((1 << MMIO_GEN_SHIFT) - 1)
+
+static u64 generation_mmio_spte_mask(unsigned int gen)
 {
-       struct kvm_mmu_page *sp =  page_header(__pa(sptep));
+       u64 mask;
+
+       WARN_ON(gen > MMIO_MAX_GEN);
+
+       mask = (gen & MMIO_GEN_LOW_MASK) << MMIO_SPTE_GEN_LOW_SHIFT;
+       mask |= ((u64)gen >> MMIO_GEN_LOW_SHIFT) << MMIO_SPTE_GEN_HIGH_SHIFT;
+       return mask;
+}
+
+static unsigned int get_mmio_spte_generation(u64 spte)
+{
+       unsigned int gen;
+
+       spte &= ~shadow_mmio_mask;
+
+       gen = (spte >> MMIO_SPTE_GEN_LOW_SHIFT) & MMIO_GEN_LOW_MASK;
+       gen |= (spte >> MMIO_SPTE_GEN_HIGH_SHIFT) << MMIO_GEN_LOW_SHIFT;
+       return gen;
+}
+
+static unsigned int kvm_current_mmio_generation(struct kvm *kvm)
+{
+       /*
+        * Init kvm generation close to MMIO_MAX_GEN to easily test the
+        * code of handling generation number wrap-around.
+        */
+       return (kvm_memslots(kvm)->generation +
+                     MMIO_MAX_GEN - 150) & MMIO_GEN_MASK;
+}
+
+static void mark_mmio_spte(struct kvm *kvm, u64 *sptep, u64 gfn,
+                          unsigned access)
+{
+       unsigned int gen = kvm_current_mmio_generation(kvm);
+       u64 mask = generation_mmio_spte_mask(gen);
 
        access &= ACC_WRITE_MASK | ACC_USER_MASK;
+       mask |= shadow_mmio_mask | access | gfn << PAGE_SHIFT;
 
-       sp->mmio_cached = true;
-       trace_mark_mmio_spte(sptep, gfn, access);
-       mmu_spte_set(sptep, shadow_mmio_mask | access | gfn << PAGE_SHIFT);
+       trace_mark_mmio_spte(sptep, gfn, access, gen);
+       mmu_spte_set(sptep, mask);
 }
 
 static bool is_mmio_spte(u64 spte)
@@ -215,24 +263,38 @@ static bool is_mmio_spte(u64 spte)
 
 static gfn_t get_mmio_spte_gfn(u64 spte)
 {
-       return (spte & ~shadow_mmio_mask) >> PAGE_SHIFT;
+       u64 mask = generation_mmio_spte_mask(MMIO_MAX_GEN) | shadow_mmio_mask;
+       return (spte & ~mask) >> PAGE_SHIFT;
 }
 
 static unsigned get_mmio_spte_access(u64 spte)
 {
-       return (spte & ~shadow_mmio_mask) & ~PAGE_MASK;
+       u64 mask = generation_mmio_spte_mask(MMIO_MAX_GEN) | shadow_mmio_mask;
+       return (spte & ~mask) & ~PAGE_MASK;
 }
 
-static bool set_mmio_spte(u64 *sptep, gfn_t gfn, pfn_t pfn, unsigned access)
+static bool set_mmio_spte(struct kvm *kvm, u64 *sptep, gfn_t gfn,
+                         pfn_t pfn, unsigned access)
 {
        if (unlikely(is_noslot_pfn(pfn))) {
-               mark_mmio_spte(sptep, gfn, access);
+               mark_mmio_spte(kvm, sptep, gfn, access);
                return true;
        }
 
        return false;
 }
 
+static bool check_mmio_spte(struct kvm *kvm, u64 spte)
+{
+       unsigned int kvm_gen, spte_gen;
+
+       kvm_gen = kvm_current_mmio_generation(kvm);
+       spte_gen = get_mmio_spte_generation(spte);
+
+       trace_check_mmio_spte(spte, kvm_gen, spte_gen);
+       return likely(kvm_gen == spte_gen);
+}
+
 static inline u64 rsvd_bits(int s, int e)
 {
        return ((1ULL << (e - s + 1)) - 1) << s;
@@ -404,9 +466,20 @@ static u64 __update_clear_spte_slow(u64 *sptep, u64 spte)
 /*
  * The idea using the light way get the spte on x86_32 guest is from
  * gup_get_pte(arch/x86/mm/gup.c).
- * The difference is we can not catch the spte tlb flush if we leave
- * guest mode, so we emulate it by increase clear_spte_count when spte
- * is cleared.
+ *
+ * An spte tlb flush may be pending, because kvm_set_pte_rmapp
+ * coalesces them and we are running out of the MMU lock.  Therefore
+ * we need to protect against in-progress updates of the spte.
+ *
+ * Reading the spte while an update is in progress may get the old value
+ * for the high part of the spte.  The race is fine for a present->non-present
+ * change (because the high part of the spte is ignored for non-present spte),
+ * but for a present->present change we must reread the spte.
+ *
+ * All such changes are done in two steps (present->non-present and
+ * non-present->present), hence it is enough to count the number of
+ * present->non-present updates: if it changed while reading the spte,
+ * we might have hit the race.  This is done using clear_spte_count.
  */
 static u64 __get_spte_lockless(u64 *sptep)
 {
@@ -1511,6 +1584,12 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
        if (!direct)
                sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache);
        set_page_private(virt_to_page(sp->spt), (unsigned long)sp);
+
+       /*
+        * The active_mmu_pages list is the FIFO list, do not move the
+        * page until it is zapped. kvm_zap_obsolete_pages depends on
+        * 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);
@@ -1648,6 +1727,16 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
 static void kvm_mmu_commit_zap_page(struct kvm *kvm,
                                    struct list_head *invalid_list);
 
+/*
+ * NOTE: we should pay more attention on the zapped-obsolete page
+ * (is_obsolete_sp(sp) && sp->role.invalid) when you do hash list walk
+ * since it has been deleted from active_mmu_pages but still can be found
+ * at hast list.
+ *
+ * for_each_gfn_indirect_valid_sp has skipped that kind of page and
+ * kvm_mmu_get_page(), the only user of for_each_gfn_sp(), has skipped
+ * all the obsolete pages.
+ */
 #define for_each_gfn_sp(_kvm, _sp, _gfn)                               \
        hlist_for_each_entry(_sp,                                       \
          &(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)], hash_link) \
@@ -1838,6 +1927,11 @@ static void clear_sp_write_flooding_count(u64 *spte)
        __clear_sp_write_flooding_count(sp);
 }
 
+static bool is_obsolete_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+       return unlikely(sp->mmu_valid_gen != kvm->arch.mmu_valid_gen);
+}
+
 static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                                             gfn_t gfn,
                                             gva_t gaddr,
@@ -1864,6 +1958,9 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
                role.quadrant = quadrant;
        }
        for_each_gfn_sp(vcpu->kvm, sp, gfn) {
+               if (is_obsolete_sp(vcpu->kvm, sp))
+                       continue;
+
                if (!need_sync && sp->unsync)
                        need_sync = true;
 
@@ -1900,6 +1997,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
 
                account_shadowed(vcpu->kvm, gfn);
        }
+       sp->mmu_valid_gen = vcpu->kvm->arch.mmu_valid_gen;
        init_shadow_page_table(sp);
        trace_kvm_mmu_get_page(sp, true);
        return sp;
@@ -2070,8 +2168,10 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
        ret = mmu_zap_unsync_children(kvm, sp, invalid_list);
        kvm_mmu_page_unlink_children(kvm, sp);
        kvm_mmu_unlink_parents(kvm, sp);
+
        if (!sp->role.invalid && !sp->role.direct)
                unaccount_shadowed(kvm, sp->gfn);
+
        if (sp->unsync)
                kvm_unlink_unsync_page(kvm, sp);
        if (!sp->root_count) {
@@ -2081,7 +2181,13 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
                kvm_mod_used_mmu_pages(kvm, -1);
        } else {
                list_move(&sp->link, &kvm->arch.active_mmu_pages);
-               kvm_reload_remote_mmus(kvm);
+
+               /*
+                * The obsolete pages can not be used on any vcpus.
+                * See the comments in kvm_mmu_invalidate_zap_all_pages().
+                */
+               if (!sp->role.invalid && !is_obsolete_sp(kvm, sp))
+                       kvm_reload_remote_mmus(kvm);
        }
 
        sp->role.invalid = 1;
@@ -2331,7 +2437,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
        u64 spte;
        int ret = 0;
 
-       if (set_mmio_spte(sptep, gfn, pfn, pte_access))
+       if (set_mmio_spte(vcpu->kvm, sptep, gfn, pfn, pte_access))
                return 0;
 
        spte = PT_PRESENT_MASK;
@@ -2869,22 +2975,25 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
 
        if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
                return;
-       spin_lock(&vcpu->kvm->mmu_lock);
+
        if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL &&
            (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL ||
             vcpu->arch.mmu.direct_map)) {
                hpa_t root = vcpu->arch.mmu.root_hpa;
 
+               spin_lock(&vcpu->kvm->mmu_lock);
                sp = page_header(root);
                --sp->root_count;
                if (!sp->root_count && sp->role.invalid) {
                        kvm_mmu_prepare_zap_page(vcpu->kvm, sp, &invalid_list);
                        kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
                }
-               vcpu->arch.mmu.root_hpa = INVALID_PAGE;
                spin_unlock(&vcpu->kvm->mmu_lock);
+               vcpu->arch.mmu.root_hpa = INVALID_PAGE;
                return;
        }
+
+       spin_lock(&vcpu->kvm->mmu_lock);
        for (i = 0; i < 4; ++i) {
                hpa_t root = vcpu->arch.mmu.pae_root[i];
 
@@ -3148,17 +3257,12 @@ static u64 walk_shadow_page_get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr)
        return spte;
 }
 
-/*
- * If it is a real mmio page fault, return 1 and emulat the instruction
- * directly, return 0 to let CPU fault again on the address, -1 is
- * returned if bug is detected.
- */
 int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct)
 {
        u64 spte;
 
        if (quickly_check_mmio_pf(vcpu, addr, direct))
-               return 1;
+               return RET_MMIO_PF_EMULATE;
 
        spte = walk_shadow_page_get_mmio_spte(vcpu, addr);
 
@@ -3166,12 +3270,15 @@ int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct)
                gfn_t gfn = get_mmio_spte_gfn(spte);
                unsigned access = get_mmio_spte_access(spte);
 
+               if (!check_mmio_spte(vcpu->kvm, spte))
+                       return RET_MMIO_PF_INVALID;
+
                if (direct)
                        addr = 0;
 
                trace_handle_mmio_page_fault(addr, gfn, access);
                vcpu_cache_mmio_info(vcpu, addr, gfn, access);
-               return 1;
+               return RET_MMIO_PF_EMULATE;
        }
 
        /*
@@ -3179,13 +3286,13 @@ int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct)
         * it's a BUG if the gfn is not a mmio page.
         */
        if (direct && !check_direct_spte_mmio_pf(spte))
-               return -1;
+               return RET_MMIO_PF_BUG;
 
        /*
         * If the page table is zapped by other cpus, let CPU fault again on
         * the address.
         */
-       return 0;
+       return RET_MMIO_PF_RETRY;
 }
 EXPORT_SYMBOL_GPL(handle_mmio_page_fault_common);
 
@@ -3195,7 +3302,7 @@ static int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr,
        int ret;
 
        ret = handle_mmio_page_fault_common(vcpu, addr, direct);
-       WARN_ON(ret < 0);
+       WARN_ON(ret == RET_MMIO_PF_BUG);
        return ret;
 }
 
@@ -3207,8 +3314,12 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
 
        pgprintk("%s: gva %lx error %x\n", __func__, gva, error_code);
 
-       if (unlikely(error_code & PFERR_RSVD_MASK))
-               return handle_mmio_page_fault(vcpu, gva, error_code, true);
+       if (unlikely(error_code & PFERR_RSVD_MASK)) {
+               r = handle_mmio_page_fault(vcpu, gva, error_code, true);
+
+               if (likely(r != RET_MMIO_PF_INVALID))
+                       return r;
+       }
 
        r = mmu_topup_memory_caches(vcpu);
        if (r)
@@ -3284,8 +3395,12 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
        ASSERT(vcpu);
        ASSERT(VALID_PAGE(vcpu->arch.mmu.root_hpa));
 
-       if (unlikely(error_code & PFERR_RSVD_MASK))
-               return handle_mmio_page_fault(vcpu, gpa, error_code, true);
+       if (unlikely(error_code & PFERR_RSVD_MASK)) {
+               r = handle_mmio_page_fault(vcpu, gpa, error_code, true);
+
+               if (likely(r != RET_MMIO_PF_INVALID))
+                       return r;
+       }
 
        r = mmu_topup_memory_caches(vcpu);
        if (r)
@@ -3391,8 +3506,8 @@ static inline void protect_clean_gpte(unsigned *access, unsigned gpte)
        *access &= mask;
 }
 
-static bool sync_mmio_spte(u64 *sptep, gfn_t gfn, unsigned access,
-                          int *nr_present)
+static bool sync_mmio_spte(struct kvm *kvm, u64 *sptep, gfn_t gfn,
+                          unsigned access, int *nr_present)
 {
        if (unlikely(is_mmio_spte(*sptep))) {
                if (gfn != get_mmio_spte_gfn(*sptep)) {
@@ -3401,7 +3516,7 @@ static bool sync_mmio_spte(u64 *sptep, gfn_t gfn, unsigned access,
                }
 
                (*nr_present)++;
-               mark_mmio_spte(sptep, gfn, access);
+               mark_mmio_spte(kvm, sptep, gfn, access);
                return true;
        }
 
@@ -3764,9 +3879,7 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu)
        if (r)
                goto out;
        r = mmu_alloc_roots(vcpu);
-       spin_lock(&vcpu->kvm->mmu_lock);
-       mmu_sync_roots(vcpu);
-       spin_unlock(&vcpu->kvm->mmu_lock);
+       kvm_mmu_sync_roots(vcpu);
        if (r)
                goto out;
        /* set_cr3() should ensure TLB has been flushed */
@@ -4179,39 +4292,107 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
        spin_unlock(&kvm->mmu_lock);
 }
 
-void kvm_mmu_zap_all(struct kvm *kvm)
+#define BATCH_ZAP_PAGES        10
+static void kvm_zap_obsolete_pages(struct kvm *kvm)
 {
        struct kvm_mmu_page *sp, *node;
-       LIST_HEAD(invalid_list);
+       int batch = 0;
 
-       spin_lock(&kvm->mmu_lock);
 restart:
-       list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link)
-               if (kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list))
+       list_for_each_entry_safe_reverse(sp, node,
+             &kvm->arch.active_mmu_pages, link) {
+               int ret;
+
+               /*
+                * No obsolete page exists before new created page since
+                * active_mmu_pages is the FIFO list.
+                */
+               if (!is_obsolete_sp(kvm, sp))
+                       break;
+
+               /*
+                * Since we are reversely walking the list and the invalid
+                * list will be moved to the head, skip the invalid page
+                * can help us to avoid the infinity list walking.
+                */
+               if (sp->role.invalid)
+                       continue;
+
+               /*
+                * Need not flush tlb since we only zap the sp with invalid
+                * generation number.
+                */
+               if (batch >= BATCH_ZAP_PAGES &&
+                     cond_resched_lock(&kvm->mmu_lock)) {
+                       batch = 0;
+                       goto restart;
+               }
+
+               ret = kvm_mmu_prepare_zap_page(kvm, sp,
+                               &kvm->arch.zapped_obsolete_pages);
+               batch += ret;
+
+               if (ret)
                        goto restart;
+       }
 
-       kvm_mmu_commit_zap_page(kvm, &invalid_list);
-       spin_unlock(&kvm->mmu_lock);
+       /*
+        * Should flush tlb before free page tables since lockless-walking
+        * may use the pages.
+        */
+       kvm_mmu_commit_zap_page(kvm, &kvm->arch.zapped_obsolete_pages);
 }
 
-void kvm_mmu_zap_mmio_sptes(struct kvm *kvm)
+/*
+ * Fast invalidate all shadow pages and use lock-break technique
+ * to zap obsolete pages.
+ *
+ * It's required when memslot is being deleted or VM is being
+ * destroyed, in these cases, we should ensure that KVM MMU does
+ * not use any resource of the being-deleted slot or all slots
+ * after calling the function.
+ */
+void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm)
 {
-       struct kvm_mmu_page *sp, *node;
-       LIST_HEAD(invalid_list);
-
        spin_lock(&kvm->mmu_lock);
-restart:
-       list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link) {
-               if (!sp->mmio_cached)
-                       continue;
-               if (kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list))
-                       goto restart;
-       }
+       trace_kvm_mmu_invalidate_zap_all_pages(kvm);
+       kvm->arch.mmu_valid_gen++;
 
-       kvm_mmu_commit_zap_page(kvm, &invalid_list);
+       /*
+        * Notify all vcpus to reload its shadow page table
+        * and flush TLB. Then all vcpus will switch to new
+        * shadow page table with the new mmu_valid_gen.
+        *
+        * Note: we should do this under the protection of
+        * mmu-lock, otherwise, vcpu would purge shadow page
+        * but miss tlb flush.
+        */
+       kvm_reload_remote_mmus(kvm);
+
+       kvm_zap_obsolete_pages(kvm);
        spin_unlock(&kvm->mmu_lock);
 }
 
+static bool kvm_has_zapped_obsolete_pages(struct kvm *kvm)
+{
+       return unlikely(!list_empty_careful(&kvm->arch.zapped_obsolete_pages));
+}
+
+void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm)
+{
+       /*
+        * The very rare case: if the generation-number is round,
+        * zap all shadow pages.
+        *
+        * The max value is MMIO_MAX_GEN - 1 since it is not called
+        * when mark memslot invalid.
+        */
+       if (unlikely(kvm_current_mmio_generation(kvm) >= (MMIO_MAX_GEN - 1))) {
+               printk_ratelimited(KERN_INFO "kvm: zapping shadow pages for mmio generation wraparound\n");
+               kvm_mmu_invalidate_zap_all_pages(kvm);
+       }
+}
+
 static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
 {
        struct kvm *kvm;
@@ -4240,15 +4421,23 @@ static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
                 * want to shrink a VM that only started to populate its MMU
                 * anyway.
                 */
-               if (!kvm->arch.n_used_mmu_pages)
+               if (!kvm->arch.n_used_mmu_pages &&
+                     !kvm_has_zapped_obsolete_pages(kvm))
                        continue;
 
                idx = srcu_read_lock(&kvm->srcu);
                spin_lock(&kvm->mmu_lock);
 
+               if (kvm_has_zapped_obsolete_pages(kvm)) {
+                       kvm_mmu_commit_zap_page(kvm,
+                             &kvm->arch.zapped_obsolete_pages);
+                       goto unlock;
+               }
+
                prepare_zap_oldest_mmu_page(kvm, &invalid_list);
                kvm_mmu_commit_zap_page(kvm, &invalid_list);
 
+unlock:
                spin_unlock(&kvm->mmu_lock);
                srcu_read_unlock(&kvm->srcu, idx);
 
index 2adcbc2cac6db49ad68ae47132e41fa4f7e6101b..5b59c573aba7a749ad52ed696b3402e5fd275106 100644 (file)
 
 int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]);
 void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask);
+
+/*
+ * Return values of handle_mmio_page_fault_common:
+ * RET_MMIO_PF_EMULATE: it is a real mmio page fault, emulate the instruction
+ *                     directly.
+ * RET_MMIO_PF_INVALID: invalid spte is detected then let the real page
+ *                     fault path update the mmio spte.
+ * RET_MMIO_PF_RETRY: let CPU fault again on the address.
+ * RET_MMIO_PF_BUG: bug is detected.
+ */
+enum {
+       RET_MMIO_PF_EMULATE = 1,
+       RET_MMIO_PF_INVALID = 2,
+       RET_MMIO_PF_RETRY = 0,
+       RET_MMIO_PF_BUG = -1
+};
+
 int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct);
 int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context);
 
@@ -97,4 +114,5 @@ static inline bool permission_fault(struct kvm_mmu *mmu, unsigned pte_access,
        return (mmu->permissions[pfec >> 1] >> pte_access) & 1;
 }
 
+void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm);
 #endif
index b8f6172f417434808397ae67e8ea9cc3ef8f2c71..9d2e0ffcb190989b52b89b8d42be561d8165e911 100644 (file)
@@ -7,16 +7,18 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvmmmu
 
-#define KVM_MMU_PAGE_FIELDS \
-       __field(__u64, gfn) \
-       __field(__u32, role) \
-       __field(__u32, root_count) \
+#define KVM_MMU_PAGE_FIELDS                    \
+       __field(unsigned long, mmu_valid_gen)   \
+       __field(__u64, gfn)                     \
+       __field(__u32, role)                    \
+       __field(__u32, root_count)              \
        __field(bool, unsync)
 
-#define KVM_MMU_PAGE_ASSIGN(sp)                             \
-       __entry->gfn = sp->gfn;                      \
-       __entry->role = sp->role.word;               \
-       __entry->root_count = sp->root_count;        \
+#define KVM_MMU_PAGE_ASSIGN(sp)                                \
+       __entry->mmu_valid_gen = sp->mmu_valid_gen;     \
+       __entry->gfn = sp->gfn;                         \
+       __entry->role = sp->role.word;                  \
+       __entry->root_count = sp->root_count;           \
        __entry->unsync = sp->unsync;
 
 #define KVM_MMU_PAGE_PRINTK() ({                                       \
@@ -28,8 +30,8 @@
                                                                        \
        role.word = __entry->role;                                      \
                                                                        \
-       trace_seq_printf(p, "sp gfn %llx %u%s q%u%s %s%s"               \
-                        " %snxe root %u %s%c",                         \
+       trace_seq_printf(p, "sp gen %lx gfn %llx %u%s q%u%s %s%s"       \
+                        " %snxe root %u %s%c", __entry->mmu_valid_gen, \
                         __entry->gfn, role.level,                      \
                         role.cr4_pae ? " pae" : "",                    \
                         role.quadrant,                                 \
@@ -197,23 +199,25 @@ DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_prepare_zap_page,
 
 TRACE_EVENT(
        mark_mmio_spte,
-       TP_PROTO(u64 *sptep, gfn_t gfn, unsigned access),
-       TP_ARGS(sptep, gfn, access),
+       TP_PROTO(u64 *sptep, gfn_t gfn, unsigned access, unsigned int gen),
+       TP_ARGS(sptep, gfn, access, gen),
 
        TP_STRUCT__entry(
                __field(void *, sptep)
                __field(gfn_t, gfn)
                __field(unsigned, access)
+               __field(unsigned int, gen)
        ),
 
        TP_fast_assign(
                __entry->sptep = sptep;
                __entry->gfn = gfn;
                __entry->access = access;
+               __entry->gen = gen;
        ),
 
-       TP_printk("sptep:%p gfn %llx access %x", __entry->sptep, __entry->gfn,
-                 __entry->access)
+       TP_printk("sptep:%p gfn %llx access %x gen %x", __entry->sptep,
+                 __entry->gfn, __entry->access, __entry->gen)
 );
 
 TRACE_EVENT(
@@ -274,6 +278,50 @@ TRACE_EVENT(
                  __spte_satisfied(old_spte), __spte_satisfied(new_spte)
        )
 );
+
+TRACE_EVENT(
+       kvm_mmu_invalidate_zap_all_pages,
+       TP_PROTO(struct kvm *kvm),
+       TP_ARGS(kvm),
+
+       TP_STRUCT__entry(
+               __field(unsigned long, mmu_valid_gen)
+               __field(unsigned int, mmu_used_pages)
+       ),
+
+       TP_fast_assign(
+               __entry->mmu_valid_gen = kvm->arch.mmu_valid_gen;
+               __entry->mmu_used_pages = kvm->arch.n_used_mmu_pages;
+       ),
+
+       TP_printk("kvm-mmu-valid-gen %lx used_pages %x",
+                 __entry->mmu_valid_gen, __entry->mmu_used_pages
+       )
+);
+
+
+TRACE_EVENT(
+       check_mmio_spte,
+       TP_PROTO(u64 spte, unsigned int kvm_gen, unsigned int spte_gen),
+       TP_ARGS(spte, kvm_gen, spte_gen),
+
+       TP_STRUCT__entry(
+               __field(unsigned int, kvm_gen)
+               __field(unsigned int, spte_gen)
+               __field(u64, spte)
+       ),
+
+       TP_fast_assign(
+               __entry->kvm_gen = kvm_gen;
+               __entry->spte_gen = spte_gen;
+               __entry->spte = spte;
+       ),
+
+       TP_printk("spte %llx kvm_gen %x spte-gen %x valid %d", __entry->spte,
+                 __entry->kvm_gen, __entry->spte_gen,
+                 __entry->kvm_gen == __entry->spte_gen
+       )
+);
 #endif /* _TRACE_KVMMMU_H */
 
 #undef TRACE_INCLUDE_PATH
index da20860b457a4c33bc7c17d6cece102b8b8f7216..7769699d48a80caac0e1d8402280ab1e15b99bed 100644 (file)
@@ -552,9 +552,12 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
 
        pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
 
-       if (unlikely(error_code & PFERR_RSVD_MASK))
-               return handle_mmio_page_fault(vcpu, addr, error_code,
+       if (unlikely(error_code & PFERR_RSVD_MASK)) {
+               r = handle_mmio_page_fault(vcpu, addr, error_code,
                                              mmu_is_nested(vcpu));
+               if (likely(r != RET_MMIO_PF_INVALID))
+                       return r;
+       };
 
        r = mmu_topup_memory_caches(vcpu);
        if (r)
@@ -792,7 +795,8 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
                pte_access &= gpte_access(vcpu, gpte);
                protect_clean_gpte(&pte_access, gpte);
 
-               if (sync_mmio_spte(&sp->spt[i], gfn, pte_access, &nr_present))
+               if (sync_mmio_spte(vcpu->kvm, &sp->spt[i], gfn, pte_access,
+                     &nr_present))
                        continue;
 
                if (gfn != sp->gfns[i]) {
index a14a6eaf871d9ea312d6dbcdd1bccb5a3c9846ac..c0bc80391e40a9bd1dfbf97243160ddcef61f145 100644 (file)
@@ -1026,7 +1026,10 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
                g_tsc_offset = svm->vmcb->control.tsc_offset -
                               svm->nested.hsave->control.tsc_offset;
                svm->nested.hsave->control.tsc_offset = offset;
-       }
+       } else
+               trace_kvm_write_tsc_offset(vcpu->vcpu_id,
+                                          svm->vmcb->control.tsc_offset,
+                                          offset);
 
        svm->vmcb->control.tsc_offset = offset + g_tsc_offset;
 
@@ -1044,6 +1047,11 @@ static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool ho
        svm->vmcb->control.tsc_offset += adjustment;
        if (is_guest_mode(vcpu))
                svm->nested.hsave->control.tsc_offset += adjustment;
+       else
+               trace_kvm_write_tsc_offset(vcpu->vcpu_id,
+                                    svm->vmcb->control.tsc_offset - adjustment,
+                                    svm->vmcb->control.tsc_offset);
+
        mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
 }
 
index fe5e00ed70369c129442a61df519bfe1823f6112..545245d7cc63f3128879724a1fc2811c31bdf55c 100644 (file)
@@ -756,6 +756,27 @@ TRACE_EVENT(
                  __entry->gpa_match ? "GPA" : "GVA")
 );
 
+TRACE_EVENT(kvm_write_tsc_offset,
+       TP_PROTO(unsigned int vcpu_id, __u64 previous_tsc_offset,
+                __u64 next_tsc_offset),
+       TP_ARGS(vcpu_id, previous_tsc_offset, next_tsc_offset),
+
+       TP_STRUCT__entry(
+               __field( unsigned int,  vcpu_id                         )
+               __field(        __u64,  previous_tsc_offset             )
+               __field(        __u64,  next_tsc_offset                 )
+       ),
+
+       TP_fast_assign(
+               __entry->vcpu_id                = vcpu_id;
+               __entry->previous_tsc_offset    = previous_tsc_offset;
+               __entry->next_tsc_offset        = next_tsc_offset;
+       ),
+
+       TP_printk("vcpu=%u prev=%llu next=%llu", __entry->vcpu_id,
+                 __entry->previous_tsc_offset, __entry->next_tsc_offset)
+);
+
 #ifdef CONFIG_X86_64
 
 #define host_clocks                                    \
index 260a9193955538b4fea743045b2f964b2736b24e..a7e18551c9689b5192d528ccae10ee9dbb20e84a 100644 (file)
@@ -2096,6 +2096,8 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
                        (nested_cpu_has(vmcs12, CPU_BASED_USE_TSC_OFFSETING) ?
                         vmcs12->tsc_offset : 0));
        } else {
+               trace_kvm_write_tsc_offset(vcpu->vcpu_id,
+                                          vmcs_read64(TSC_OFFSET), offset);
                vmcs_write64(TSC_OFFSET, offset);
        }
 }
@@ -2103,11 +2105,14 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
 static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool host)
 {
        u64 offset = vmcs_read64(TSC_OFFSET);
+
        vmcs_write64(TSC_OFFSET, offset + adjustment);
        if (is_guest_mode(vcpu)) {
                /* Even when running L2, the adjustment needs to apply to L1 */
                to_vmx(vcpu)->nested.vmcs01_tsc_offset += adjustment;
-       }
+       } else
+               trace_kvm_write_tsc_offset(vcpu->vcpu_id, offset,
+                                          offset + adjustment);
 }
 
 static u64 vmx_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
@@ -4176,10 +4181,10 @@ static void ept_set_mmio_spte_mask(void)
        /*
         * EPT Misconfigurations can be generated if the value of bits 2:0
         * of an EPT paging-structure entry is 110b (write/execute).
-        * Also, magic bits (0xffull << 49) is set to quickly identify mmio
+        * Also, magic bits (0x3ull << 62) is set to quickly identify mmio
         * spte.
         */
-       kvm_mmu_set_mmio_spte_mask(0xffull << 49 | 0x6ull);
+       kvm_mmu_set_mmio_spte_mask((0x3ull << 62) | 0x6ull);
 }
 
 /*
@@ -5366,10 +5371,14 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
        gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
 
        ret = handle_mmio_page_fault_common(vcpu, gpa, true);
-       if (likely(ret == 1))
+       if (likely(ret == RET_MMIO_PF_EMULATE))
                return x86_emulate_instruction(vcpu, gpa, 0, NULL, 0) ==
                                              EMULATE_DONE;
-       if (unlikely(!ret))
+
+       if (unlikely(ret == RET_MMIO_PF_INVALID))
+               return kvm_mmu_page_fault(vcpu, gpa, 0, NULL, 0);
+
+       if (unlikely(ret == RET_MMIO_PF_RETRY))
                return 1;
 
        /* It is the real ept misconfig */
@@ -7942,7 +7951,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
 
        kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->host_rsp);
        kvm_register_write(vcpu, VCPU_REGS_RIP, vmcs12->host_rip);
-       vmx_set_rflags(vcpu, X86_EFLAGS_BIT1);
+       vmx_set_rflags(vcpu, X86_EFLAGS_FIXED);
        /*
         * Note that calling vmx_set_cr0 is important, even if cr0 hasn't
         * actually changed, because it depends on the current state of
index e8ba99c341808d6069b0b4f6985b8d71ef243971..d21bce5053155535f51d1507f7f38306023eb994 100644 (file)
@@ -618,7 +618,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
        if (!guest_cpuid_has_smep(vcpu) && (cr4 & X86_CR4_SMEP))
                return 1;
 
-       if (!guest_cpuid_has_fsgsbase(vcpu) && (cr4 & X86_CR4_RDWRGSFS))
+       if (!guest_cpuid_has_fsgsbase(vcpu) && (cr4 & X86_CR4_FSGSBASE))
                return 1;
 
        if (is_long_mode(vcpu)) {
@@ -1193,20 +1193,37 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
        elapsed = ns - kvm->arch.last_tsc_nsec;
 
        if (vcpu->arch.virtual_tsc_khz) {
+               int faulted = 0;
+
                /* n.b - signed multiplication and division required */
                usdiff = data - kvm->arch.last_tsc_write;
 #ifdef CONFIG_X86_64
                usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz;
 #else
                /* do_div() only does unsigned */
-               asm("idivl %2; xor %%edx, %%edx"
-               : "=A"(usdiff)
-               : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz));
+               asm("1: idivl %[divisor]\n"
+                   "2: xor %%edx, %%edx\n"
+                   "   movl $0, %[faulted]\n"
+                   "3:\n"
+                   ".section .fixup,\"ax\"\n"
+                   "4: movl $1, %[faulted]\n"
+                   "   jmp  3b\n"
+                   ".previous\n"
+
+               _ASM_EXTABLE(1b, 4b)
+
+               : "=A"(usdiff), [faulted] "=r" (faulted)
+               : "A"(usdiff * 1000), [divisor] "rm"(vcpu->arch.virtual_tsc_khz));
+
 #endif
                do_div(elapsed, 1000);
                usdiff -= elapsed;
                if (usdiff < 0)
                        usdiff = -usdiff;
+
+               /* idivl overflow => difference is larger than USEC_PER_SEC */
+               if (faulted)
+                       usdiff = USEC_PER_SEC;
        } else
                usdiff = USEC_PER_SEC; /* disable TSC match window below */
 
@@ -1587,6 +1604,30 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
        return 0;
 }
 
+/*
+ * kvmclock updates which are isolated to a given vcpu, such as
+ * vcpu->cpu migration, should not allow system_timestamp from
+ * the rest of the vcpus to remain static. Otherwise ntp frequency
+ * correction applies to one vcpu's system_timestamp but not
+ * the others.
+ *
+ * So in those cases, request a kvmclock update for all vcpus.
+ * The worst case for a remote vcpu to update its kvmclock
+ * is then bounded by maximum nohz sleep latency.
+ */
+
+static void kvm_gen_kvmclock_update(struct kvm_vcpu *v)
+{
+       int i;
+       struct kvm *kvm = v->kvm;
+       struct kvm_vcpu *vcpu;
+
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               set_bit(KVM_REQ_CLOCK_UPDATE, &vcpu->requests);
+               kvm_vcpu_kick(vcpu);
+       }
+}
+
 static bool msr_mtrr_valid(unsigned msr)
 {
        switch (msr) {
@@ -1984,7 +2025,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                kvmclock_reset(vcpu);
 
                vcpu->arch.time = data;
-               kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+               kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
 
                /* we verify if the enable bit is set... */
                if (!(data & 1))
@@ -2701,7 +2742,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
                 * kvmclock on vcpu->cpu migration
                 */
                if (!vcpu->kvm->arch.use_master_clock || vcpu->cpu == -1)
-                       kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+                       kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
                if (vcpu->cpu != cpu)
                        kvm_migrate_timers(vcpu);
                vcpu->cpu = cpu;
@@ -5238,7 +5279,13 @@ static void kvm_set_mmio_spte_mask(void)
         * Set the reserved bits and the present bit of an paging-structure
         * entry to generate page fault with PFER.RSV = 1.
         */
-       mask = ((1ull << (62 - maxphyaddr + 1)) - 1) << maxphyaddr;
+        /* Mask the reserved physical address bits. */
+       mask = ((1ull << (51 - maxphyaddr + 1)) - 1) << maxphyaddr;
+
+       /* Bit 62 is always reserved for 32bit host. */
+       mask |= 0x3ull << 62;
+
+       /* Set the present bit. */
        mask |= 1ull;
 
 #ifdef CONFIG_X86_64
@@ -5498,13 +5545,6 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
        char instruction[3];
        unsigned long rip = kvm_rip_read(vcpu);
 
-       /*
-        * Blow out the MMU to ensure that no other VCPU has an active mapping
-        * to ensure that the updated hypercall appears atomically across all
-        * VCPUs.
-        */
-       kvm_mmu_zap_all(vcpu->kvm);
-
        kvm_x86_ops->patch_hypercall(vcpu, instruction);
 
        return emulator_write_emulated(ctxt, rip, instruction, 3, NULL);
@@ -5702,6 +5742,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                        __kvm_migrate_timers(vcpu);
                if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))
                        kvm_gen_update_masterclock(vcpu->kvm);
+               if (kvm_check_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu))
+                       kvm_gen_kvmclock_update(vcpu);
                if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) {
                        r = kvm_guest_time_update(vcpu);
                        if (unlikely(r))
@@ -6812,6 +6854,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
                return -EINVAL;
 
        INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
+       INIT_LIST_HEAD(&kvm->arch.zapped_obsolete_pages);
        INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
 
        /* Reserve bit 0 of irq_sources_bitmap for userspace irq source */
@@ -7040,22 +7083,18 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
         * If memory slot is created, or moved, we need to clear all
         * mmio sptes.
         */
-       if ((change == KVM_MR_CREATE) || (change == KVM_MR_MOVE)) {
-               kvm_mmu_zap_mmio_sptes(kvm);
-               kvm_reload_remote_mmus(kvm);
-       }
+       kvm_mmu_invalidate_mmio_sptes(kvm);
 }
 
 void kvm_arch_flush_shadow_all(struct kvm *kvm)
 {
-       kvm_mmu_zap_all(kvm);
-       kvm_reload_remote_mmus(kvm);
+       kvm_mmu_invalidate_zap_all_pages(kvm);
 }
 
 void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
                                   struct kvm_memory_slot *slot)
 {
-       kvm_arch_flush_shadow_all(kvm);
+       kvm_mmu_invalidate_zap_all_pages(kvm);
 }
 
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
@@ -7263,3 +7302,4 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_intr_vmexit);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_invlpga);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_skinit);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_intercepts);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_write_tsc_offset);
index 94e0e54056a9bcbf71e0bbe0abcf9db495da22ae..8f38d577a2fae42e3cecb6309d835798b46e4947 100644 (file)
@@ -1,2 +1,2 @@
-obj-y          := i386_head.o boot.o
+obj-y          := head_32.o boot.o
 CFLAGS_boot.o  := $(call cc-option, -fno-stack-protector)
index 7114c63f047d06432a453884c4500474ea9681ea..d482bcaf61c182d7daac37a4c833303dd38eb658 100644 (file)
@@ -1410,7 +1410,7 @@ __init void lguest_init(void)
        new_cpu_data.x86_capability[0] = cpuid_edx(1);
 
        /* Math is always hard! */
-       new_cpu_data.hard_math = 1;
+       set_cpu_cap(&new_cpu_data, X86_FEATURE_FPU);
 
        /* We don't have features.  We have puppies!  Puppies! */
 #ifdef CONFIG_X86_MCE
index 252b8f5489ba6e1b84152545d211ba31121ffb7f..4500142bc4aa46429cb2be41a7ee3407426f6155 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/swap.h> /* for totalram_pages */
+#include <linux/bootmem.h>
 
 void *kmap(struct page *page)
 {
@@ -121,6 +122,11 @@ void __init set_highmem_pages_init(void)
        struct zone *zone;
        int nid;
 
+       /*
+        * Explicitly reset zone->managed_pages because set_highmem_pages_init()
+        * is invoked before free_all_bootmem()
+        */
+       reset_all_zones_managed_pages();
        for_each_zone(zone) {
                unsigned long zone_start_pfn, zone_end_pfn;
 
index ae1aa71d0115f8ef2509e8ae4a1789385446df18..7e73e8c690966dccbd8a7ef9f3d5397a367828f1 100644 (file)
 #include <asm/tlbflush.h>
 #include <asm/pgalloc.h>
 
-static unsigned long page_table_shareable(struct vm_area_struct *svma,
-                               struct vm_area_struct *vma,
-                               unsigned long addr, pgoff_t idx)
-{
-       unsigned long saddr = ((idx - svma->vm_pgoff) << PAGE_SHIFT) +
-                               svma->vm_start;
-       unsigned long sbase = saddr & PUD_MASK;
-       unsigned long s_end = sbase + PUD_SIZE;
-
-       /* Allow segments to share if only one is marked locked */
-       unsigned long vm_flags = vma->vm_flags & ~VM_LOCKED;
-       unsigned long svm_flags = svma->vm_flags & ~VM_LOCKED;
-
-       /*
-        * match the virtual addresses, permission and the alignment of the
-        * page table page.
-        */
-       if (pmd_index(addr) != pmd_index(saddr) ||
-           vm_flags != svm_flags ||
-           sbase < svma->vm_start || svma->vm_end < s_end)
-               return 0;
-
-       return saddr;
-}
-
-static int vma_shareable(struct vm_area_struct *vma, unsigned long addr)
-{
-       unsigned long base = addr & PUD_MASK;
-       unsigned long end = base + PUD_SIZE;
-
-       /*
-        * check on proper vm_flags and page table alignment
-        */
-       if (vma->vm_flags & VM_MAYSHARE &&
-           vma->vm_start <= base && end <= vma->vm_end)
-               return 1;
-       return 0;
-}
-
-/*
- * Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc()
- * and returns the corresponding pte. While this is not necessary for the
- * !shared pmd case because we can allocate the pmd later as well, it makes the
- * code much cleaner. pmd allocation is essential for the shared case because
- * pud has to be populated inside the same i_mmap_mutex section - otherwise
- * racing tasks could either miss the sharing (see huge_pte_offset) or select a
- * bad pmd for sharing.
- */
-static pte_t *
-huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
-{
-       struct vm_area_struct *vma = find_vma(mm, addr);
-       struct address_space *mapping = vma->vm_file->f_mapping;
-       pgoff_t idx = ((addr - vma->vm_start) >> PAGE_SHIFT) +
-                       vma->vm_pgoff;
-       struct vm_area_struct *svma;
-       unsigned long saddr;
-       pte_t *spte = NULL;
-       pte_t *pte;
-
-       if (!vma_shareable(vma, addr))
-               return (pte_t *)pmd_alloc(mm, pud, addr);
-
-       mutex_lock(&mapping->i_mmap_mutex);
-       vma_interval_tree_foreach(svma, &mapping->i_mmap, idx, idx) {
-               if (svma == vma)
-                       continue;
-
-               saddr = page_table_shareable(svma, vma, addr, idx);
-               if (saddr) {
-                       spte = huge_pte_offset(svma->vm_mm, saddr);
-                       if (spte) {
-                               get_page(virt_to_page(spte));
-                               break;
-                       }
-               }
-       }
-
-       if (!spte)
-               goto out;
-
-       spin_lock(&mm->page_table_lock);
-       if (pud_none(*pud))
-               pud_populate(mm, pud, (pmd_t *)((unsigned long)spte & PAGE_MASK));
-       else
-               put_page(virt_to_page(spte));
-       spin_unlock(&mm->page_table_lock);
-out:
-       pte = (pte_t *)pmd_alloc(mm, pud, addr);
-       mutex_unlock(&mapping->i_mmap_mutex);
-       return pte;
-}
-
-/*
- * unmap huge page backed by shared pte.
- *
- * Hugetlb pte page is ref counted at the time of mapping.  If pte is shared
- * indicated by page_count > 1, unmap is achieved by clearing pud and
- * decrementing the ref count. If count == 1, the pte page is not shared.
- *
- * called with vma->vm_mm->page_table_lock held.
- *
- * returns: 1 successfully unmapped a shared pte page
- *         0 the underlying pte page is not shared, or it is the last user
- */
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
-       pgd_t *pgd = pgd_offset(mm, *addr);
-       pud_t *pud = pud_offset(pgd, *addr);
-
-       BUG_ON(page_count(virt_to_page(ptep)) == 0);
-       if (page_count(virt_to_page(ptep)) == 1)
-               return 0;
-
-       pud_clear(pud);
-       put_page(virt_to_page(ptep));
-       *addr = ALIGN(*addr, HPAGE_SIZE * PTRS_PER_PTE) - HPAGE_SIZE;
-       return 1;
-}
-
-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;
-
-       pgd = pgd_offset(mm, addr);
-       pud = pud_alloc(mm, pgd, addr);
-       if (pud) {
-               if (sz == PUD_SIZE) {
-                       pte = (pte_t *)pud;
-               } else {
-                       BUG_ON(sz != PMD_SIZE);
-                       if (pud_none(*pud))
-                               pte = huge_pmd_share(mm, addr, pud);
-                       else
-                               pte = (pte_t *)pmd_alloc(mm, pud, addr);
-               }
-       }
-       BUG_ON(pte && !pte_none(*pte) && !pte_huge(*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;
-
-       pgd = pgd_offset(mm, addr);
-       if (pgd_present(*pgd)) {
-               pud = pud_offset(pgd, addr);
-               if (pud_present(*pud)) {
-                       if (pud_large(*pud))
-                               return (pte_t *)pud;
-                       pmd = pmd_offset(pud, addr);
-               }
-       }
-       return (pte_t *) pmd;
-}
-
 #if 0  /* This is just for testing */
 struct page *
 follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
@@ -240,30 +77,6 @@ int pud_huge(pud_t pud)
        return !!(pud_val(pud) & _PAGE_PSE);
 }
 
-struct page *
-follow_huge_pmd(struct mm_struct *mm, unsigned long address,
-               pmd_t *pmd, int write)
-{
-       struct page *page;
-
-       page = pte_page(*(pte_t *)pmd);
-       if (page)
-               page += ((address & ~PMD_MASK) >> PAGE_SHIFT);
-       return page;
-}
-
-struct page *
-follow_huge_pud(struct mm_struct *mm, unsigned long address,
-               pud_t *pud, int write)
-{
-       struct page *page;
-
-       page = pte_page(*(pte_t *)pud);
-       if (page)
-               page += ((address & ~PUD_MASK) >> PAGE_SHIFT);
-       return page;
-}
-
 #endif
 
 /* x86_64 also uses this file */
index 1f34e9219775b2251c72cbb3234fef0ebec600f3..2ec29ac78ae6b76b47f6496d67830770bdac7275 100644 (file)
@@ -494,7 +494,6 @@ int devmem_is_allowed(unsigned long pagenr)
 
 void free_init_pages(char *what, unsigned long begin, unsigned long end)
 {
-       unsigned long addr;
        unsigned long begin_aligned, end_aligned;
 
        /* Make sure boundaries are page aligned */
@@ -509,8 +508,6 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
        if (begin >= end)
                return;
 
-       addr = begin;
-
        /*
         * If debugging page accesses then do not free this memory but
         * mark them not present - any buggy init-section access will
@@ -529,18 +526,13 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
        set_memory_nx(begin, (end - begin) >> PAGE_SHIFT);
        set_memory_rw(begin, (end - begin) >> PAGE_SHIFT);
 
-       printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
-
-       for (; addr < end; addr += PAGE_SIZE) {
-               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
-               free_reserved_page(virt_to_page(addr));
-       }
+       free_reserved_area((void *)begin, (void *)end, POISON_FREE_INITMEM, what);
 #endif
 }
 
 void free_initmem(void)
 {
-       free_init_pages("unused kernel memory",
+       free_init_pages("unused kernel",
                        (unsigned long)(&__init_begin),
                        (unsigned long)(&__init_end));
 }
@@ -566,7 +558,7 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
         *   - relocate_initrd()
         * So here We can do PAGE_ALIGN() safely to get partial page to be freed
         */
-       free_init_pages("initrd memory", start, PAGE_ALIGN(end));
+       free_init_pages("initrd", start, PAGE_ALIGN(end));
 }
 #endif
 
index 3ac7e319918d413bef5a48bfd38740dc9aa34118..4287f1ffba7ef2e42cc68839a38c3ecc0d6b1304 100644 (file)
@@ -660,10 +660,8 @@ void __init initmem_init(void)
                highstart_pfn = max_low_pfn;
        printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
                pages_to_mb(highend_pfn - highstart_pfn));
-       num_physpages = highend_pfn;
        high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
 #else
-       num_physpages = max_low_pfn;
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
 #endif
 
@@ -671,7 +669,7 @@ void __init initmem_init(void)
        sparse_memory_present_with_active_regions(0);
 
 #ifdef CONFIG_FLATMEM
-       max_mapnr = num_physpages;
+       max_mapnr = IS_ENABLED(CONFIG_HIGHMEM) ? highend_pfn : max_low_pfn;
 #endif
        __vmalloc_start_set = true;
 
@@ -739,9 +737,6 @@ static void __init test_wp_bit(void)
 
 void __init mem_init(void)
 {
-       int codesize, reservedpages, datasize, initsize;
-       int tmp;
-
        pci_iommu_alloc();
 
 #ifdef CONFIG_FLATMEM
@@ -759,32 +754,11 @@ void __init mem_init(void)
        set_highmem_pages_init();
 
        /* this will put all low memory onto the freelists */
-       totalram_pages += free_all_bootmem();
-
-       reservedpages = 0;
-       for (tmp = 0; tmp < max_low_pfn; tmp++)
-               /*
-                * Only count reserved RAM pages:
-                */
-               if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
-                       reservedpages++;
+       free_all_bootmem();
 
        after_bootmem = 1;
 
-       codesize =  (unsigned long) &_etext - (unsigned long) &_text;
-       datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
-       initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
-       printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
-                       "%dk reserved, %dk data, %dk init, %ldk highmem)\n",
-               nr_free_pages() << (PAGE_SHIFT-10),
-               num_physpages << (PAGE_SHIFT-10),
-               codesize >> 10,
-               reservedpages << (PAGE_SHIFT-10),
-               datasize >> 10,
-               initsize >> 10,
-               totalhigh_pages << (PAGE_SHIFT-10));
-
+       mem_init_print_info(NULL);
        printk(KERN_INFO "virtual kernel memory layout:\n"
                "    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #ifdef CONFIG_HIGHMEM
index bb00c4672ad64462b6b3a4e687df6174e68e8ed9..104d56a9245f1ea071009dc49e3bd25a2c48383b 100644 (file)
@@ -368,7 +368,7 @@ void __init init_extra_mapping_uc(unsigned long phys, unsigned long size)
  *
  *   from __START_KERNEL_map to __START_KERNEL_map + size (== _end-_text)
  *
- * phys_addr holds the negative offset to the kernel, which is added
+ * phys_base holds the negative offset to the kernel, which is added
  * to the compile time generated pmds. This results in invalid pmds up
  * to the point where we hit the physaddr 0 mapping.
  *
@@ -712,36 +712,22 @@ EXPORT_SYMBOL_GPL(arch_add_memory);
 
 static void __meminit free_pagetable(struct page *page, int order)
 {
-       struct zone *zone;
-       bool bootmem = false;
        unsigned long magic;
        unsigned int nr_pages = 1 << order;
 
        /* bootmem page has reserved flag */
        if (PageReserved(page)) {
                __ClearPageReserved(page);
-               bootmem = true;
 
                magic = (unsigned long)page->lru.next;
                if (magic == SECTION_INFO || magic == MIX_SECTION_INFO) {
                        while (nr_pages--)
                                put_page_bootmem(page++);
                } else
-                       __free_pages_bootmem(page, order);
+                       while (nr_pages--)
+                               free_reserved_page(page++);
        } else
                free_pages((unsigned long)page_address(page), order);
-
-       /*
-        * SECTION_INFO pages and MIX_SECTION_INFO pages
-        * are all allocated by bootmem.
-        */
-       if (bootmem) {
-               zone = page_zone(page);
-               zone_span_writelock(zone);
-               zone->present_pages += nr_pages;
-               zone_span_writeunlock(zone);
-               totalram_pages += nr_pages;
-       }
 }
 
 static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd)
@@ -1058,9 +1044,6 @@ static void __init register_page_bootmem_info(void)
 
 void __init mem_init(void)
 {
-       long codesize, reservedpages, datasize, initsize;
-       unsigned long absent_pages;
-
        pci_iommu_alloc();
 
        /* clear_bss() already clear the empty_zero_page */
@@ -1068,29 +1051,14 @@ void __init mem_init(void)
        register_page_bootmem_info();
 
        /* this will put all memory onto the freelists */
-       totalram_pages = free_all_bootmem();
-
-       absent_pages = absent_pages_in_range(0, max_pfn);
-       reservedpages = max_pfn - totalram_pages - absent_pages;
+       free_all_bootmem();
        after_bootmem = 1;
 
-       codesize =  (unsigned long) &_etext - (unsigned long) &_text;
-       datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
-       initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
        /* Register memory areas for /proc/kcore */
        kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START,
                         VSYSCALL_END - VSYSCALL_START, KCORE_OTHER);
 
-       printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
-                        "%ldk absent, %ldk reserved, %ldk data, %ldk init)\n",
-               nr_free_pages() << (PAGE_SHIFT-10),
-               max_pfn << (PAGE_SHIFT-10),
-               codesize >> 10,
-               absent_pages << (PAGE_SHIFT-10),
-               reservedpages << (PAGE_SHIFT-10),
-               datasize >> 10,
-               initsize >> 10);
+       mem_init_print_info(NULL);
 }
 
 #ifdef CONFIG_DEBUG_RODATA
@@ -1166,11 +1134,10 @@ void mark_rodata_ro(void)
        set_memory_ro(start, (end-start) >> PAGE_SHIFT);
 #endif
 
-       free_init_pages("unused kernel memory",
+       free_init_pages("unused kernel",
                        (unsigned long) __va(__pa_symbol(text_end)),
                        (unsigned long) __va(__pa_symbol(rodata_start)));
-
-       free_init_pages("unused kernel memory",
+       free_init_pages("unused kernel",
                        (unsigned long) __va(__pa_symbol(rodata_end)),
                        (unsigned long) __va(__pa_symbol(_sdata)));
 }
index 9a1e6583910c2e5ada549f52ff8dcb19639c3cd3..0215e2c563ef5bbbaebd0e4f2666023f0afdef1d 100644 (file)
@@ -501,15 +501,15 @@ __early_ioremap(resource_size_t phys_addr, unsigned long size, pgprot_t prot)
        }
 
        if (slot < 0) {
-               printk(KERN_INFO "early_iomap(%08llx, %08lx) not found slot\n",
-                        (u64)phys_addr, size);
+               printk(KERN_INFO "%s(%08llx, %08lx) not found slot\n",
+                      __func__, (u64)phys_addr, size);
                WARN_ON(1);
                return NULL;
        }
 
        if (early_ioremap_debug) {
-               printk(KERN_INFO "early_ioremap(%08llx, %08lx) [%d] => ",
-                      (u64)phys_addr, size, slot);
+               printk(KERN_INFO "%s(%08llx, %08lx) [%d] => ",
+                      __func__, (u64)phys_addr, size, slot);
                dump_stack();
        }
 
index 73a6d7395bd355630d6d00abf5c9d4730fd83766..0342d27ca7986924d9ed8c68f21a88bec982ed89 100644 (file)
@@ -83,10 +83,8 @@ void __init initmem_init(void)
                highstart_pfn = max_low_pfn;
        printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
               pages_to_mb(highend_pfn - highstart_pfn));
-       num_physpages = highend_pfn;
        high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
 #else
-       num_physpages = max_low_pfn;
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
 #endif
        printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
index 3e724256dbee6b0bb4d2e4156522a08e3bd480e4..d641897a1f4e5d53a5f14ec3e25b7517fe3d8b9f 100644 (file)
@@ -324,14 +324,11 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
        res->start = start;
        res->end = end;
        info->res_offset[info->res_num] = addr.translation_offset;
+       info->res_num++;
 
-       if (!pci_use_crs) {
+       if (!pci_use_crs)
                dev_printk(KERN_DEBUG, &info->bridge->dev,
                           "host bridge window %pR (ignored)\n", res);
-               return AE_OK;
-       }
-
-       info->res_num++;
 
        return AE_OK;
 }
index d2fbcedcf6eaf2fd77179075c1be2c5c4d3d8347..b410b71bdcf767fc97fbb8f08dcaed1ea46f4c1f 100644 (file)
@@ -929,6 +929,13 @@ void __init efi_enter_virtual_mode(void)
                        va = efi_ioremap(md->phys_addr, size,
                                         md->type, md->attribute);
 
+               if (!(md->attribute & EFI_MEMORY_RUNTIME)) {
+                       if (!va)
+                               pr_err("ioremap of 0x%llX failed!\n",
+                                      (unsigned long long)md->phys_addr);
+                       continue;
+               }
+
                md->virt_addr = (u64) (unsigned long) va;
 
                if (!va) {
index 0faad646f5fda8eb40c64a95e685c2c919daadf6..d6bfb876cfb02d86c19dc4d18956957437209972 100644 (file)
@@ -372,7 +372,7 @@ subsys_initcall(sysenter_setup);
 /* Register vsyscall32 into the ABI table */
 #include <linux/sysctl.h>
 
-static ctl_table abi_table2[] = {
+static struct ctl_table abi_table2[] = {
        {
                .procname       = "vsyscall32",
                .data           = &sysctl_vsyscall32,
@@ -383,7 +383,7 @@ static ctl_table abi_table2[] = {
        {}
 };
 
-static ctl_table abi_root_table2[] = {
+static struct ctl_table abi_root_table2[] = {
        {
                .procname = "abi",
                .mode = 0555,
index a492be2635ac048a527d856b796431ccac72d9fd..2fa02bc50034773290712429f6593af6051614fa 100644 (file)
@@ -1557,7 +1557,7 @@ asmlinkage void __init xen_start_kernel(void)
 #ifdef CONFIG_X86_32
        /* set up basic CPUID stuff */
        cpu_detect(&new_cpu_data);
-       new_cpu_data.hard_math = 1;
+       set_cpu_cap(&new_cpu_data, X86_FEATURE_FPU);
        new_cpu_data.wp_works_ok = 1;
        new_cpu_data.x86_capability[0] = cpuid_edx(1);
 #endif
index d99cae8147d1243b84faa111bcd74b447e5ff7ec..c1367b29c3b13c7b1a796aaee8cfa101c90689fa 100644 (file)
 
 cpumask_var_t xen_cpu_initialized_map;
 
-static DEFINE_PER_CPU(int, xen_resched_irq);
-static DEFINE_PER_CPU(int, xen_callfunc_irq);
-static DEFINE_PER_CPU(int, xen_callfuncsingle_irq);
-static DEFINE_PER_CPU(int, xen_irq_work);
-static DEFINE_PER_CPU(int, xen_debug_irq) = -1;
+struct xen_common_irq {
+       int irq;
+       char *name;
+};
+static DEFINE_PER_CPU(struct xen_common_irq, xen_resched_irq) = { .irq = -1 };
+static DEFINE_PER_CPU(struct xen_common_irq, xen_callfunc_irq) = { .irq = -1 };
+static DEFINE_PER_CPU(struct xen_common_irq, xen_callfuncsingle_irq) = { .irq = -1 };
+static DEFINE_PER_CPU(struct xen_common_irq, xen_irq_work) = { .irq = -1 };
+static DEFINE_PER_CPU(struct xen_common_irq, xen_debug_irq) = { .irq = -1 };
 
 static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
 static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
@@ -99,10 +103,47 @@ static void __cpuinit cpu_bringup_and_idle(void)
        cpu_startup_entry(CPUHP_ONLINE);
 }
 
+static void xen_smp_intr_free(unsigned int cpu)
+{
+       if (per_cpu(xen_resched_irq, cpu).irq >= 0) {
+               unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu).irq, NULL);
+               per_cpu(xen_resched_irq, cpu).irq = -1;
+               kfree(per_cpu(xen_resched_irq, cpu).name);
+               per_cpu(xen_resched_irq, cpu).name = NULL;
+       }
+       if (per_cpu(xen_callfunc_irq, cpu).irq >= 0) {
+               unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu).irq, NULL);
+               per_cpu(xen_callfunc_irq, cpu).irq = -1;
+               kfree(per_cpu(xen_callfunc_irq, cpu).name);
+               per_cpu(xen_callfunc_irq, cpu).name = NULL;
+       }
+       if (per_cpu(xen_debug_irq, cpu).irq >= 0) {
+               unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu).irq, NULL);
+               per_cpu(xen_debug_irq, cpu).irq = -1;
+               kfree(per_cpu(xen_debug_irq, cpu).name);
+               per_cpu(xen_debug_irq, cpu).name = NULL;
+       }
+       if (per_cpu(xen_callfuncsingle_irq, cpu).irq >= 0) {
+               unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu).irq,
+                                      NULL);
+               per_cpu(xen_callfuncsingle_irq, cpu).irq = -1;
+               kfree(per_cpu(xen_callfuncsingle_irq, cpu).name);
+               per_cpu(xen_callfuncsingle_irq, cpu).name = NULL;
+       }
+       if (xen_hvm_domain())
+               return;
+
+       if (per_cpu(xen_irq_work, cpu).irq >= 0) {
+               unbind_from_irqhandler(per_cpu(xen_irq_work, cpu).irq, NULL);
+               per_cpu(xen_irq_work, cpu).irq = -1;
+               kfree(per_cpu(xen_irq_work, cpu).name);
+               per_cpu(xen_irq_work, cpu).name = NULL;
+       }
+};
 static int xen_smp_intr_init(unsigned int cpu)
 {
        int rc;
-       const char *resched_name, *callfunc_name, *debug_name;
+       char *resched_name, *callfunc_name, *debug_name;
 
        resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
        rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
@@ -113,7 +154,8 @@ static int xen_smp_intr_init(unsigned int cpu)
                                    NULL);
        if (rc < 0)
                goto fail;
-       per_cpu(xen_resched_irq, cpu) = rc;
+       per_cpu(xen_resched_irq, cpu).irq = rc;
+       per_cpu(xen_resched_irq, cpu).name = resched_name;
 
        callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
        rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
@@ -124,7 +166,8 @@ static int xen_smp_intr_init(unsigned int cpu)
                                    NULL);
        if (rc < 0)
                goto fail;
-       per_cpu(xen_callfunc_irq, cpu) = rc;
+       per_cpu(xen_callfunc_irq, cpu).irq = rc;
+       per_cpu(xen_callfunc_irq, cpu).name = callfunc_name;
 
        debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
        rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu, xen_debug_interrupt,
@@ -132,7 +175,8 @@ static int xen_smp_intr_init(unsigned int cpu)
                                     debug_name, NULL);
        if (rc < 0)
                goto fail;
-       per_cpu(xen_debug_irq, cpu) = rc;
+       per_cpu(xen_debug_irq, cpu).irq = rc;
+       per_cpu(xen_debug_irq, cpu).name = debug_name;
 
        callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
        rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
@@ -143,7 +187,8 @@ static int xen_smp_intr_init(unsigned int cpu)
                                    NULL);
        if (rc < 0)
                goto fail;
-       per_cpu(xen_callfuncsingle_irq, cpu) = rc;
+       per_cpu(xen_callfuncsingle_irq, cpu).irq = rc;
+       per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name;
 
        /*
         * The IRQ worker on PVHVM goes through the native path and uses the
@@ -161,26 +206,13 @@ static int xen_smp_intr_init(unsigned int cpu)
                                    NULL);
        if (rc < 0)
                goto fail;
-       per_cpu(xen_irq_work, cpu) = rc;
+       per_cpu(xen_irq_work, cpu).irq = rc;
+       per_cpu(xen_irq_work, cpu).name = callfunc_name;
 
        return 0;
 
  fail:
-       if (per_cpu(xen_resched_irq, cpu) >= 0)
-               unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
-       if (per_cpu(xen_callfunc_irq, cpu) >= 0)
-               unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
-       if (per_cpu(xen_debug_irq, cpu) >= 0)
-               unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
-       if (per_cpu(xen_callfuncsingle_irq, cpu) >= 0)
-               unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu),
-                                      NULL);
-       if (xen_hvm_domain())
-               return rc;
-
-       if (per_cpu(xen_irq_work, cpu) >= 0)
-               unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
-
+       xen_smp_intr_free(cpu);
        return rc;
 }
 
@@ -433,12 +465,7 @@ static void xen_cpu_die(unsigned int cpu)
                current->state = TASK_UNINTERRUPTIBLE;
                schedule_timeout(HZ/10);
        }
-       unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
-       unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
-       if (!xen_hvm_domain())
-               unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
+       xen_smp_intr_free(cpu);
        xen_uninit_lock_cpu(cpu);
        xen_teardown_timer(cpu);
 }
index 3002ec1bb71a27d193ce4b1e041f8b3a3c5b49fa..a40f8508e760d0259e6016903be5fdb1e5d69aa9 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/debugfs.h>
 #include <linux/log2.h>
 #include <linux/gfp.h>
+#include <linux/slab.h>
 
 #include <asm/paravirt.h>
 
@@ -165,6 +166,7 @@ static int xen_spin_trylock(struct arch_spinlock *lock)
        return old == 0;
 }
 
+static DEFINE_PER_CPU(char *, irq_name);
 static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
 static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
 
@@ -362,7 +364,7 @@ static irqreturn_t dummy_handler(int irq, void *dev_id)
 void __cpuinit xen_init_lock_cpu(int cpu)
 {
        int irq;
-       const char *name;
+       char *name;
 
        WARN(per_cpu(lock_kicker_irq, cpu) >= 0, "spinlock on CPU%d exists on IRQ%d!\n",
             cpu, per_cpu(lock_kicker_irq, cpu));
@@ -385,6 +387,7 @@ void __cpuinit xen_init_lock_cpu(int cpu)
        if (irq >= 0) {
                disable_irq(irq); /* make sure it's never delivered */
                per_cpu(lock_kicker_irq, cpu) = irq;
+               per_cpu(irq_name, cpu) = name;
        }
 
        printk("cpu %d spinlock event irq %d\n", cpu, irq);
@@ -401,6 +404,8 @@ void xen_uninit_lock_cpu(int cpu)
 
        unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
        per_cpu(lock_kicker_irq, cpu) = -1;
+       kfree(per_cpu(irq_name, cpu));
+       per_cpu(irq_name, cpu) = NULL;
 }
 
 void __init xen_init_spinlocks(void)
index 3d88bfdf9e1c092a23e9d4be143630a074a92926..a690868be837ad99407d050a1c0229d9a237adc5 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/math64.h>
 #include <linux/gfp.h>
+#include <linux/slab.h>
 
 #include <asm/pvclock.h>
 #include <asm/xen/hypervisor.h>
@@ -36,9 +37,8 @@ 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 and blocked time */
+/* unused ns of stolen time */
 static DEFINE_PER_CPU(u64, xen_residual_stolen);
-static DEFINE_PER_CPU(u64, xen_residual_blocked);
 
 /* return an consistent snapshot of 64-bit time/counter value */
 static u64 get64(const u64 *p)
@@ -115,7 +115,7 @@ static void do_stolen_accounting(void)
 {
        struct vcpu_runstate_info state;
        struct vcpu_runstate_info *snap;
-       s64 blocked, runnable, offline, stolen;
+       s64 runnable, offline, stolen;
        cputime_t ticks;
 
        get_runstate_snapshot(&state);
@@ -125,7 +125,6 @@ static void do_stolen_accounting(void)
        snap = &__get_cpu_var(xen_runstate_snapshot);
 
        /* work out how much time the VCPU has not been runn*ing*  */
-       blocked = state.time[RUNSTATE_blocked] - snap->time[RUNSTATE_blocked];
        runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable];
        offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline];
 
@@ -141,17 +140,6 @@ static void do_stolen_accounting(void)
        ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen);
        __this_cpu_write(xen_residual_stolen, stolen);
        account_steal_ticks(ticks);
-
-       /* Add the appropriate number of ticks of blocked time,
-          including any left-overs from last time. */
-       blocked += __this_cpu_read(xen_residual_blocked);
-
-       if (blocked < 0)
-               blocked = 0;
-
-       ticks = iter_div_u64_rem(blocked, NS_PER_TICK, &blocked);
-       __this_cpu_write(xen_residual_blocked, blocked);
-       account_idle_ticks(ticks);
 }
 
 /* Get the TSC speed from Xen */
@@ -377,11 +365,16 @@ static const struct clock_event_device xen_vcpuop_clockevent = {
 
 static const struct clock_event_device *xen_clockevent =
        &xen_timerop_clockevent;
-static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events) = { .irq = -1 };
+
+struct xen_clock_event_device {
+       struct clock_event_device evt;
+       char *name;
+};
+static DEFINE_PER_CPU(struct xen_clock_event_device, xen_clock_events) = { .evt.irq = -1 };
 
 static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
 {
-       struct clock_event_device *evt = &__get_cpu_var(xen_clock_events);
+       struct clock_event_device *evt = &__get_cpu_var(xen_clock_events).evt;
        irqreturn_t ret;
 
        ret = IRQ_NONE;
@@ -395,14 +388,30 @@ static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
        return ret;
 }
 
+void xen_teardown_timer(int cpu)
+{
+       struct clock_event_device *evt;
+       BUG_ON(cpu == 0);
+       evt = &per_cpu(xen_clock_events, cpu).evt;
+
+       if (evt->irq >= 0) {
+               unbind_from_irqhandler(evt->irq, NULL);
+               evt->irq = -1;
+               kfree(per_cpu(xen_clock_events, cpu).name);
+               per_cpu(xen_clock_events, cpu).name = NULL;
+       }
+}
+
 void xen_setup_timer(int cpu)
 {
-       const char *name;
+       char *name;
        struct clock_event_device *evt;
        int irq;
 
-       evt = &per_cpu(xen_clock_events, cpu);
+       evt = &per_cpu(xen_clock_events, cpu).evt;
        WARN(evt->irq >= 0, "IRQ%d for CPU%d is already allocated\n", evt->irq, cpu);
+       if (evt->irq >= 0)
+               xen_teardown_timer(cpu);
 
        printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
 
@@ -420,22 +429,15 @@ void xen_setup_timer(int cpu)
 
        evt->cpumask = cpumask_of(cpu);
        evt->irq = irq;
+       per_cpu(xen_clock_events, cpu).name = name;
 }
 
-void xen_teardown_timer(int cpu)
-{
-       struct clock_event_device *evt;
-       BUG_ON(cpu == 0);
-       evt = &per_cpu(xen_clock_events, cpu);
-       unbind_from_irqhandler(evt->irq, NULL);
-       evt->irq = -1;
-}
 
 void xen_setup_cpu_clockevents(void)
 {
        BUG_ON(preemptible());
 
-       clockevents_register_device(&__get_cpu_var(xen_clock_events));
+       clockevents_register_device(&__get_cpu_var(xen_clock_events).evt);
 }
 
 void xen_timer_resume(void)
index bba125b4bb0693172c5e50bf92b8798b27606720..479d7537a32a4f8039ae02581f8644d53eb80dda 100644 (file)
@@ -173,39 +173,16 @@ void __init zones_init(void)
 
 void __init mem_init(void)
 {
-       unsigned long codesize, reservedpages, datasize, initsize;
-       unsigned long highmemsize, tmp, ram;
-
-       max_mapnr = num_physpages = max_low_pfn - ARCH_PFN_OFFSET;
+       max_mapnr = max_low_pfn - ARCH_PFN_OFFSET;
        high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
-       highmemsize = 0;
 
 #ifdef CONFIG_HIGHMEM
 #error HIGHGMEM not implemented in init.c
 #endif
 
-       totalram_pages += free_all_bootmem();
-
-       reservedpages = ram = 0;
-       for (tmp = 0; tmp < max_mapnr; tmp++) {
-               ram++;
-               if (PageReserved(mem_map+tmp))
-                       reservedpages++;
-       }
+       free_all_bootmem();
 
-       codesize =  (unsigned long) _etext - (unsigned long) _stext;
-       datasize =  (unsigned long) _edata - (unsigned long) _sdata;
-       initsize =  (unsigned long) __init_end - (unsigned long) __init_begin;
-
-       printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, "
-              "%ldk data, %ldk init %ldk highmem)\n",
-              nr_free_pages() << (PAGE_SHIFT-10),
-              ram << (PAGE_SHIFT-10),
-              codesize >> 10,
-              reservedpages << (PAGE_SHIFT-10),
-              datasize >> 10,
-              initsize >> 10,
-              highmemsize >> 10);
+       mem_init_print_info(NULL);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -214,11 +191,11 @@ extern int initrd_is_mapped;
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
        if (initrd_is_mapped)
-               free_reserved_area(start, end, 0, "initrd");
+               free_reserved_area((void *)start, (void *)end, -1, "initrd");
 }
 #endif
 
 void free_initmem(void)
 {
-       free_initmem_default(0);
+       free_initmem_default(-1);
 }
index d5745b5833c9d76527809c41b4718c3df70407df..93a18d1d3da8e43d79b4450e30211ecb59f14b2f 100644 (file)
@@ -2315,6 +2315,9 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
                case -EBADE:
                        error_type = "critical nexus";
                        break;
+               case -ETIMEDOUT:
+                       error_type = "timeout";
+                       break;
                case -EIO:
                default:
                        error_type = "I/O";
@@ -3180,7 +3183,8 @@ int __init blk_dev_init(void)
 
        /* used for unplugging and affects IO latency/throughput - HIGHPRI */
        kblockd_workqueue = alloc_workqueue("kblockd",
-                                           WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
+                                           WQ_MEM_RECLAIM | WQ_HIGHPRI |
+                                           WQ_POWER_EFFICIENT, 0);
        if (!kblockd_workqueue)
                panic("Failed to create kblockd\n");
 
index 9c4bb8266bc80327926f0e68e3a85c2eb8315773..4464c823cff2a0f3228a2dd5d54da3c9cdcbbde4 100644 (file)
@@ -144,7 +144,8 @@ void put_io_context(struct io_context *ioc)
        if (atomic_long_dec_and_test(&ioc->refcount)) {
                spin_lock_irqsave(&ioc->lock, flags);
                if (!hlist_empty(&ioc->icq_list))
-                       schedule_work(&ioc->release_work);
+                       queue_work(system_power_efficient_wq,
+                                       &ioc->release_work);
                else
                        free_ioc = true;
                spin_unlock_irqrestore(&ioc->lock, flags);
index 6e4744cbfb56b4ca0d99062a0d9b0437c894016d..65f103563969bf32391c7bb3d6f4e4859ed1459a 100644 (file)
@@ -82,9 +82,10 @@ void blk_delete_timer(struct request *req)
 static void blk_rq_timed_out(struct request *req)
 {
        struct request_queue *q = req->q;
-       enum blk_eh_timer_return ret;
+       enum blk_eh_timer_return ret = BLK_EH_RESET_TIMER;
 
-       ret = q->rq_timed_out_fn(req);
+       if (q->rq_timed_out_fn)
+               ret = q->rq_timed_out_fn(req);
        switch (ret) {
        case BLK_EH_HANDLED:
                __blk_complete_request(req);
index 7c668c8a6f953e1b6c298c9fc8af400924d7368a..7e5d474dc6ba8a3028abe19e296d3b19a9d4bded 100644 (file)
@@ -59,6 +59,7 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
        if (!disk->fops->getgeo)
                return -ENOTTY;
 
+       memset(&geo, 0, sizeof(geo));
        /*
         * We need to set the startsect first, the driver may
         * want to override it.
index 20625eed55116555216cb594c49e4a0c36049675..dadf42b454a383299231fa46abee1631aab53196 100644 (file)
@@ -512,7 +512,7 @@ static void register_disk(struct gendisk *disk)
 
        ddev->parent = disk->driverfs_dev;
 
-       dev_set_name(ddev, disk->disk_name);
+       dev_set_name(ddev, "%s", disk->disk_name);
 
        /* delay uevents, until we scanned partition table */
        dev_set_uevent_suppress(ddev, 1);
@@ -1489,9 +1489,11 @@ static void __disk_unblock_events(struct gendisk *disk, bool check_now)
        intv = disk_events_poll_jiffies(disk);
        set_timer_slack(&ev->dwork.timer, intv / 4);
        if (check_now)
-               queue_delayed_work(system_freezable_wq, &ev->dwork, 0);
+               queue_delayed_work(system_freezable_power_efficient_wq,
+                               &ev->dwork, 0);
        else if (intv)
-               queue_delayed_work(system_freezable_wq, &ev->dwork, intv);
+               queue_delayed_work(system_freezable_power_efficient_wq,
+                               &ev->dwork, intv);
 out_unlock:
        spin_unlock_irqrestore(&ev->lock, flags);
 }
@@ -1534,7 +1536,8 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask)
        spin_lock_irq(&ev->lock);
        ev->clearing |= mask;
        if (!ev->block)
-               mod_delayed_work(system_freezable_wq, &ev->dwork, 0);
+               mod_delayed_work(system_freezable_power_efficient_wq,
+                               &ev->dwork, 0);
        spin_unlock_irq(&ev->lock);
 }
 
@@ -1627,7 +1630,8 @@ static void disk_check_events(struct disk_events *ev,
 
        intv = disk_events_poll_jiffies(disk);
        if (!ev->block && intv)
-               queue_delayed_work(system_freezable_wq, &ev->dwork, intv);
+               queue_delayed_work(system_freezable_power_efficient_wq,
+                               &ev->dwork, intv);
 
        spin_unlock_irq(&ev->lock);
 
index 6149a6e09643f0c9b975ac339dd904dd58421262..7a1ae87f1683459711c0b0c6badd1d76ddd9c9f1 100644 (file)
@@ -495,7 +495,8 @@ static struct crypto_template *__crypto_lookup_template(const char *name)
 
 struct crypto_template *crypto_lookup_template(const char *name)
 {
-       return try_then_request_module(__crypto_lookup_template(name), name);
+       return try_then_request_module(__crypto_lookup_template(name), "%s",
+                                      name);
 }
 EXPORT_SYMBOL_GPL(crypto_lookup_template);
 
index 1b11abbb5c912c2fe004eda04cd6d0244f7b8a17..f38a58aef3ecbffc2777e83d4e47309f5d00dfa2 100644 (file)
@@ -10,10 +10,6 @@ config ASYNC_XOR
        select ASYNC_CORE
        select XOR_BLOCKS
 
-config ASYNC_MEMSET
-       tristate
-       select ASYNC_CORE
-
 config ASYNC_PQ
        tristate
        select ASYNC_CORE
index d1e0e6f72bc14e651c2a9c0a1c1f7936ead53970..462e4abbfe693e2f11bc9656ed2398c1cae3bb59 100644 (file)
@@ -1,6 +1,5 @@
 obj-$(CONFIG_ASYNC_CORE) += async_tx.o
 obj-$(CONFIG_ASYNC_MEMCPY) += async_memcpy.o
-obj-$(CONFIG_ASYNC_MEMSET) += async_memset.o
 obj-$(CONFIG_ASYNC_XOR) += async_xor.o
 obj-$(CONFIG_ASYNC_PQ) += async_pq.o
 obj-$(CONFIG_ASYNC_RAID6_RECOV) += async_raid6_recov.o
diff --git a/crypto/async_tx/async_memset.c b/crypto/async_tx/async_memset.c
deleted file mode 100644 (file)
index 05a4d1e..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * memory fill offload engine support
- *
- * Copyright Â© 2006, Intel Corporation.
- *
- *      Dan Williams <dan.j.williams@intel.com>
- *
- *      with architecture considerations by:
- *      Neil Brown <neilb@suse.de>
- *      Jeff Garzik <jeff@garzik.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
-#include <linux/async_tx.h>
-
-/**
- * async_memset - attempt to fill memory with a dma engine.
- * @dest: destination page
- * @val: fill value
- * @offset: offset in pages to start transaction
- * @len: length in bytes
- *
- * honored flags: ASYNC_TX_ACK
- */
-struct dma_async_tx_descriptor *
-async_memset(struct page *dest, int val, unsigned int offset, size_t len,
-            struct async_submit_ctl *submit)
-{
-       struct dma_chan *chan = async_tx_find_channel(submit, DMA_MEMSET,
-                                                     &dest, 1, NULL, 0, len);
-       struct dma_device *device = chan ? chan->device : NULL;
-       struct dma_async_tx_descriptor *tx = NULL;
-
-       if (device && is_dma_fill_aligned(device, offset, 0, len)) {
-               dma_addr_t dma_dest;
-               unsigned long dma_prep_flags = 0;
-
-               if (submit->cb_fn)
-                       dma_prep_flags |= DMA_PREP_INTERRUPT;
-               if (submit->flags & ASYNC_TX_FENCE)
-                       dma_prep_flags |= DMA_PREP_FENCE;
-               dma_dest = dma_map_page(device->dev, dest, offset, len,
-                                       DMA_FROM_DEVICE);
-
-               tx = device->device_prep_dma_memset(chan, dma_dest, val, len,
-                                                   dma_prep_flags);
-       }
-
-       if (tx) {
-               pr_debug("%s: (async) len: %zu\n", __func__, len);
-               async_tx_submit(chan, tx, submit);
-       } else { /* run the memset synchronously */
-               void *dest_buf;
-               pr_debug("%s: (sync) len: %zu\n", __func__, len);
-
-               dest_buf = page_address(dest) + offset;
-
-               /* wait for any prerequisite operations */
-               async_tx_quiesce(&submit->depend_tx);
-
-               memset(dest_buf, val, len);
-
-               async_tx_sync_epilog(submit);
-       }
-
-       return tx;
-}
-EXPORT_SYMBOL_GPL(async_memset);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("asynchronous memset api");
-MODULE_LICENSE("GPL");
index b2c99dc1c5e2f244bab9cf8fafcedb0860df67f6..f8c920cafe639c8451349e15b3f1e22e19da80e4 100644 (file)
@@ -455,8 +455,8 @@ static int pcrypt_init_padata(struct padata_pcrypt *pcrypt,
 
        get_online_cpus();
 
-       pcrypt->wq = alloc_workqueue(name,
-                                    WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+       pcrypt->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE,
+                                    1, name);
        if (!pcrypt->wq)
                goto err;
 
index 536562c626a2fab4bb20c128abcf27f4404ca23f..81dbeb83bb45805de6b0f7e083ed3bb421eabca9 100644 (file)
@@ -34,6 +34,7 @@ acpi-$(CONFIG_ACPI_SLEEP)     += proc.o
 acpi-y                         += bus.o glue.o
 acpi-y                         += scan.o
 acpi-y                         += resource.o
+acpi-y                         += acpi_processor.o
 acpi-y                         += processor_core.o
 acpi-y                         += ec.o
 acpi-$(CONFIG_ACPI_DOCK)       += dock.o
@@ -43,6 +44,7 @@ acpi-y                                += acpi_platform.o
 acpi-y                         += power.o
 acpi-y                         += event.o
 acpi-y                         += sysfs.o
+acpi-$(CONFIG_X86)             += acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)                += debugfs.o
 acpi-$(CONFIG_ACPI_NUMA)       += numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c
new file mode 100644 (file)
index 0000000..84190ed
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * ACPI support for CMOS RTC Address Space access
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Lan Tianyu <tianyu.lan@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm-generic/rtc.h>
+
+#include "internal.h"
+
+#define PREFIX "ACPI: "
+
+ACPI_MODULE_NAME("cmos rtc");
+
+static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
+       { "PNP0B00" },
+       { "PNP0B01" },
+       { "PNP0B02" },
+       {}
+};
+
+static acpi_status
+acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address,
+                     u32 bits, u64 *value64,
+                     void *handler_context, void *region_context)
+{
+       int i;
+       u8 *value = (u8 *)&value64;
+
+       if (address > 0xff || !value64)
+               return AE_BAD_PARAMETER;
+
+       if (function != ACPI_WRITE && function != ACPI_READ)
+               return AE_BAD_PARAMETER;
+
+       spin_lock_irq(&rtc_lock);
+
+       for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value)
+               if (function == ACPI_READ)
+                       *value = CMOS_READ(address);
+               else
+                       CMOS_WRITE(*value, address);
+
+       spin_unlock_irq(&rtc_lock);
+
+       return AE_OK;
+}
+
+static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
+               const struct acpi_device_id *id)
+{
+       acpi_status status;
+
+       status = acpi_install_address_space_handler(adev->handle,
+                       ACPI_ADR_SPACE_CMOS,
+                       &acpi_cmos_rtc_space_handler,
+                       NULL, NULL);
+       if (ACPI_FAILURE(status)) {
+               pr_err(PREFIX "Error installing CMOS-RTC region handler\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)
+{
+       if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle,
+                       ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
+               pr_err(PREFIX "Error removing CMOS-RTC region handler\n");
+}
+
+static struct acpi_scan_handler cmos_rtc_handler = {
+       .ids = acpi_cmos_rtc_ids,
+       .attach = acpi_install_cmos_rtc_space_handler,
+       .detach = acpi_remove_cmos_rtc_space_handler,
+};
+
+void __init acpi_cmos_rtc_init(void)
+{
+       acpi_scan_add_handler(&cmos_rtc_handler);
+}
index cab13f2fc28e3033aaed24adbbf618199473bb28..6a382188fa20a7f2f67f8f45d506439f8e45db7b 100644 (file)
@@ -32,12 +32,26 @@ ACPI_MODULE_NAME("acpi_lpss");
 #define LPSS_GENERAL_LTR_MODE_SW       BIT(2)
 #define LPSS_SW_LTR                    0x10
 #define LPSS_AUTO_LTR                  0x14
+#define LPSS_TX_INT                    0x20
+#define LPSS_TX_INT_MASK               BIT(1)
+
+struct lpss_shared_clock {
+       const char *name;
+       unsigned long rate;
+       struct clk *clk;
+};
+
+struct lpss_private_data;
 
 struct lpss_device_desc {
        bool clk_required;
        const char *clkdev_name;
        bool ltr_required;
        unsigned int prv_offset;
+       size_t prv_size_override;
+       bool clk_gate;
+       struct lpss_shared_clock *shared_clock;
+       void (*setup)(struct lpss_private_data *pdata);
 };
 
 static struct lpss_device_desc lpss_dma_desc = {
@@ -52,17 +66,76 @@ struct lpss_private_data {
        const struct lpss_device_desc *dev_desc;
 };
 
+static void lpss_uart_setup(struct lpss_private_data *pdata)
+{
+       unsigned int tx_int_offset = pdata->dev_desc->prv_offset + LPSS_TX_INT;
+       u32 reg;
+
+       reg = readl(pdata->mmio_base + tx_int_offset);
+       writel(reg | LPSS_TX_INT_MASK, pdata->mmio_base + tx_int_offset);
+}
+
 static struct lpss_device_desc lpt_dev_desc = {
        .clk_required = true,
        .prv_offset = 0x800,
        .ltr_required = true,
+       .clk_gate = true,
+};
+
+static struct lpss_device_desc lpt_uart_dev_desc = {
+       .clk_required = true,
+       .prv_offset = 0x800,
+       .ltr_required = true,
+       .clk_gate = true,
+       .setup = lpss_uart_setup,
 };
 
 static struct lpss_device_desc lpt_sdio_dev_desc = {
        .prv_offset = 0x1000,
+       .prv_size_override = 0x1018,
        .ltr_required = true,
 };
 
+static struct lpss_shared_clock uart_clock = {
+       .name = "uart_clk",
+       .rate = 44236800,
+};
+
+static struct lpss_device_desc byt_uart_dev_desc = {
+       .clk_required = true,
+       .prv_offset = 0x800,
+       .clk_gate = true,
+       .shared_clock = &uart_clock,
+       .setup = lpss_uart_setup,
+};
+
+static struct lpss_shared_clock spi_clock = {
+       .name = "spi_clk",
+       .rate = 50000000,
+};
+
+static struct lpss_device_desc byt_spi_dev_desc = {
+       .clk_required = true,
+       .prv_offset = 0x400,
+       .clk_gate = true,
+       .shared_clock = &spi_clock,
+};
+
+static struct lpss_device_desc byt_sdio_dev_desc = {
+       .clk_required = true,
+};
+
+static struct lpss_shared_clock i2c_clock = {
+       .name = "i2c_clk",
+       .rate = 100000000,
+};
+
+static struct lpss_device_desc byt_i2c_dev_desc = {
+       .clk_required = true,
+       .prv_offset = 0x800,
+       .shared_clock = &i2c_clock,
+};
+
 static const struct acpi_device_id acpi_lpss_device_ids[] = {
        /* Generic LPSS devices */
        { "INTL9C60", (unsigned long)&lpss_dma_desc },
@@ -72,11 +145,18 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
        { "INT33C1", (unsigned long)&lpt_dev_desc },
        { "INT33C2", (unsigned long)&lpt_dev_desc },
        { "INT33C3", (unsigned long)&lpt_dev_desc },
-       { "INT33C4", (unsigned long)&lpt_dev_desc },
-       { "INT33C5", (unsigned long)&lpt_dev_desc },
+       { "INT33C4", (unsigned long)&lpt_uart_dev_desc },
+       { "INT33C5", (unsigned long)&lpt_uart_dev_desc },
        { "INT33C6", (unsigned long)&lpt_sdio_dev_desc },
        { "INT33C7", },
 
+       /* BayTrail LPSS devices */
+       { "80860F0A", (unsigned long)&byt_uart_dev_desc },
+       { "80860F0E", (unsigned long)&byt_spi_dev_desc },
+       { "80860F14", (unsigned long)&byt_sdio_dev_desc },
+       { "80860F41", (unsigned long)&byt_i2c_dev_desc },
+       { "INT33B2", },
+
        { }
 };
 
@@ -98,7 +178,10 @@ static int register_device_clock(struct acpi_device *adev,
                                 struct lpss_private_data *pdata)
 {
        const struct lpss_device_desc *dev_desc = pdata->dev_desc;
+       struct lpss_shared_clock *shared_clock = dev_desc->shared_clock;
+       struct clk *clk = ERR_PTR(-ENODEV);
        struct lpss_clk_data *clk_data;
+       const char *parent;
 
        if (!lpss_clk_dev)
                lpt_register_clock_device();
@@ -117,14 +200,30 @@ static int register_device_clock(struct acpi_device *adev,
            || pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE)
                return -ENODATA;
 
-       pdata->clk = clk_register_gate(NULL, dev_name(&adev->dev),
-                                      clk_data->name, 0,
-                                      pdata->mmio_base + dev_desc->prv_offset,
-                                      0, 0, NULL);
-       if (IS_ERR(pdata->clk))
-               return PTR_ERR(pdata->clk);
+       parent = clk_data->name;
+
+       if (shared_clock) {
+               clk = shared_clock->clk;
+               if (!clk) {
+                       clk = clk_register_fixed_rate(NULL, shared_clock->name,
+                                                     "lpss_clk", 0,
+                                                     shared_clock->rate);
+                       shared_clock->clk = clk;
+               }
+               parent = shared_clock->name;
+       }
+
+       if (dev_desc->clk_gate) {
+               clk = clk_register_gate(NULL, dev_name(&adev->dev), parent, 0,
+                                       pdata->mmio_base + dev_desc->prv_offset,
+                                       0, 0, NULL);
+               pdata->clk = clk;
+       }
 
-       clk_register_clkdev(pdata->clk, NULL, dev_name(&adev->dev));
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       clk_register_clkdev(clk, NULL, dev_name(&adev->dev));
        return 0;
 }
 
@@ -152,7 +251,10 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
 
        list_for_each_entry(rentry, &resource_list, node)
                if (resource_type(&rentry->res) == IORESOURCE_MEM) {
-                       pdata->mmio_size = resource_size(&rentry->res);
+                       if (dev_desc->prv_size_override)
+                               pdata->mmio_size = dev_desc->prv_size_override;
+                       else
+                               pdata->mmio_size = resource_size(&rentry->res);
                        pdata->mmio_base = ioremap(rentry->res.start,
                                                   pdata->mmio_size);
                        pdata->dev_desc = dev_desc;
@@ -182,6 +284,9 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
                goto err_out;
        }
 
+       if (dev_desc->setup)
+               dev_desc->setup(pdata);
+
        adev->driver_data = pdata;
        ret = acpi_create_platform_device(adev, id);
        if (ret > 0)
index 5e6301e949206adb9f9b512a4b44b9d093e588df..c711d1144044ec18b47a8aad9f0c0f43e5f5f690 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/memory.h>
 #include <linux/memory_hotplug.h>
 
 #include "internal.h"
@@ -166,13 +167,50 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
        return 0;
 }
 
+static unsigned long acpi_meminfo_start_pfn(struct acpi_memory_info *info)
+{
+       return PFN_DOWN(info->start_addr);
+}
+
+static unsigned long acpi_meminfo_end_pfn(struct acpi_memory_info *info)
+{
+       return PFN_UP(info->start_addr + info->length-1);
+}
+
+static int acpi_bind_memblk(struct memory_block *mem, void *arg)
+{
+       return acpi_bind_one(&mem->dev, (acpi_handle)arg);
+}
+
+static int acpi_bind_memory_blocks(struct acpi_memory_info *info,
+                                  acpi_handle handle)
+{
+       return walk_memory_range(acpi_meminfo_start_pfn(info),
+                                acpi_meminfo_end_pfn(info), (void *)handle,
+                                acpi_bind_memblk);
+}
+
+static int acpi_unbind_memblk(struct memory_block *mem, void *arg)
+{
+       acpi_unbind_one(&mem->dev);
+       return 0;
+}
+
+static void acpi_unbind_memory_blocks(struct acpi_memory_info *info,
+                                     acpi_handle handle)
+{
+       walk_memory_range(acpi_meminfo_start_pfn(info),
+                         acpi_meminfo_end_pfn(info), NULL, acpi_unbind_memblk);
+}
+
 static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
 {
+       acpi_handle handle = mem_device->device->handle;
        int result, num_enabled = 0;
        struct acpi_memory_info *info;
        int node;
 
-       node = acpi_get_node(mem_device->device->handle);
+       node = acpi_get_node(handle);
        /*
         * Tell the VM there is more memory here...
         * Note: Assume that this function returns zero on success
@@ -203,6 +241,12 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
                if (result && result != -EEXIST)
                        continue;
 
+               result = acpi_bind_memory_blocks(info, handle);
+               if (result) {
+                       acpi_unbind_memory_blocks(info, handle);
+                       return -ENODEV;
+               }
+
                info->enabled = 1;
 
                /*
@@ -227,12 +271,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
        return 0;
 }
 
-static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
+static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
 {
-       int result = 0, nid;
+       acpi_handle handle = mem_device->device->handle;
        struct acpi_memory_info *info, *n;
-
-       nid = acpi_get_node(mem_device->device->handle);
+       int nid = acpi_get_node(handle);
 
        list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
                if (!info->enabled)
@@ -240,15 +283,12 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
 
                if (nid < 0)
                        nid = memory_add_physaddr_to_nid(info->start_addr);
-               result = remove_memory(nid, info->start_addr, info->length);
-               if (result)
-                       return result;
 
+               acpi_unbind_memory_blocks(info, handle);
+               remove_memory(nid, info->start_addr, info->length);
                list_del(&info->list);
                kfree(info);
        }
-
-       return result;
 }
 
 static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
@@ -300,7 +340,7 @@ static int acpi_memory_device_add(struct acpi_device *device,
        if (result) {
                dev_err(&device->dev, "acpi_memory_enable_device() error\n");
                acpi_memory_device_free(mem_device);
-               return -ENODEV;
+               return result;
        }
 
        dev_dbg(&device->dev, "Memory device configured by ACPI\n");
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
new file mode 100644 (file)
index 0000000..e9b01e3
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * acpi_processor.c - ACPI processor enumeration support
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2004       Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * Copyright (C) 2013, Intel Corporation
+ *                     Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include <acpi/processor.h>
+
+#include <asm/cpu.h>
+
+#include "internal.h"
+
+#define _COMPONENT     ACPI_PROCESSOR_COMPONENT
+
+ACPI_MODULE_NAME("processor");
+
+DEFINE_PER_CPU(struct acpi_processor *, processors);
+EXPORT_PER_CPU_SYMBOL(processors);
+
+/* --------------------------------------------------------------------------
+                                Errata Handling
+   -------------------------------------------------------------------------- */
+
+struct acpi_processor_errata errata __read_mostly;
+EXPORT_SYMBOL_GPL(errata);
+
+static int acpi_processor_errata_piix4(struct pci_dev *dev)
+{
+       u8 value1 = 0;
+       u8 value2 = 0;
+
+
+       if (!dev)
+               return -EINVAL;
+
+       /*
+        * Note that 'dev' references the PIIX4 ACPI Controller.
+        */
+
+       switch (dev->revision) {
+       case 0:
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
+               break;
+       case 1:
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n"));
+               break;
+       case 2:
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n"));
+               break;
+       case 3:
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n"));
+               break;
+       default:
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n"));
+               break;
+       }
+
+       switch (dev->revision) {
+
+       case 0:         /* PIIX4 A-step */
+       case 1:         /* PIIX4 B-step */
+               /*
+                * See specification changes #13 ("Manual Throttle Duty Cycle")
+                * and #14 ("Enabling and Disabling Manual Throttle"), plus
+                * erratum #5 ("STPCLK# Deassertion Time") from the January
+                * 2002 PIIX4 specification update.  Applies to only older
+                * PIIX4 models.
+                */
+               errata.piix4.throttle = 1;
+
+       case 2:         /* PIIX4E */
+       case 3:         /* PIIX4M */
+               /*
+                * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
+                * Livelock") from the January 2002 PIIX4 specification update.
+                * Applies to all PIIX4 models.
+                */
+
+               /*
+                * BM-IDE
+                * ------
+                * Find the PIIX4 IDE Controller and get the Bus Master IDE
+                * Status register address.  We'll use this later to read
+                * each IDE controller's DMA status to make sure we catch all
+                * DMA activity.
+                */
+               dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+                                    PCI_DEVICE_ID_INTEL_82371AB,
+                                    PCI_ANY_ID, PCI_ANY_ID, NULL);
+               if (dev) {
+                       errata.piix4.bmisx = pci_resource_start(dev, 4);
+                       pci_dev_put(dev);
+               }
+
+               /*
+                * Type-F DMA
+                * ----------
+                * Find the PIIX4 ISA Controller and read the Motherboard
+                * DMA controller's status to see if Type-F (Fast) DMA mode
+                * is enabled (bit 7) on either channel.  Note that we'll
+                * disable C3 support if this is enabled, as some legacy
+                * devices won't operate well if fast DMA is disabled.
+                */
+               dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+                                    PCI_DEVICE_ID_INTEL_82371AB_0,
+                                    PCI_ANY_ID, PCI_ANY_ID, NULL);
+               if (dev) {
+                       pci_read_config_byte(dev, 0x76, &value1);
+                       pci_read_config_byte(dev, 0x77, &value2);
+                       if ((value1 & 0x80) || (value2 & 0x80))
+                               errata.piix4.fdma = 1;
+                       pci_dev_put(dev);
+               }
+
+               break;
+       }
+
+       if (errata.piix4.bmisx)
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Bus master activity detection (BM-IDE) erratum enabled\n"));
+       if (errata.piix4.fdma)
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Type-F DMA livelock erratum (C3 disabled)\n"));
+
+       return 0;
+}
+
+static int acpi_processor_errata(struct acpi_processor *pr)
+{
+       int result = 0;
+       struct pci_dev *dev = NULL;
+
+
+       if (!pr)
+               return -EINVAL;
+
+       /*
+        * PIIX4
+        */
+       dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+                            PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID,
+                            PCI_ANY_ID, NULL);
+       if (dev) {
+               result = acpi_processor_errata_piix4(dev);
+               pci_dev_put(dev);
+       }
+
+       return result;
+}
+
+/* --------------------------------------------------------------------------
+                                Initialization
+   -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+static int acpi_processor_hotadd_init(struct acpi_processor *pr)
+{
+       unsigned long long sta;
+       acpi_status status;
+       int ret;
+
+       status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
+       if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
+               return -ENODEV;
+
+       ret = acpi_map_lsapic(pr->handle, &pr->id);
+       if (ret)
+               return ret;
+
+       ret = arch_register_cpu(pr->id);
+       if (ret) {
+               acpi_unmap_lsapic(pr->id);
+               return ret;
+       }
+
+       /*
+        * CPU got hot-added, but cpu_data is not initialized yet.  Set a flag
+        * to delay cpu_idle/throttling initialization and do it when the CPU
+        * gets online for the first time.
+        */
+       pr_info("CPU%d has been hot-added\n", pr->id);
+       pr->flags.need_hotplug_init = 1;
+       return 0;
+}
+#else
+static inline int acpi_processor_hotadd_init(struct acpi_processor *pr)
+{
+       return -ENODEV;
+}
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
+static int acpi_processor_get_info(struct acpi_device *device)
+{
+       union acpi_object object = { 0 };
+       struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
+       struct acpi_processor *pr = acpi_driver_data(device);
+       int cpu_index, device_declaration = 0;
+       acpi_status status = AE_OK;
+       static int cpu0_initialized;
+
+       if (num_online_cpus() > 1)
+               errata.smp = TRUE;
+
+       acpi_processor_errata(pr);
+
+       /*
+        * Check to see if we have bus mastering arbitration control.  This
+        * is required for proper C3 usage (to maintain cache coherency).
+        */
+       if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
+               pr->flags.bm_control = 1;
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Bus mastering arbitration control present\n"));
+       } else
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "No bus mastering arbitration control\n"));
+
+       if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) {
+               /* Declared with "Processor" statement; match ProcessorID */
+               status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+               if (ACPI_FAILURE(status)) {
+                       dev_err(&device->dev,
+                               "Failed to evaluate processor object (0x%x)\n",
+                               status);
+                       return -ENODEV;
+               }
+
+               /*
+                * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
+                *      >>> 'acpi_get_processor_id(acpi_id, &id)' in
+                *      arch/xxx/acpi.c
+                */
+               pr->acpi_id = object.processor.proc_id;
+       } else {
+               /*
+                * Declared with "Device" statement; match _UID.
+                * Note that we don't handle string _UIDs yet.
+                */
+               unsigned long long value;
+               status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
+                                               NULL, &value);
+               if (ACPI_FAILURE(status)) {
+                       dev_err(&device->dev,
+                               "Failed to evaluate processor _UID (0x%x)\n",
+                               status);
+                       return -ENODEV;
+               }
+               device_declaration = 1;
+               pr->acpi_id = value;
+       }
+       cpu_index = acpi_get_cpuid(pr->handle, device_declaration, pr->acpi_id);
+
+       /* Handle UP system running SMP kernel, with no LAPIC in MADT */
+       if (!cpu0_initialized && (cpu_index == -1) &&
+           (num_online_cpus() == 1)) {
+               cpu_index = 0;
+       }
+
+       cpu0_initialized = 1;
+
+       pr->id = cpu_index;
+
+       /*
+        *  Extra Processor objects may be enumerated on MP systems with
+        *  less than the max # of CPUs. They should be ignored _iff
+        *  they are physically not present.
+        */
+       if (pr->id == -1) {
+               int ret = acpi_processor_hotadd_init(pr);
+               if (ret)
+                       return ret;
+       }
+       /*
+        * On some boxes several processors use the same processor bus id.
+        * But they are located in different scope. For example:
+        * \_SB.SCK0.CPU0
+        * \_SB.SCK1.CPU0
+        * Rename the processor device bus id. And the new bus id will be
+        * generated as the following format:
+        * CPU+CPU ID.
+        */
+       sprintf(acpi_device_bid(device), "CPU%X", pr->id);
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
+                         pr->acpi_id));
+
+       if (!object.processor.pblk_address)
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
+       else if (object.processor.pblk_length != 6)
+               dev_err(&device->dev, "Invalid PBLK length [%d]\n",
+                           object.processor.pblk_length);
+       else {
+               pr->throttling.address = object.processor.pblk_address;
+               pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
+               pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
+
+               pr->pblk = object.processor.pblk_address;
+
+               /*
+                * We don't care about error returns - we just try to mark
+                * these reserved so that nobody else is confused into thinking
+                * that this region might be unused..
+                *
+                * (In particular, allocating the IO range for Cardbus)
+                */
+               request_region(pr->throttling.address, 6, "ACPI CPU throttle");
+       }
+
+       /*
+        * If ACPI describes a slot number for this CPU, we can use it to
+        * ensure we get the right value in the "physical id" field
+        * of /proc/cpuinfo
+        */
+       status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer);
+       if (ACPI_SUCCESS(status))
+               arch_fix_phys_package_id(pr->id, object.integer.value);
+
+       return 0;
+}
+
+/*
+ * Do not put anything in here which needs the core to be online.
+ * For example MSR access or setting up things which check for cpuinfo_x86
+ * (cpu_data(cpu)) values, like CPU feature flags, family, model, etc.
+ * Such things have to be put in and set up by the processor driver's .probe().
+ */
+static DEFINE_PER_CPU(void *, processor_device_array);
+
+static int __cpuinit acpi_processor_add(struct acpi_device *device,
+                                       const struct acpi_device_id *id)
+{
+       struct acpi_processor *pr;
+       struct device *dev;
+       int result = 0;
+
+       pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
+       if (!pr)
+               return -ENOMEM;
+
+       if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
+               result = -ENOMEM;
+               goto err_free_pr;
+       }
+
+       pr->handle = device->handle;
+       strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
+       strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
+       device->driver_data = pr;
+
+       result = acpi_processor_get_info(device);
+       if (result) /* Processor is not physically present or unavailable */
+               return 0;
+
+#ifdef CONFIG_SMP
+       if (pr->id >= setup_max_cpus && pr->id != 0)
+               return 0;
+#endif
+
+       BUG_ON(pr->id >= nr_cpu_ids);
+
+       /*
+        * Buggy BIOS check.
+        * ACPI id of processors can be reported wrongly by the BIOS.
+        * Don't trust it blindly
+        */
+       if (per_cpu(processor_device_array, pr->id) != NULL &&
+           per_cpu(processor_device_array, pr->id) != device) {
+               dev_warn(&device->dev,
+                       "BIOS reported wrong ACPI id %d for the processor\n",
+                       pr->id);
+               /* Give up, but do not abort the namespace scan. */
+               goto err;
+       }
+       /*
+        * processor_device_array is not cleared on errors to allow buggy BIOS
+        * checks.
+        */
+       per_cpu(processor_device_array, pr->id) = device;
+       per_cpu(processors, pr->id) = pr;
+
+       dev = get_cpu_device(pr->id);
+       if (!dev) {
+               result = -ENODEV;
+               goto err;
+       }
+
+       result = acpi_bind_one(dev, pr->handle);
+       if (result)
+               goto err;
+
+       pr->dev = dev;
+       dev->offline = pr->flags.need_hotplug_init;
+
+       /* Trigger the processor driver's .probe() if present. */
+       if (device_attach(dev) >= 0)
+               return 1;
+
+       dev_err(dev, "Processor driver could not be attached\n");
+       acpi_unbind_one(dev);
+
+ err:
+       free_cpumask_var(pr->throttling.shared_cpu_map);
+       device->driver_data = NULL;
+       per_cpu(processors, pr->id) = NULL;
+ err_free_pr:
+       kfree(pr);
+       return result;
+}
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+/* --------------------------------------------------------------------------
+                                    Removal
+   -------------------------------------------------------------------------- */
+
+static void acpi_processor_remove(struct acpi_device *device)
+{
+       struct acpi_processor *pr;
+
+       if (!device || !acpi_driver_data(device))
+               return;
+
+       pr = acpi_driver_data(device);
+       if (pr->id >= nr_cpu_ids)
+               goto out;
+
+       /*
+        * The only reason why we ever get here is CPU hot-removal.  The CPU is
+        * already offline and the ACPI device removal locking prevents it from
+        * being put back online at this point.
+        *
+        * Unbind the driver from the processor device and detach it from the
+        * ACPI companion object.
+        */
+       device_release_driver(pr->dev);
+       acpi_unbind_one(pr->dev);
+
+       /* Clean up. */
+       per_cpu(processor_device_array, pr->id) = NULL;
+       per_cpu(processors, pr->id) = NULL;
+       try_offline_node(cpu_to_node(pr->id));
+
+       /* Remove the CPU. */
+       get_online_cpus();
+       arch_unregister_cpu(pr->id);
+       acpi_unmap_lsapic(pr->id);
+       put_online_cpus();
+
+ out:
+       free_cpumask_var(pr->throttling.shared_cpu_map);
+       kfree(pr);
+}
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
+/*
+ * The following ACPI IDs are known to be suitable for representing as
+ * processor devices.
+ */
+static const struct acpi_device_id processor_device_ids[] = {
+
+       { ACPI_PROCESSOR_OBJECT_HID, },
+       { ACPI_PROCESSOR_DEVICE_HID, },
+
+       { }
+};
+
+static struct acpi_scan_handler __refdata processor_handler = {
+       .ids = processor_device_ids,
+       .attach = acpi_processor_add,
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+       .detach = acpi_processor_remove,
+#endif
+       .hotplug = {
+               .enabled = true,
+       },
+};
+
+void __init acpi_processor_init(void)
+{
+       acpi_scan_add_handler_with_hotplug(&processor_handler, "processor");
+}
index 7ddf29eca9f59f42a9f98bd46c031ae89aa23fe1..438304086ff1bb117f946f79038ff586a80df9c5 100644 (file)
@@ -83,6 +83,7 @@ acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
 acpi-y +=              \
        nsaccess.o      \
        nsalloc.o       \
+       nsarguments.o   \
        nsconvert.o     \
        nsdump.o        \
        nseval.o        \
@@ -137,6 +138,7 @@ acpi-y +=           \
        tbfadt.o        \
        tbfind.o        \
        tbinstal.o      \
+       tbprint.o       \
        tbutils.o       \
        tbxface.o       \
        tbxfload.o      \
@@ -145,11 +147,13 @@ acpi-y +=         \
 acpi-y +=              \
        utaddress.o     \
        utalloc.o       \
+       utbuffer.o      \
        utcopy.o        \
        utexcep.o       \
        utdebug.o       \
        utdecode.o      \
        utdelete.o      \
+       uterror.o       \
        uteval.o        \
        utglobal.o      \
        utids.o         \
index 07160928ca25cced7906412401d46d40b72194be..b8d38117a20c9f5971b719bea11d90017e571d69 100644 (file)
@@ -132,6 +132,12 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_truncate_io_addresses, FALSE);
  */
 u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE);
 
+/*
+ * Optionally do not load any SSDTs from the RSDT/XSDT during initialization.
+ * This can be useful for debugging ACPI problems on some machines.
+ */
+u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_ssdt_table_load, FALSE);
+
 /* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
 
 struct acpi_table_fadt acpi_gbl_FADT;
index d5bfbd331bfdda124d92a195b3418ae34cfbc2af..dfed26545ba28bb7858ce832fdce823460407992 100644 (file)
@@ -362,23 +362,6 @@ union acpi_predefined_info {
 
 #pragma pack()
 
-/* Data block used during object validation */
-
-struct acpi_predefined_data {
-       char *pathname;
-       const union acpi_predefined_info *predefined;
-       union acpi_operand_object *parent_package;
-       struct acpi_namespace_node *node;
-       u32 flags;
-       u32 return_btype;
-       u8 node_flags;
-};
-
-/* Defines for Flags field above */
-
-#define ACPI_OBJECT_REPAIRED    1
-#define ACPI_OBJECT_WRAPPED     2
-
 /* Return object auto-repair info */
 
 typedef acpi_status(*acpi_object_converter) (union acpi_operand_object
index 53666bd9193d5c566d264275ea7ba38518317ccc..530a2f8c1252da88d0598071b3f32da2bb739f1d 100644 (file)
  * the plist contains a set of parens to allow variable-length lists.
  * These macros are used for both the debug and non-debug versions of the code.
  */
-#define ACPI_ERROR_NAMESPACE(s, e)      acpi_ut_namespace_error (AE_INFO, s, e);
-#define ACPI_ERROR_METHOD(s, n, p, e)   acpi_ut_method_error (AE_INFO, s, n, p, e);
-#define ACPI_WARN_PREDEFINED(plist)     acpi_ut_predefined_warning plist
-#define ACPI_INFO_PREDEFINED(plist)     acpi_ut_predefined_info plist
+#define ACPI_ERROR_NAMESPACE(s, e)          acpi_ut_namespace_error (AE_INFO, s, e);
+#define ACPI_ERROR_METHOD(s, n, p, e)       acpi_ut_method_error (AE_INFO, s, n, p, e);
+#define ACPI_WARN_PREDEFINED(plist)         acpi_ut_predefined_warning plist
+#define ACPI_INFO_PREDEFINED(plist)         acpi_ut_predefined_info plist
+#define ACPI_BIOS_ERROR_PREDEFINED(plist)   acpi_ut_predefined_bios_error plist
 
 #else
 
 #define ACPI_ERROR_METHOD(s, n, p, e)
 #define ACPI_WARN_PREDEFINED(plist)
 #define ACPI_INFO_PREDEFINED(plist)
+#define ACPI_BIOS_ERROR_PREDEFINED(plist)
 
 #endif                         /* ACPI_NO_ERROR_MESSAGES */
 
index d2e491876bc043c64d7bd12d7bdd6d8217497a0a..b83dc32a5ae053eee5a935e30aaedaf0f7b6f3c3 100644 (file)
@@ -223,22 +223,33 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info);
 void acpi_ns_exec_module_code_list(void);
 
 /*
- * nspredef - Support for predefined/reserved names
+ * nsarguments - Argument count/type checking for predefined/reserved names
  */
-acpi_status
-acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
-                              u32 user_param_count,
-                              acpi_status return_status,
-                              union acpi_operand_object **return_object);
+void
+acpi_ns_check_argument_count(char *pathname,
+                            struct acpi_namespace_node *node,
+                            u32 user_param_count,
+                            const union acpi_predefined_info *info);
 
 void
-acpi_ns_check_parameter_count(char *pathname,
+acpi_ns_check_acpi_compliance(char *pathname,
                              struct acpi_namespace_node *node,
-                             u32 user_param_count,
-                             const union acpi_predefined_info *info);
+                             const union acpi_predefined_info *predefined);
+
+void acpi_ns_check_argument_types(struct acpi_evaluate_info *info);
+
+/*
+ * nspredef - Return value checking for predefined/reserved names
+ */
+acpi_status
+acpi_ns_check_return_value(struct acpi_namespace_node *node,
+                          struct acpi_evaluate_info *info,
+                          u32 user_param_count,
+                          acpi_status return_status,
+                          union acpi_operand_object **return_object);
 
 acpi_status
-acpi_ns_check_object_type(struct acpi_predefined_data *data,
+acpi_ns_check_object_type(struct acpi_evaluate_info *info,
                          union acpi_operand_object **return_object_ptr,
                          u32 expected_btypes, u32 package_index);
 
@@ -246,7 +257,7 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
  * nsprepkg - Validation of predefined name packages
  */
 acpi_status
-acpi_ns_check_package(struct acpi_predefined_data *data,
+acpi_ns_check_package(struct acpi_evaluate_info *info,
                      union acpi_operand_object **return_object_ptr);
 
 /*
@@ -308,24 +319,24 @@ acpi_ns_get_attached_data(struct acpi_namespace_node *node,
  * predefined methods/objects
  */
 acpi_status
-acpi_ns_simple_repair(struct acpi_predefined_data *data,
+acpi_ns_simple_repair(struct acpi_evaluate_info *info,
                      u32 expected_btypes,
                      u32 package_index,
                      union acpi_operand_object **return_object_ptr);
 
 acpi_status
-acpi_ns_wrap_with_package(struct acpi_predefined_data *data,
+acpi_ns_wrap_with_package(struct acpi_evaluate_info *info,
                          union acpi_operand_object *original_object,
                          union acpi_operand_object **obj_desc_ptr);
 
 acpi_status
-acpi_ns_repair_null_element(struct acpi_predefined_data *data,
+acpi_ns_repair_null_element(struct acpi_evaluate_info *info,
                            u32 expected_btypes,
                            u32 package_index,
                            union acpi_operand_object **return_object_ptr);
 
 void
-acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
+acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
                             u8 package_type,
                             union acpi_operand_object *obj_desc);
 
@@ -334,7 +345,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
  * predefined methods/objects
  */
 acpi_status
-acpi_ns_complex_repairs(struct acpi_predefined_data *data,
+acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
                        struct acpi_namespace_node *node,
                        acpi_status validate_status,
                        union acpi_operand_object **return_object_ptr);
index b22b70944fd63175dc3f8f9876ad37c505948686..f600aded7261cde6762b3fee5d9b9a6a790664b8 100644 (file)
@@ -128,8 +128,8 @@ enum acpi_return_package_types {
 #define ARG_COUNT_IS_MINIMUM            0x8000
 #define METHOD_MAX_ARG_TYPE             ACPI_TYPE_PACKAGE
 
-#define METHOD_GET_COUNT(arg_list)      (arg_list & METHOD_ARG_MASK)
-#define METHOD_GET_NEXT_ARG(arg_list)   (arg_list >> METHOD_ARG_BIT_WIDTH)
+#define METHOD_GET_ARG_COUNT(arg_list)  ((arg_list) & METHOD_ARG_MASK)
+#define METHOD_GET_NEXT_TYPE(arg_list)  (((arg_list) >>= METHOD_ARG_BIT_WIDTH) & METHOD_ARG_MASK)
 
 /* Macros used to build the predefined info table */
 
index 7896d85876cacd534991bf72e4a920ce041947b8..fc83c0a5ca70fe228857d1336d967a91dd0765fa 100644 (file)
@@ -178,25 +178,41 @@ union acpi_aml_operands {
 };
 
 /*
- * Structure used to pass object evaluation parameters.
+ * Structure used to pass object evaluation information and parameters.
  * Purpose is to reduce CPU stack use.
  */
 struct acpi_evaluate_info {
-       struct acpi_namespace_node *prefix_node;
-       char *pathname;
-       union acpi_operand_object *obj_desc;
-       union acpi_operand_object **parameters;
-       struct acpi_namespace_node *resolved_node;
-       union acpi_operand_object *return_object;
-       u8 param_count;
-       u8 pass_number;
-       u8 return_object_type;
-       u8 flags;
+       /* The first 3 elements are passed by the caller to acpi_ns_evaluate */
+
+       struct acpi_namespace_node *prefix_node;        /* Input: starting node */
+       char *relative_pathname;        /* Input: path relative to prefix_node */
+       union acpi_operand_object **parameters; /* Input: argument list */
+
+       struct acpi_namespace_node *node;       /* Resolved node (prefix_node:relative_pathname) */
+       union acpi_operand_object *obj_desc;    /* Object attached to the resolved node */
+       char *full_pathname;    /* Full pathname of the resolved node */
+
+       const union acpi_predefined_info *predefined;   /* Used if Node is a predefined name */
+       union acpi_operand_object *return_object;       /* Object returned from the evaluation */
+       union acpi_operand_object *parent_package;      /* Used if return object is a Package */
+
+       u32 return_flags;       /* Used for return value analysis */
+       u32 return_btype;       /* Bitmapped type of the returned object */
+       u16 param_count;        /* Count of the input argument list */
+       u8 pass_number;         /* Parser pass number */
+       u8 return_object_type;  /* Object type of the returned object */
+       u8 node_flags;          /* Same as Node->Flags */
+       u8 flags;               /* General flags */
 };
 
 /* Values for Flags above */
 
-#define ACPI_IGNORE_RETURN_VALUE        1
+#define ACPI_IGNORE_RETURN_VALUE    1
+
+/* Defines for return_flags field above */
+
+#define ACPI_OBJECT_REPAIRED        1
+#define ACPI_OBJECT_WRAPPED         2
 
 /* Info used by acpi_ns_initialize_devices */
 
index 202f4f12d3e2fad0e6d447a781c559a7bbcad88d..3c76edea6803faf0cf8c7db1b76431b5abafbf04 100644 (file)
@@ -87,6 +87,48 @@ extern const char *acpi_gbl_fc_decode[];
 extern const char *acpi_gbl_pt_decode[];
 #endif
 
+/*
+ * For the iASL compiler case, the output is redirected to stderr so that
+ * any of the various ACPI errors and warnings do not appear in the output
+ * files, for either the compiler or disassembler portions of the tool.
+ */
+#ifdef ACPI_ASL_COMPILER
+
+#include <stdio.h>
+extern FILE *acpi_gbl_output_file;
+
+#define ACPI_MSG_REDIRECT_BEGIN \
+       FILE                            *output_file = acpi_gbl_output_file; \
+       acpi_os_redirect_output (stderr);
+
+#define ACPI_MSG_REDIRECT_END \
+       acpi_os_redirect_output (output_file);
+
+#else
+/*
+ * non-iASL case - no redirection, nothing to do
+ */
+#define ACPI_MSG_REDIRECT_BEGIN
+#define ACPI_MSG_REDIRECT_END
+#endif
+
+/*
+ * Common error message prefixes
+ */
+#define ACPI_MSG_ERROR          "ACPI Error: "
+#define ACPI_MSG_EXCEPTION      "ACPI Exception: "
+#define ACPI_MSG_WARNING        "ACPI Warning: "
+#define ACPI_MSG_INFO           "ACPI: "
+
+#define ACPI_MSG_BIOS_ERROR     "ACPI BIOS Error (bug): "
+#define ACPI_MSG_BIOS_WARNING   "ACPI BIOS Warning (bug): "
+
+/*
+ * Common message suffix
+ */
+#define ACPI_MSG_SUFFIX \
+       acpi_os_printf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
+
 /* Types for Resource descriptor entries */
 
 #define ACPI_INVALID_RESOURCE           0
@@ -578,7 +620,7 @@ void acpi_ut_print_string(char *string, u8 max_length);
 
 void ut_convert_backslashes(char *pathname);
 
-u8 acpi_ut_valid_acpi_name(u32 name);
+u8 acpi_ut_valid_acpi_name(char *name);
 
 u8 acpi_ut_valid_acpi_char(char character, u32 position);
 
@@ -670,6 +712,12 @@ acpi_ut_predefined_info(const char *module_name,
                        u32 line_number,
                        char *pathname, u8 node_flags, const char *format, ...);
 
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_bios_error(const char *module_name,
+                             u32 line_number,
+                             char *pathname,
+                             u8 node_flags, const char *format, ...);
+
 void
 acpi_ut_namespace_error(const char *module_name,
                        u32 line_number,
index 7ea0f162f11ca42e11d7247fc3263d4c1fb0b2e1..eb56b66444b5e3d671572b6290a1245473e7d165 100644 (file)
@@ -78,7 +78,6 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
 
        switch (op->common.aml_opcode) {
        case AML_WHILE_OP:
-
                /*
                 * If this is an additional iteration of a while loop, continue.
                 * There is no need to allocate a new control state.
@@ -99,7 +98,6 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
                /*lint -fallthrough */
 
        case AML_IF_OP:
-
                /*
                 * IF/WHILE: Create a new control state to manage these
                 * constructs. We need to manage these as a stack, in order
@@ -142,6 +140,7 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
                break;
 
        default:
+
                break;
        }
 
@@ -344,6 +343,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
        case AML_NOOP_OP:
 
                /* Just do nothing! */
+
                break;
 
        case AML_BREAK_POINT_OP:
index feadeed1012dc2256c1596bb79e7ff6190e6cb41..d4bfe7b7f90a54a5b5cdafb8119f0d60698be171 100644 (file)
@@ -563,21 +563,25 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
         */
        switch (walk_state->opcode) {
        case AML_FIELD_OP:
+
                arg = acpi_ps_get_arg(op, 2);
                type = ACPI_TYPE_LOCAL_REGION_FIELD;
                break;
 
        case AML_BANK_FIELD_OP:
+
                arg = acpi_ps_get_arg(op, 4);
                type = ACPI_TYPE_LOCAL_BANK_FIELD;
                break;
 
        case AML_INDEX_FIELD_OP:
+
                arg = acpi_ps_get_arg(op, 3);
                type = ACPI_TYPE_LOCAL_INDEX_FIELD;
                break;
 
        default:
+
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
index bc8e63f7784b96a7bf39c5476dc9cacd07688bb5..14424200d246c8538bcde5070072100528dcf1dd 100644 (file)
@@ -127,6 +127,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
                break;
 
        default:
+
                break;
        }
 
index 3da80460ce38af069241fb59ee41d2aeb695d319..c4b0b365723758fe5181e26eaeaa7cb5314f18d3 100644 (file)
@@ -285,6 +285,7 @@ acpi_ds_method_data_get_node(u8 type,
                break;
 
        default:
+
                ACPI_ERROR((AE_INFO, "Type %u is invalid", type));
                return_ACPI_STATUS(AE_TYPE);
        }
@@ -428,7 +429,6 @@ acpi_ds_method_data_get_value(u8 type,
                                return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);
 
                        case ACPI_REFCLASS_LOCAL:
-
                                /*
                                 * No error message for this case, will be trapped again later to
                                 * detect and ignore cases of Store(local_x,local_x)
index e20e9f84eee80653b6dfc932f140c6eaebf4a5ac..63f0d220ca3d99a2da601b1b4571972bf2f71397 100644 (file)
@@ -648,7 +648,6 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
 
        switch (obj_desc->common.type) {
        case ACPI_TYPE_BUFFER:
-
                /*
                 * Defer evaluation of Buffer term_arg operand
                 */
@@ -660,7 +659,6 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
                break;
 
        case ACPI_TYPE_PACKAGE:
-
                /*
                 * Defer evaluation of Package term_arg operand
                 */
@@ -741,6 +739,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
                        break;
 
                default:
+
                        ACPI_ERROR((AE_INFO, "Unknown Integer type 0x%X",
                                    op_info->type));
                        status = AE_AML_OPERAND_TYPE;
index ee6367b8eaf7afcf6866ff75193e5ca59bfa94f4..1fc1ff114f269867bf1a281e584511c00595d960 100644 (file)
@@ -636,6 +636,7 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
                break;
 
        default:
+
                return_ACPI_STATUS(AE_AML_BAD_OPCODE);
        }
 
index 99778997c35ab8f1fb5c6249c030c9e48fd35366..c666fc01498795afdb76f6afad8383f75389d1bb 100644 (file)
@@ -240,7 +240,6 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
 
                case AML_IF_OP:
                case AML_WHILE_OP:
-
                        /*
                         * If we are executing the predicate AND this is the predicate op,
                         * we will use the return value
@@ -254,7 +253,9 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
                        break;
 
                default:
+
                        /* Ignore other control opcodes */
+
                        break;
                }
 
@@ -263,7 +264,6 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
                goto result_not_used;
 
        case AML_CLASS_CREATE:
-
                /*
                 * These opcodes allow term_arg(s) as operands and therefore
                 * the operands can be method calls. The result is used.
@@ -292,7 +292,6 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
                goto result_not_used;
 
        default:
-
                /*
                 * In all other cases. the parent will actually use the return
                 * object, so keep it.
index e2199a9474703196326024af6bbfc0c5460e7201..151d924817e1b2041bfd60cad46aaaf1a5dc9e20 100644 (file)
@@ -327,6 +327,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
                break;
 
        default:
+
                break;
        }
 
@@ -488,7 +489,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
                        break;
 
                case AML_TYPE_METHOD_CALL:
-
                        /*
                         * If the method is referenced from within a package
                         * declaration, it is not a invocation of the method, just
@@ -582,7 +582,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
 
                        switch (op->common.parent->common.aml_opcode) {
                        case AML_NAME_OP:
-
                                /*
                                 * Put the Node on the object stack (Contains the ACPI Name
                                 * of this object)
index 6e17c0e24e63ca4e758d1e2a2147419ed5e4b0ec..95e681a36f9c28d820b40f55d211426ae4b2de92 100644 (file)
@@ -74,6 +74,7 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
 
        switch (pass_number) {
        case 1:
+
                walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
                    ACPI_PARSE_DELETE_TREE;
                walk_state->descending_callback = acpi_ds_load1_begin_op;
@@ -81,6 +82,7 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
                break;
 
        case 2:
+
                walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
                    ACPI_PARSE_DELETE_TREE;
                walk_state->descending_callback = acpi_ds_load2_begin_op;
@@ -88,6 +90,7 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
                break;
 
        case 3:
+
 #ifndef ACPI_NO_METHOD_EXECUTION
                walk_state->parse_flags |= ACPI_PARSE_EXECUTE |
                    ACPI_PARSE_DELETE_TREE;
@@ -97,6 +100,7 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
                break;
 
        default:
+
                return (AE_BAD_PARAMETER);
        }
 
@@ -161,7 +165,6 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
 
        switch (walk_state->opcode) {
        case AML_SCOPE_OP:
-
                /*
                 * The target name of the Scope() operator must exist at this point so
                 * that we can actually open the scope to enter new names underneath it.
@@ -210,7 +213,6 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
                case ACPI_TYPE_INTEGER:
                case ACPI_TYPE_STRING:
                case ACPI_TYPE_BUFFER:
-
                        /*
                         * These types we will allow, but we will change the type.
                         * This enables some existing code of the form:
@@ -232,7 +234,6 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
                        break;
 
                case ACPI_TYPE_METHOD:
-
                        /*
                         * Allow scope change to root during execution of module-level
                         * code. Root is typed METHOD during this time.
index 4407ff2377d5918b10fe08875434ed07b981d836..b1f8f4725c230b0d6b0bf9155f13028f42d62667 100644 (file)
@@ -509,6 +509,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
                        break;
 
                default:
+
                        /* All NAMED_FIELD opcodes must be handled above */
                        break;
                }
@@ -548,6 +549,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
                        break;
 
                default:
+
                        /* Unknown opcode */
 
                        status = AE_OK;
@@ -674,6 +676,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
 #endif                         /* ACPI_NO_METHOD_EXECUTION */
 
                default:
+
                        /* All NAMED_COMPLEX opcodes must be handled above */
                        break;
                }
@@ -721,6 +724,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
                break;
 
        default:
+
                break;
        }
 
index a621481c6cf27f946a6050f5ef9f6ea466b51689..fdb0a76e40a3020806cfce8c4e637273e2fc4f2c 100644 (file)
@@ -128,6 +128,7 @@ acpi_status acpi_ev_remove_global_lock_handler(void)
        status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
                                                 acpi_ev_global_lock_handler);
 
+       acpi_os_delete_lock(acpi_gbl_global_lock_pending_lock);
        return_ACPI_STATUS(status);
 }
 
index a493b528f8f9f3c5a88b13ed685befdbc07c9e13..c8a1f7d5931f518b004cc8311d31e5ad8e5cdaeb 100644 (file)
@@ -529,7 +529,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
 
        switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
        case ACPI_GPE_DISPATCH_NOTIFY:
-
                /*
                 * Implicit notify.
                 * Dispatch a DEVICE_WAKE notify to the appropriate handler.
@@ -579,11 +578,11 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
                                        (local_gpe_event_info->dispatch.
                                         method_node)));
                }
-
                break;
 
        default:
-               return_VOID;    /* Should never happen */
+
+               return_VOID;    /* Should never happen */
        }
 
        /* Defer enabling of GPE until all notify handlers are done */
@@ -755,7 +754,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
 
        case ACPI_GPE_DISPATCH_METHOD:
        case ACPI_GPE_DISPATCH_NOTIFY:
-
                /*
                 * Execute the method associated with the GPE
                 * NOTE: Level-triggered GPEs are cleared after the method completes.
@@ -771,7 +769,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
                break;
 
        default:
-
                /*
                 * No handler or method to run!
                 * 03/2010: This case should no longer be possible. We will not allow
index a2d688bbac02c7ee96e43b5764f97442c1dd2a6f..c1aa1eda26c32ec73dc68ac6d5433d783383348b 100644 (file)
@@ -382,6 +382,8 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
 
        status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);
        if (ACPI_FAILURE(status)) {
+               ACPI_FREE(gpe_block->register_info);
+               ACPI_FREE(gpe_block->event_info);
                ACPI_FREE(gpe_block);
                return_ACPI_STATUS(status);
        }
index 72b8f6b3f4cafeac10eee0bacfa2af5c1851f281..9037f17c9608f70a6bc2df68eca5b55043ad9723 100644 (file)
@@ -363,14 +363,17 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
         */
        switch (name[1]) {
        case 'L':
+
                type = ACPI_GPE_LEVEL_TRIGGERED;
                break;
 
        case 'E':
+
                type = ACPI_GPE_EDGE_TRIGGERED;
                break;
 
        default:
+
                /* Unknown method type, just ignore it */
 
                ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
index d4f83112c2e266ff2fcf5f8415d9714ffa071330..068af96134b89787a739cce281f481db82e46e19 100644 (file)
@@ -354,36 +354,43 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node,
 
                switch (space_id) {
                case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+
                        handler = acpi_ex_system_memory_space_handler;
                        setup = acpi_ev_system_memory_region_setup;
                        break;
 
                case ACPI_ADR_SPACE_SYSTEM_IO:
+
                        handler = acpi_ex_system_io_space_handler;
                        setup = acpi_ev_io_space_region_setup;
                        break;
 
                case ACPI_ADR_SPACE_PCI_CONFIG:
+
                        handler = acpi_ex_pci_config_space_handler;
                        setup = acpi_ev_pci_config_region_setup;
                        break;
 
                case ACPI_ADR_SPACE_CMOS:
+
                        handler = acpi_ex_cmos_space_handler;
                        setup = acpi_ev_cmos_region_setup;
                        break;
 
                case ACPI_ADR_SPACE_PCI_BAR_TARGET:
+
                        handler = acpi_ex_pci_bar_space_handler;
                        setup = acpi_ev_pci_bar_region_setup;
                        break;
 
                case ACPI_ADR_SPACE_DATA_TABLE:
+
                        handler = acpi_ex_data_table_space_handler;
                        setup = NULL;
                        break;
 
                default:
+
                        status = AE_BAD_PARAMETER;
                        goto unlock_and_exit;
                }
index c986b2336b81d6b1b85e60ee4e2e9568e2750a33..1b111ef74903771f8f9a8f690aef85b752f65c61 100644 (file)
@@ -78,6 +78,7 @@ u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
                return (TRUE);
 
        default:
+
                return (FALSE);
        }
 }
@@ -275,6 +276,8 @@ void acpi_ev_terminate(void)
                        ACPI_ERROR((AE_INFO,
                                    "Could not remove Global Lock handler"));
                }
+
+               acpi_gbl_events_initialized = FALSE;
        }
 
        /* Deallocate all handler objects installed within GPE info structs */
index 6555e350fc1fe21087cea7e219a9c4b170d70e25..cea14d6fc76c976db580144f93d28d890ff3938f 100644 (file)
@@ -54,7 +54,8 @@ extern u8 acpi_gbl_default_address_spaces[];
 
 /* Local prototypes */
 
-static void acpi_ev_orphan_ec_reg_method(void);
+static void
+acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node);
 
 static acpi_status
 acpi_ev_reg_run(acpi_handle obj_handle,
@@ -532,7 +533,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
        }
 
        info->prefix_node = region_obj2->extra.method_REG;
-       info->pathname = NULL;
+       info->relative_pathname = NULL;
        info->parameters = args;
        info->flags = ACPI_IGNORE_RETURN_VALUE;
 
@@ -612,7 +613,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
        /* Special case for EC: handle "orphan" _REG methods with no region */
 
        if (space_id == ACPI_ADR_SPACE_EC) {
-               acpi_ev_orphan_ec_reg_method();
+               acpi_ev_orphan_ec_reg_method(node);
        }
 
        return_ACPI_STATUS(status);
@@ -681,7 +682,7 @@ acpi_ev_reg_run(acpi_handle obj_handle,
  *
  * FUNCTION:    acpi_ev_orphan_ec_reg_method
  *
- * PARAMETERS:  None
+ * PARAMETERS:  ec_device_node      - Namespace node for an EC device
  *
  * RETURN:      None
  *
@@ -693,37 +694,27 @@ acpi_ev_reg_run(acpi_handle obj_handle,
  *              detected by providing a _REG method object underneath the
  *              Embedded Controller device."
  *
- *              To quickly access the EC device, we use the EC_ID that appears
- *              within the ECDT. Otherwise, we would need to perform a time-
- *              consuming namespace walk, executing _HID methods to find the
- *              EC device.
+ *              To quickly access the EC device, we use the ec_device_node used
+ *              during EC handler installation. Otherwise, we would need to
+ *              perform a time consuming namespace walk, executing _HID
+ *              methods to find the EC device.
+ *
+ *  MUTEX:      Assumes the namespace is locked
  *
  ******************************************************************************/
 
-static void acpi_ev_orphan_ec_reg_method(void)
+static void
+acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node)
 {
-       struct acpi_table_ecdt *table;
+       acpi_handle reg_method;
+       struct acpi_namespace_node *next_node;
        acpi_status status;
        struct acpi_object_list args;
        union acpi_object objects[2];
-       struct acpi_namespace_node *ec_device_node;
-       struct acpi_namespace_node *reg_method;
-       struct acpi_namespace_node *next_node;
 
        ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method);
 
-       /* Get the ECDT (if present in system) */
-
-       status = acpi_get_table(ACPI_SIG_ECDT, 0,
-                               ACPI_CAST_INDIRECT_PTR(struct acpi_table_header,
-                                                      &table));
-       if (ACPI_FAILURE(status)) {
-               return_VOID;
-       }
-
-       /* We need a valid EC_ID string */
-
-       if (!(*table->id)) {
+       if (!ec_device_node) {
                return_VOID;
        }
 
@@ -731,22 +722,11 @@ static void acpi_ev_orphan_ec_reg_method(void)
 
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 
-       /* Get a handle to the EC device referenced in the ECDT */
-
-       status = acpi_get_handle(NULL,
-                                ACPI_CAST_PTR(char, table->id),
-                                ACPI_CAST_PTR(acpi_handle, &ec_device_node));
-       if (ACPI_FAILURE(status)) {
-               goto exit;
-       }
-
        /* Get a handle to a _REG method immediately under the EC device */
 
-       status = acpi_get_handle(ec_device_node,
-                                METHOD_NAME__REG, ACPI_CAST_PTR(acpi_handle,
-                                                                &reg_method));
+       status = acpi_get_handle(ec_device_node, METHOD_NAME__REG, &reg_method);
        if (ACPI_FAILURE(status)) {
-               goto exit;
+               goto exit;      /* There is no _REG method present */
        }
 
        /*
@@ -754,19 +734,20 @@ static void acpi_ev_orphan_ec_reg_method(void)
         * this scope with the Embedded Controller space ID. Otherwise, it
         * will already have been executed. Note, this allows for Regions
         * with other space IDs to be present; but the code below will then
-        * execute the _REG method with the EC space ID argument.
+        * execute the _REG method with the embedded_control space_ID argument.
         */
        next_node = acpi_ns_get_next_node(ec_device_node, NULL);
        while (next_node) {
                if ((next_node->type == ACPI_TYPE_REGION) &&
                    (next_node->object) &&
                    (next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) {
-                       goto exit;      /* Do not execute _REG */
+                       goto exit;      /* Do not execute the _REG */
                }
+
                next_node = acpi_ns_get_next_node(ec_device_node, next_node);
        }
 
-       /* Evaluate the _REG(EC,Connect) method */
+       /* Evaluate the _REG(embedded_control,Connect) method */
 
        args.count = 2;
        args.pointer = objects;
index 3bb616794b3b46fe5aaaaa7b77335523b351b159..8354c4f7f10c55c604765a92020abd2d30547de9 100644 (file)
@@ -596,7 +596,9 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
                                break;
 
                        default:
+
                                /* Ignore other objects */
+
                                break;
                        }
 
index aff4cc2612115304f41ea11a6aa57a5038a6f101..7662f1a42ff6bb19513e0f9272f90c921f64ec90 100644 (file)
@@ -366,16 +366,19 @@ acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action)
 
        switch (action) {
        case ACPI_GPE_ENABLE:
+
                ACPI_SET_BIT(gpe_register_info->enable_for_wake,
                             (u8)register_bit);
                break;
 
        case ACPI_GPE_DISABLE:
+
                ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
                               (u8)register_bit);
                break;
 
        default:
+
                ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
                status = AE_BAD_PARAMETER;
                break;
index 96c9e5f355aed40f7e07fc598d60b61907c501a6..80cecf8385917c7ed32ca75eb9afc807dbb6b0b2 100644 (file)
@@ -139,6 +139,7 @@ acpi_install_address_space_handler(acpi_handle device,
                break;
 
        default:
+
                break;
        }
 
index d93b70be60adf071c132687b208241d233bb4f3a..06d216c8d43ab18edc0fb1f66def077014b2aa3f 100644 (file)
@@ -480,6 +480,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                break;
 
        default:
+
                return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
        }
 
@@ -588,7 +589,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
            (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) ||
            (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) ||
            (!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+               return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
        }
 
        /* Get the table index from the ddb_handle */
index d2b9613bbf01d231e72f44d87381e83ab87f11e4..69e4a8cc9b71728f98b1aad402a0a44538033457 100644 (file)
@@ -99,6 +99,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
                break;
 
        default:
+
                return_ACPI_STATUS(AE_TYPE);
        }
 
@@ -117,7 +118,6 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
 
        switch (obj_desc->common.type) {
        case ACPI_TYPE_STRING:
-
                /*
                 * Convert string to an integer - for most cases, the string must be
                 * hexadecimal as per the ACPI specification. The only exception (as
@@ -161,6 +161,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
        default:
 
                /* No other types can get here */
+
                break;
        }
 
@@ -213,7 +214,6 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(AE_OK);
 
        case ACPI_TYPE_INTEGER:
-
                /*
                 * Create a new Buffer object.
                 * Need enough space for one integer
@@ -233,7 +233,6 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
                break;
 
        case ACPI_TYPE_STRING:
-
                /*
                 * Create a new Buffer object
                 * Size will be the string length
@@ -258,6 +257,7 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
                break;
 
        default:
+
                return_ACPI_STATUS(AE_TYPE);
        }
 
@@ -304,15 +304,18 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
 
                switch (data_width) {
                case 1:
+
                        decimal_length = ACPI_MAX8_DECIMAL_DIGITS;
                        break;
 
                case 4:
+
                        decimal_length = ACPI_MAX32_DECIMAL_DIGITS;
                        break;
 
                case 8:
                default:
+
                        decimal_length = ACPI_MAX64_DECIMAL_DIGITS;
                        break;
                }
@@ -546,6 +549,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
                break;
 
        default:
+
                return_ACPI_STATUS(AE_TYPE);
        }
 
@@ -599,6 +603,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
                        break;
 
                default:
+
                        /* No conversion allowed for these types */
 
                        if (destination_type != source_desc->common.type) {
@@ -649,6 +654,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
                        break;
 
                default:
+
                        ACPI_ERROR((AE_INFO,
                                    "Bad destination type during conversion: 0x%X",
                                    destination_type));
@@ -664,6 +670,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
                break;
 
        default:
+
                ACPI_ERROR((AE_INFO,
                            "Unknown Target type ID 0x%X AmlOpcode 0x%X DestType %s",
                            GET_CURRENT_ARG_TYPE(walk_state->op_info->
index 26a13f67977ea11248cc54ec9f034ecf1a584e45..269e81d86ef41c59e7eaa3d61bb7c63ba23457bd 100644 (file)
@@ -103,7 +103,6 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
        case ACPI_TYPE_BUFFER:
        case ACPI_TYPE_PACKAGE:
        case ACPI_TYPE_BUFFER_FIELD:
-
                /*
                 * These types open a new scope, so we need the NS node in order to access
                 * any children.
@@ -113,7 +112,6 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
        case ACPI_TYPE_PROCESSOR:
        case ACPI_TYPE_THERMAL:
        case ACPI_TYPE_LOCAL_SCOPE:
-
                /*
                 * The new alias has the type ALIAS and points to the original
                 * NS node, not the object itself.
@@ -124,7 +122,6 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
                break;
 
        case ACPI_TYPE_METHOD:
-
                /*
                 * Control method aliases need to be differentiated
                 */
index 7eb853cd279f776f5b384543dba38fdedfafff38..81c72a4ecd823eaca8542135aea5396d7d6d5626 100644 (file)
@@ -193,6 +193,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
                        return_VOID;
 
                default:
+
                        break;
                }
 
@@ -226,6 +227,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
                                        break;
 
                                default:
+
                                        acpi_ex_do_debug_object((source_desc->
                                                                 reference.
                                                                 node)->object,
index e5a3c249f7fad23c544a856504d13d33134c104e..c740f24e3101069af922a5e5842a77fb60d34710 100644 (file)
@@ -357,6 +357,7 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
 
                switch (info->opcode) {
                case ACPI_EXD_INIT:
+
                        break;
 
                case ACPI_EXD_TYPE:
@@ -718,6 +719,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
                break;
 
        default:
+
                /* Unknown Type */
 
                acpi_os_printf("Unknown Type %X\n", obj_desc->common.type);
index 7d4bae71e8c62da6399bc6af7e0f3fd132efa574..c2a65aaf29af006f3be629aab6b9f6b698650b40 100644 (file)
@@ -331,21 +331,25 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
 
        switch (source_desc->common.type) {
        case ACPI_TYPE_INTEGER:
+
                buffer = &source_desc->integer.value;
                length = sizeof(source_desc->integer.value);
                break;
 
        case ACPI_TYPE_BUFFER:
+
                buffer = source_desc->buffer.pointer;
                length = source_desc->buffer.length;
                break;
 
        case ACPI_TYPE_STRING:
+
                buffer = source_desc->string.pointer;
                length = source_desc->string.length;
                break;
 
        default:
+
                return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
        }
 
index c84ee956fa4c58f50c8849cc660a151d46febe39..7e0afe72487ea73ee5504d73891b294b83aceb91 100644 (file)
@@ -446,7 +446,6 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
                break;
 
        case ACPI_TYPE_LOCAL_BANK_FIELD:
-
                /*
                 * Ensure that the bank_value is not beyond the capacity of
                 * the register
@@ -488,7 +487,6 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
                break;
 
        case ACPI_TYPE_LOCAL_INDEX_FIELD:
-
                /*
                 * Ensure that the index_value is not beyond the capacity of
                 * the register
index 72a2a13b6d36de72eb97cf7d38aacb0cada1587b..00bf298775741763054eabd2d3030dcb6494e150 100644 (file)
@@ -105,7 +105,6 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
                break;
 
        case ACPI_DESC_TYPE_NAMED:
-
                /*
                 * A named reference that has already been resolved to a Node
                 */
@@ -261,20 +260,24 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0,
         */
        switch (operand0->common.type) {
        case ACPI_TYPE_INTEGER:
+
                status =
                    acpi_ex_convert_to_integer(operand1, &local_operand1, 16);
                break;
 
        case ACPI_TYPE_STRING:
+
                status = acpi_ex_convert_to_string(operand1, &local_operand1,
                                                   ACPI_IMPLICIT_CONVERT_HEX);
                break;
 
        case ACPI_TYPE_BUFFER:
+
                status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
                break;
 
        default:
+
                ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
                            operand0->common.type));
                status = AE_AML_INTERNAL;
@@ -519,6 +522,7 @@ acpi_ex_do_logical_numeric_op(u16 opcode,
                break;
 
        default:
+
                status = AE_AML_INTERNAL;
                break;
        }
@@ -580,20 +584,24 @@ acpi_ex_do_logical_op(u16 opcode,
         */
        switch (operand0->common.type) {
        case ACPI_TYPE_INTEGER:
+
                status =
                    acpi_ex_convert_to_integer(operand1, &local_operand1, 16);
                break;
 
        case ACPI_TYPE_STRING:
+
                status = acpi_ex_convert_to_string(operand1, &local_operand1,
                                                   ACPI_IMPLICIT_CONVERT_HEX);
                break;
 
        case ACPI_TYPE_BUFFER:
+
                status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
                break;
 
        default:
+
                status = AE_AML_INTERNAL;
                break;
        }
@@ -636,6 +644,7 @@ acpi_ex_do_logical_op(u16 opcode,
                        break;
 
                default:
+
                        status = AE_AML_INTERNAL;
                        break;
                }
@@ -703,6 +712,7 @@ acpi_ex_do_logical_op(u16 opcode,
                        break;
 
                default:
+
                        status = AE_AML_INTERNAL;
                        break;
                }
index b60c877f5906d9d8b7d00d9a022d3105f4aa2c2a..814b4a3d656ad1dc3d9acf438258735569017656 100644 (file)
@@ -327,7 +327,6 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
                        break;
 
                case AML_FROM_BCD_OP:   /* from_bcd (BCDValue, Result) */
-
                        /*
                         * The 64-bit ACPI integer can hold 16 4-bit BCD characters
                         * (if table is 32-bit, integer can hold 8 BCD characters)
@@ -407,7 +406,6 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
                        break;
 
                case AML_COND_REF_OF_OP:        /* cond_ref_of (source_object, Result) */
-
                        /*
                         * This op is a little strange because the internal return value is
                         * different than the return value stored in the result descriptor
@@ -442,13 +440,14 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
                        goto cleanup;
 
                default:
+
                        /* No other opcodes get here */
+
                        break;
                }
                break;
 
        case AML_STORE_OP:      /* Store (Source, Target) */
-
                /*
                 * A store operand is typically a number, string, buffer or lvalue
                 * Be careful about deleting the source object,
@@ -615,7 +614,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
 
        case AML_DECREMENT_OP:  /* Decrement (Operand)  */
        case AML_INCREMENT_OP:  /* Increment (Operand)  */
-
                /*
                 * Create a new integer. Can't just get the base integer and
                 * increment it because it may be an Arg or Field.
@@ -682,7 +680,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
                break;
 
        case AML_TYPE_OP:       /* object_type (source_object) */
-
                /*
                 * Note: The operand is not resolved at this point because we want to
                 * get the associated object, not its value. For example, we don't
@@ -709,7 +706,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
                break;
 
        case AML_SIZE_OF_OP:    /* size_of (source_object) */
-
                /*
                 * Note: The operand is not resolved at this point because we want to
                 * get the associated object, not its value.
@@ -735,10 +731,12 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
                 */
                switch (type) {
                case ACPI_TYPE_INTEGER:
+
                        value = acpi_gbl_integer_byte_width;
                        break;
 
                case ACPI_TYPE_STRING:
+
                        value = temp_desc->string.length;
                        break;
 
@@ -759,6 +757,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
                        break;
 
                default:
+
                        ACPI_ERROR((AE_INFO,
                                    "Operand must be Buffer/Integer/String/Package - found type %s",
                                    acpi_ut_get_type_name(type)));
@@ -860,9 +859,11 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
                                break;
 
                        case ACPI_TYPE_STRING:
+
                                break;
 
                        default:
+
                                status = AE_AML_OPERAND_TYPE;
                                goto cleanup;
                        }
@@ -923,7 +924,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
                         */
                        switch (operand[0]->reference.class) {
                        case ACPI_REFCLASS_INDEX:
-
                                /*
                                 * The target type for the Index operator must be
                                 * either a Buffer or a Package
@@ -956,7 +956,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
                                        break;
 
                                case ACPI_TYPE_PACKAGE:
-
                                        /*
                                         * Return the referenced element of the package. We must
                                         * add another reference to the referenced object, however.
@@ -999,6 +998,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
                                break;
 
                        default:
+
                                ACPI_ERROR((AE_INFO,
                                            "Unknown class in reference(%p) - 0x%2.2X",
                                            operand[0],
index b0838a4ea53e6fc70cb9b57a8b3fc2fab1b2bce7..d5088f7030c753fb9e36b78b25d894e2c48cf74c 100644 (file)
@@ -304,7 +304,6 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
                break;
 
        case AML_TO_STRING_OP:  /* to_string (Buffer, Length, Result) (ACPI 2.0) */
-
                /*
                 * Input object is guaranteed to be a buffer at this point (it may have
                 * been converted.)  Copy the raw buffer data to a new object of
index 2d7491f3126ef906ee6e589494f7936f20885166..37656f12f204bcd3b12ae6c1d8384eb392990e1a 100644 (file)
@@ -155,7 +155,6 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
 
        switch (walk_state->opcode) {
        case AML_MID_OP:        /* Mid (Source[0], Index[1], Length[2], Result[3]) */
-
                /*
                 * Create the return object. The Source operand is guaranteed to be
                 * either a String or a Buffer, so just use its type.
index b76b97002dffd1701741b5fe18031f3104580dfb..879b6cd8319cdc09023e3852da1efe1b51f84282 100644 (file)
@@ -119,7 +119,6 @@ acpi_ex_do_match(u32 match_op,
                break;
 
        case MATCH_MEQ:
-
                /*
                 * True if equal: (P[i] == M)
                 * Change to:     (M == P[i])
@@ -133,7 +132,6 @@ acpi_ex_do_match(u32 match_op,
                break;
 
        case MATCH_MLE:
-
                /*
                 * True if less than or equal: (P[i] <= M) (P[i] not_greater than M)
                 * Change to:                  (M >= P[i]) (M not_less than P[i])
@@ -148,7 +146,6 @@ acpi_ex_do_match(u32 match_op,
                break;
 
        case MATCH_MLT:
-
                /*
                 * True if less than: (P[i] < M)
                 * Change to:         (M > P[i])
@@ -162,7 +159,6 @@ acpi_ex_do_match(u32 match_op,
                break;
 
        case MATCH_MGE:
-
                /*
                 * True if greater than or equal: (P[i] >= M) (P[i] not_less than M)
                 * Change to:                     (M <= P[i]) (M not_greater than P[i])
@@ -177,7 +173,6 @@ acpi_ex_do_match(u32 match_op,
                break;
 
        case MATCH_MGT:
-
                /*
                 * True if greater than: (P[i] > M)
                 * Change to:            (M < P[i])
index 6b728aef2dcab54804d11509e23660b06e11d21e..5a588611ab484f12e33966fcbdf4ce2a03ffdc4e 100644 (file)
@@ -253,26 +253,31 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
 
        case AML_FIELD_ACCESS_BYTE:
        case AML_FIELD_ACCESS_BUFFER:   /* ACPI 2.0 (SMBus Buffer) */
+
                byte_alignment = 1;
                bit_length = 8;
                break;
 
        case AML_FIELD_ACCESS_WORD:
+
                byte_alignment = 2;
                bit_length = 16;
                break;
 
        case AML_FIELD_ACCESS_DWORD:
+
                byte_alignment = 4;
                bit_length = 32;
                break;
 
        case AML_FIELD_ACCESS_QWORD:    /* ACPI 2.0 */
+
                byte_alignment = 8;
                bit_length = 64;
                break;
 
        default:
+
                /* Invalid field access type */
 
                ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access));
@@ -598,7 +603,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
                break;
 
        default:
+
                /* No other types should get here */
+
                break;
        }
 
index 182abaf045e165588606bd4a52de7c98413717c1..303429bb4d5d6631878878a872b3f0c46f82f390 100644 (file)
@@ -88,22 +88,27 @@ acpi_ex_system_memory_space_handler(u32 function,
 
        switch (bit_width) {
        case 8:
+
                length = 1;
                break;
 
        case 16:
+
                length = 2;
                break;
 
        case 32:
+
                length = 4;
                break;
 
        case 64:
+
                length = 8;
                break;
 
        default:
+
                ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u",
                            bit_width));
                return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
@@ -214,23 +219,29 @@ acpi_ex_system_memory_space_handler(u32 function,
                *value = 0;
                switch (bit_width) {
                case 8:
-                       *value = (u64) ACPI_GET8(logical_addr_ptr);
+
+                       *value = (u64)ACPI_GET8(logical_addr_ptr);
                        break;
 
                case 16:
-                       *value = (u64) ACPI_GET16(logical_addr_ptr);
+
+                       *value = (u64)ACPI_GET16(logical_addr_ptr);
                        break;
 
                case 32:
-                       *value = (u64) ACPI_GET32(logical_addr_ptr);
+
+                       *value = (u64)ACPI_GET32(logical_addr_ptr);
                        break;
 
                case 64:
-                       *value = (u64) ACPI_GET64(logical_addr_ptr);
+
+                       *value = (u64)ACPI_GET64(logical_addr_ptr);
                        break;
 
                default:
+
                        /* bit_width was already validated */
+
                        break;
                }
                break;
@@ -239,28 +250,35 @@ acpi_ex_system_memory_space_handler(u32 function,
 
                switch (bit_width) {
                case 8:
+
                        ACPI_SET8(logical_addr_ptr, *value);
                        break;
 
                case 16:
+
                        ACPI_SET16(logical_addr_ptr, *value);
                        break;
 
                case 32:
+
                        ACPI_SET32(logical_addr_ptr, *value);
                        break;
 
                case 64:
+
                        ACPI_SET64(logical_addr_ptr, *value);
                        break;
 
                default:
+
                        /* bit_width was already validated */
+
                        break;
                }
                break;
 
        default:
+
                status = AE_BAD_PARAMETER;
                break;
        }
@@ -320,6 +338,7 @@ acpi_ex_system_io_space_handler(u32 function,
                break;
 
        default:
+
                status = AE_BAD_PARAMETER;
                break;
        }
index 8565b6bd12bb41a886aa8ad94d9355dd74d3a942..acd34f5993131d573aa6bcdf6046e7dd34afad12 100644 (file)
@@ -248,6 +248,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
                        break;
 
                default:
+
                        /* No named references are allowed here */
 
                        ACPI_ERROR((AE_INFO,
index e4f9dfbb2a13f737e37e65bba8d374a7e673a987..ac04278ad28f00294d6fc7a3034795bcbb1c0bfb 100644 (file)
@@ -156,7 +156,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
                switch (ref_type) {
                case ACPI_REFCLASS_LOCAL:
                case ACPI_REFCLASS_ARG:
-
                        /*
                         * Get the local from the method's state info
                         * Note: this increments the local's object reference count
@@ -309,6 +308,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
                break;
 
        default:
+
                break;
        }
 
@@ -348,10 +348,12 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
 
        switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
        case ACPI_DESC_TYPE_OPERAND:
+
                type = obj_desc->common.type;
                break;
 
        case ACPI_DESC_TYPE_NAMED:
+
                type = ((struct acpi_namespace_node *)obj_desc)->type;
                obj_desc =
                    acpi_ns_get_attached_object((struct acpi_namespace_node *)
@@ -538,7 +540,9 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
                break;
 
        default:
+
                /* No change to Type required */
+
                break;
        }
 
index 9fb9f5e9a4daefe2f3a477eeb222d6ba1e560719..00e5af7129c1234338e4c5f0aeddcde5941ce94d 100644 (file)
@@ -307,7 +307,6 @@ acpi_ex_resolve_operands(u16 opcode,
                case ARGI_TARGETREF:    /* Allows implicit conversion rules before store */
                case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */
                case ARGI_SIMPLE_TARGET:        /* Name, Local, or arg - no implicit conversion  */
-
                        /*
                         * Need an operand of type ACPI_TYPE_LOCAL_REFERENCE
                         * A Namespace Node is OK as-is
@@ -326,7 +325,6 @@ acpi_ex_resolve_operands(u16 opcode,
                        goto next_operand;
 
                case ARGI_DATAREFOBJ:   /* Store operator only */
-
                        /*
                         * We don't want to resolve index_op reference objects during
                         * a store because this would be an implicit de_ref_of operation.
@@ -343,7 +341,9 @@ acpi_ex_resolve_operands(u16 opcode,
                        break;
 
                default:
+
                        /* All cases covered above */
+
                        break;
                }
 
@@ -433,7 +433,6 @@ acpi_ex_resolve_operands(u16 opcode,
                        goto next_operand;
 
                case ARGI_BUFFER:
-
                        /*
                         * Need an operand of type ACPI_TYPE_BUFFER,
                         * But we can implicitly convert from a STRING or INTEGER
@@ -459,7 +458,6 @@ acpi_ex_resolve_operands(u16 opcode,
                        goto next_operand;
 
                case ARGI_STRING:
-
                        /*
                         * Need an operand of type ACPI_TYPE_STRING,
                         * But we can implicitly convert from a BUFFER or INTEGER
@@ -562,6 +560,7 @@ acpi_ex_resolve_operands(u16 opcode,
                                break;
 
                        default:
+
                                ACPI_ERROR((AE_INFO,
                                            "Needed [Buffer/String/Package/Reference], found [%s] %p",
                                            acpi_ut_get_object_type_name
@@ -584,6 +583,7 @@ acpi_ex_resolve_operands(u16 opcode,
                                break;
 
                        default:
+
                                ACPI_ERROR((AE_INFO,
                                            "Needed [Buffer/String/Package], found [%s] %p",
                                            acpi_ut_get_object_type_name
@@ -605,6 +605,7 @@ acpi_ex_resolve_operands(u16 opcode,
                                break;
 
                        default:
+
                                ACPI_ERROR((AE_INFO,
                                            "Needed [Region/Buffer], found [%s] %p",
                                            acpi_ut_get_object_type_name
index 93c6049c2d754d3e621729599510344e2d06d7dc..2bdba6f7d7620c43a8f6dafcbe83d5a14679f8b4 100644 (file)
@@ -114,6 +114,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
 
        switch (dest_desc->common.type) {
        case ACPI_TYPE_LOCAL_REFERENCE:
+
                break;
 
        case ACPI_TYPE_INTEGER:
@@ -178,7 +179,6 @@ acpi_ex_store(union acpi_operand_object *source_desc,
                break;
 
        case ACPI_REFCLASS_DEBUG:
-
                /*
                 * Storing to the Debug object causes the value stored to be
                 * displayed and otherwise has no effect -- see ACPI Specification
@@ -291,7 +291,6 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
                break;
 
        case ACPI_TYPE_BUFFER_FIELD:
-
                /*
                 * Store into a Buffer or String (not actually a real buffer_field)
                 * at a location defined by an Index.
@@ -447,7 +446,6 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
        case ACPI_TYPE_INTEGER:
        case ACPI_TYPE_STRING:
        case ACPI_TYPE_BUFFER:
-
                /*
                 * These target types are all of type Integer/String/Buffer, and
                 * therefore support implicit conversion before the store.
index 1cefe777068eef26b2d66851418c7992ede3244a..20d809d90c5b8f113e7b0f3c56fcafa58893dda2 100644 (file)
@@ -85,11 +85,9 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
                 * These cases all require only Integers or values that
                 * can be converted to Integers (Strings or Buffers)
                 */
-
        case ACPI_TYPE_INTEGER:
        case ACPI_TYPE_STRING:
        case ACPI_TYPE_BUFFER:
-
                /*
                 * Stores into a Field/Region or into a Integer/Buffer/String
                 * are all essentially the same. This case handles the
@@ -133,7 +131,6 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
 
        case ACPI_TYPE_LOCAL_ALIAS:
        case ACPI_TYPE_LOCAL_METHOD_ALIAS:
-
                /*
                 * All aliases should have been resolved earlier, during the
                 * operand resolution phase.
@@ -144,7 +141,6 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
 
        case ACPI_TYPE_PACKAGE:
        default:
-
                /*
                 * All other types than Alias and the various Fields come here,
                 * including the untyped case - ACPI_TYPE_ANY.
index 579c3a53ac87ede953e7610dab23f1270c6bafcc..3d36df828f520b1c196783453905c3f05f34543c 100644 (file)
@@ -108,7 +108,6 @@ acpi_status acpi_hw_set_mode(u32 mode)
                break;
 
        case ACPI_SYS_MODE_LEGACY:
-
                /*
                 * BIOS should clear all fixed status bits and restore fixed event
                 * enable bits to default
@@ -120,6 +119,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
                break;
 
        default:
+
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
index 20d02e93c99021e10038849b5290d77e360b55fc..96540506058fcc94351e2980feab2adf990d9ad6 100644 (file)
@@ -127,14 +127,17 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
                /*lint -fallthrough */
 
        case ACPI_GPE_ENABLE:
+
                ACPI_SET_BIT(enable_mask, register_bit);
                break;
 
        case ACPI_GPE_DISABLE:
+
                ACPI_CLEAR_BIT(enable_mask, register_bit);
                break;
 
        default:
+
                ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u", action));
                return (AE_BAD_PARAMETER);
        }
index 083d6551f0e2b2db97020d6e0ecc4e9d7ed85211..8d2e866be15f84a301183cf5690205785ec4f2ea 100644 (file)
@@ -419,6 +419,7 @@ acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
                break;
 
        default:
+
                ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
                status = AE_BAD_PARAMETER;
                break;
@@ -491,7 +492,6 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
                break;
 
        case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
-
                /*
                 * Perform a read first to preserve certain bits (per ACPI spec)
                 * Note: This includes SCI_EN, we never want to change this bit
@@ -520,7 +520,6 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
                break;
 
        case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
-
                /*
                 * For control registers, all reserved bits must be preserved,
                 * as per the ACPI spec.
@@ -555,6 +554,7 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
                break;
 
        default:
+
                ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
                status = AE_BAD_PARAMETER;
                break;
index 04c2e16f2c0a6ef86ab734cd309cfb1ce41d49db..5ee7a814cd9207db34d42b8945867e415ab733bb 100644 (file)
@@ -495,7 +495,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
         * Evaluate the \_Sx namespace object containing the register values
         * for this state
         */
-       info->pathname =
+       info->relative_pathname =
            ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
        status = acpi_ns_evaluate(info);
        if (ACPI_FAILURE(status)) {
@@ -506,7 +506,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
 
        if (!info->return_object) {
                ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
-                           info->pathname));
+                           info->relative_pathname));
                status = AE_AML_NO_RETURN_VALUE;
                goto cleanup;
        }
@@ -528,10 +528,12 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
        elements = info->return_object->package.elements;
        switch (info->return_object->package.count) {
        case 0:
+
                status = AE_AML_PACKAGE_LIMIT;
                break;
 
        case 1:
+
                if (elements[0]->common.type != ACPI_TYPE_INTEGER) {
                        status = AE_AML_OPERAND_TYPE;
                        break;
@@ -545,6 +547,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
 
        case 2:
        default:
+
                if ((elements[0]->common.type != ACPI_TYPE_INTEGER) ||
                    (elements[1]->common.type != ACPI_TYPE_INTEGER)) {
                        status = AE_AML_OPERAND_TYPE;
@@ -565,7 +568,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
        if (ACPI_FAILURE(status)) {
                ACPI_EXCEPTION((AE_INFO, status,
                                "While evaluating Sleep State [%s]",
-                               info->pathname));
+                               info->relative_pathname));
        }
 
        ACPI_FREE(info);
index 35eebdac0f9d1e02976d382376005abbe4a870a5..f2e669db8b65e90deddae8ee64a1e2b8ed3bfb39 100644 (file)
@@ -240,12 +240,14 @@ static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id)
            &acpi_sleep_dispatch[function_id];
 
 #if (!ACPI_REDUCED_HARDWARE)
-
        /*
         * If the Hardware Reduced flag is set (from the FADT), we must
-        * use the extended sleep registers
+        * use the extended sleep registers (FADT). Note: As per the ACPI
+        * specification, these extended registers are to be used for HW-reduced
+        * platforms only. They are not general-purpose replacements for the
+        * legacy PM register sleep support.
         */
-       if (acpi_gbl_reduced_hardware || acpi_gbl_FADT.sleep_control.address) {
+       if (acpi_gbl_reduced_hardware) {
                status = sleep_functions->extended_function(sleep_state);
        } else {
                /* Legacy sleep */
@@ -314,20 +316,24 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
 
        switch (sleep_state) {
        case ACPI_STATE_S0:
+
                sst_value = ACPI_SST_WORKING;
                break;
 
        case ACPI_STATE_S1:
        case ACPI_STATE_S2:
        case ACPI_STATE_S3:
+
                sst_value = ACPI_SST_SLEEPING;
                break;
 
        case ACPI_STATE_S4:
+
                sst_value = ACPI_SST_SLEEP_CONTEXT;
                break;
 
        default:
+
                sst_value = ACPI_SST_INDICATOR_OFF;     /* Default is off */
                break;
        }
index 8769cf83b044ff704db113a4ef7ffc8a5f78fbc0..c5316e5bd4abf2efce5aad7d4968708d3bccdb3d 100644 (file)
@@ -151,6 +151,7 @@ acpi_status acpi_ns_root_initialize(void)
                         */
                        switch (init_val->type) {
                        case ACPI_TYPE_METHOD:
+
                                obj_desc->method.param_count =
                                    (u8) ACPI_TO_INTEGER(val);
                                obj_desc->common.flags |= AOPOBJ_DATA_VALID;
diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c
new file mode 100644 (file)
index 0000000..74b24c8
--- /dev/null
@@ -0,0 +1,294 @@
+/******************************************************************************
+ *
+ * Module Name: nsarguments - Validation of args for ACPI predefined methods
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acpredef.h"
+
+#define _COMPONENT          ACPI_NAMESPACE
+ACPI_MODULE_NAME("nsarguments")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_check_argument_types
+ *
+ * PARAMETERS:  info            - Method execution information block
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Check the incoming argument count and all argument types
+ *              against the argument type list for a predefined name.
+ *
+ ******************************************************************************/
+void acpi_ns_check_argument_types(struct acpi_evaluate_info *info)
+{
+       u16 arg_type_list;
+       u8 arg_count;
+       u8 arg_type;
+       u8 user_arg_type;
+       u32 i;
+
+       /* If not a predefined name, cannot typecheck args */
+
+       if (!info->predefined) {
+               return;
+       }
+
+       arg_type_list = info->predefined->info.argument_list;
+       arg_count = METHOD_GET_ARG_COUNT(arg_type_list);
+
+       /* Typecheck all arguments */
+
+       for (i = 0; ((i < arg_count) && (i < info->param_count)); i++) {
+               arg_type = METHOD_GET_NEXT_TYPE(arg_type_list);
+               user_arg_type = info->parameters[i]->common.type;
+
+               if (user_arg_type != arg_type) {
+                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                             ACPI_WARN_ALWAYS,
+                                             "Argument #%u type mismatch - "
+                                             "Found [%s], ACPI requires [%s]",
+                                             (i + 1),
+                                             acpi_ut_get_type_name
+                                             (user_arg_type),
+                                             acpi_ut_get_type_name(arg_type)));
+               }
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_check_acpi_compliance
+ *
+ * PARAMETERS:  pathname        - Full pathname to the node (for error msgs)
+ *              node            - Namespace node for the method/object
+ *              predefined      - Pointer to entry in predefined name table
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Check that the declared parameter count (in ASL/AML) for a
+ *              predefined name is what is expected (matches what is defined in
+ *              the ACPI specification for this predefined name.)
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_check_acpi_compliance(char *pathname,
+                             struct acpi_namespace_node *node,
+                             const union acpi_predefined_info *predefined)
+{
+       u32 aml_param_count;
+       u32 required_param_count;
+
+       if (!predefined) {
+               return;
+       }
+
+       /* Get the ACPI-required arg count from the predefined info table */
+
+       required_param_count =
+           METHOD_GET_ARG_COUNT(predefined->info.argument_list);
+
+       /*
+        * If this object is not a control method, we can check if the ACPI
+        * spec requires that it be a method.
+        */
+       if (node->type != ACPI_TYPE_METHOD) {
+               if (required_param_count > 0) {
+
+                       /* Object requires args, must be implemented as a method */
+
+                       ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname,
+                                                   ACPI_WARN_ALWAYS,
+                                                   "Object (%s) must be a control method with %u arguments",
+                                                   acpi_ut_get_type_name(node->
+                                                                         type),
+                                                   required_param_count));
+               } else if (!required_param_count
+                          && !predefined->info.expected_btypes) {
+
+                       /* Object requires no args and no return value, must be a method */
+
+                       ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname,
+                                                   ACPI_WARN_ALWAYS,
+                                                   "Object (%s) must be a control method "
+                                                   "with no arguments and no return value",
+                                                   acpi_ut_get_type_name(node->
+                                                                         type)));
+               }
+
+               return;
+       }
+
+       /*
+        * This is a control method.
+        * Check that the ASL/AML-defined parameter count for this method
+        * matches the ACPI-required parameter count
+        *
+        * Some methods are allowed to have a "minimum" number of args (_SCP)
+        * because their definition in ACPI has changed over time.
+        *
+        * Note: These are BIOS errors in the declaration of the object
+        */
+       aml_param_count = node->object->method.param_count;
+
+       if (aml_param_count < required_param_count) {
+               ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS,
+                                           "Insufficient arguments - "
+                                           "ASL declared %u, ACPI requires %u",
+                                           aml_param_count,
+                                           required_param_count));
+       } else if ((aml_param_count > required_param_count)
+                  && !(predefined->info.
+                       argument_list & ARG_COUNT_IS_MINIMUM)) {
+               ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS,
+                                           "Excess arguments - "
+                                           "ASL declared %u, ACPI requires %u",
+                                           aml_param_count,
+                                           required_param_count));
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_check_argument_count
+ *
+ * PARAMETERS:  pathname        - Full pathname to the node (for error msgs)
+ *              node            - Namespace node for the method/object
+ *              user_param_count - Number of args passed in by the caller
+ *              predefined      - Pointer to entry in predefined name table
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Check that incoming argument count matches the declared
+ *              parameter count (in the ASL/AML) for an object.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_check_argument_count(char *pathname,
+                            struct acpi_namespace_node *node,
+                            u32 user_param_count,
+                            const union acpi_predefined_info *predefined)
+{
+       u32 aml_param_count;
+       u32 required_param_count;
+
+       if (!predefined) {
+               /*
+                * Not a predefined name. Check the incoming user argument count
+                * against the count that is specified in the method/object.
+                */
+               if (node->type != ACPI_TYPE_METHOD) {
+                       if (user_param_count) {
+                               ACPI_INFO_PREDEFINED((AE_INFO, pathname,
+                                                     ACPI_WARN_ALWAYS,
+                                                     "%u arguments were passed to a non-method ACPI object (%s)",
+                                                     user_param_count,
+                                                     acpi_ut_get_type_name
+                                                     (node->type)));
+                       }
+
+                       return;
+               }
+
+               /*
+                * This is a control method. Check the parameter count.
+                * We can only check the incoming argument count against the
+                * argument count declared for the method in the ASL/AML.
+                *
+                * Emit a message if too few or too many arguments have been passed
+                * by the caller.
+                *
+                * Note: Too many arguments will not cause the method to
+                * fail. However, the method will fail if there are too few
+                * arguments and the method attempts to use one of the missing ones.
+                */
+               aml_param_count = node->object->method.param_count;
+
+               if (user_param_count < aml_param_count) {
+                       ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+                                             ACPI_WARN_ALWAYS,
+                                             "Insufficient arguments - "
+                                             "Caller passed %u, method requires %u",
+                                             user_param_count,
+                                             aml_param_count));
+               } else if (user_param_count > aml_param_count) {
+                       ACPI_INFO_PREDEFINED((AE_INFO, pathname,
+                                             ACPI_WARN_ALWAYS,
+                                             "Excess arguments - "
+                                             "Caller passed %u, method requires %u",
+                                             user_param_count,
+                                             aml_param_count));
+               }
+
+               return;
+       }
+
+       /*
+        * This is a predefined name. Validate the user-supplied parameter
+        * count against the ACPI specification. We don't validate against
+        * the method itself because what is important here is that the
+        * caller is in conformance with the spec. (The arg count for the
+        * method was checked against the ACPI spec earlier.)
+        *
+        * Some methods are allowed to have a "minimum" number of args (_SCP)
+        * because their definition in ACPI has changed over time.
+        */
+       required_param_count =
+           METHOD_GET_ARG_COUNT(predefined->info.argument_list);
+
+       if (user_param_count < required_param_count) {
+               ACPI_WARN_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS,
+                                     "Insufficient arguments - "
+                                     "Caller passed %u, ACPI requires %u",
+                                     user_param_count, required_param_count));
+       } else if ((user_param_count > required_param_count) &&
+                  !(predefined->info.argument_list & ARG_COUNT_IS_MINIMUM)) {
+               ACPI_INFO_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS,
+                                     "Excess arguments - "
+                                     "Caller passed %u, ACPI requires %u",
+                                     user_param_count, required_param_count));
+       }
+}
index 8f79a9d2d50ec659f157e0c3ccd011d81c0658df..acd2964c26906f995b159bd382a42ce000cfa2c3 100644 (file)
@@ -103,6 +103,7 @@ acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
                break;
 
        default:
+
                return (AE_AML_OPERAND_TYPE);
        }
 
@@ -191,6 +192,7 @@ acpi_ns_convert_to_string(union acpi_operand_object *original_object,
                break;
 
        default:
+
                return (AE_AML_OPERAND_TYPE);
        }
 
@@ -294,6 +296,7 @@ acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
                break;
 
        default:
+
                return (AE_AML_OPERAND_TYPE);
        }
 
index ce6e9732620523ba36e1a474d76dddfcf03005d9..7418c77fde8c70db88d0d0af9c0c6a8fcad6cad5 100644 (file)
@@ -244,10 +244,12 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
                        case ACPI_TYPE_BUFFER:
                        case ACPI_TYPE_STRING:
                        case ACPI_TYPE_METHOD:
+
                                acpi_os_printf("<No attached object>");
                                break;
 
                        default:
+
                                break;
                        }
 
@@ -433,6 +435,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
                        break;
 
                default:
+
                        break;
                }
                break;
@@ -567,32 +570,39 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
                        goto cleanup;
 
                case ACPI_TYPE_BUFFER_FIELD:
+
                        obj_desc =
                            (union acpi_operand_object *)obj_desc->buffer_field.
                            buffer_obj;
                        break;
 
                case ACPI_TYPE_PACKAGE:
+
                        obj_desc = (void *)obj_desc->package.elements;
                        break;
 
                case ACPI_TYPE_METHOD:
+
                        obj_desc = (void *)obj_desc->method.aml_start;
                        break;
 
                case ACPI_TYPE_LOCAL_REGION_FIELD:
+
                        obj_desc = (void *)obj_desc->field.region_obj;
                        break;
 
                case ACPI_TYPE_LOCAL_BANK_FIELD:
+
                        obj_desc = (void *)obj_desc->bank_field.region_obj;
                        break;
 
                case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
                        obj_desc = (void *)obj_desc->index_field.index_obj;
                        break;
 
                default:
+
                        goto cleanup;
                }
 
index b61db69d56752160e5be0e4bd0ab430d2871fcb5..18108bc2e51cd76833c42b13d6c6e6e678bcb976 100644 (file)
@@ -61,7 +61,7 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
  *
  * PARAMETERS:  info            - Evaluation info block, contains:
  *                  prefix_node     - Prefix or Method/Object Node to execute
- *                  pathname        - Name of method to execute, If NULL, the
+ *                  relative_path   - Name of method to execute, If NULL, the
  *                                    Node is the object to execute
  *                  parameters      - List of parameters to pass to the method,
  *                                    terminated by NULL. Params itself may be
@@ -82,10 +82,9 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
  *
  ******************************************************************************/
 
-acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
+acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
 {
        acpi_status status;
-       struct acpi_namespace_node *node;
 
        ACPI_FUNCTION_TRACE(ns_evaluate);
 
@@ -93,83 +92,138 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       /* Initialize the return value to an invalid object */
-
-       info->return_object = NULL;
-       info->param_count = 0;
-
-       if (!info->resolved_node) {
+       if (!info->node) {
                /*
-                * Get the actual namespace node for the target object if we need to.
-                * Handles these cases:
+                * Get the actual namespace node for the target object if we
+                * need to. Handles these cases:
                 *
-                * 1) Null node, Pathname (absolute path)
-                * 2) Node, Pathname (path relative to Node)
-                * 3) Node, Null Pathname
+                * 1) Null node, valid pathname from root (absolute path)
+                * 2) Node and valid pathname (path relative to Node)
+                * 3) Node, Null pathname
                 */
-               status = acpi_ns_get_node(info->prefix_node, info->pathname,
-                                         ACPI_NS_NO_UPSEARCH,
-                                         &info->resolved_node);
+               status =
+                   acpi_ns_get_node(info->prefix_node, info->relative_pathname,
+                                    ACPI_NS_NO_UPSEARCH, &info->node);
                if (ACPI_FAILURE(status)) {
                        return_ACPI_STATUS(status);
                }
        }
 
        /*
-        * For a method alias, we must grab the actual method node so that proper
-        * scoping context will be established before execution.
+        * For a method alias, we must grab the actual method node so that
+        * proper scoping context will be established before execution.
         */
-       if (acpi_ns_get_type(info->resolved_node) ==
-           ACPI_TYPE_LOCAL_METHOD_ALIAS) {
-               info->resolved_node =
+       if (acpi_ns_get_type(info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
+               info->node =
                    ACPI_CAST_PTR(struct acpi_namespace_node,
-                                 info->resolved_node->object);
+                                 info->node->object);
+       }
+
+       /* Complete the info block initialization */
+
+       info->return_object = NULL;
+       info->node_flags = info->node->flags;
+       info->obj_desc = acpi_ns_get_attached_object(info->node);
+
+       ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n",
+                         info->relative_pathname, info->node,
+                         acpi_ns_get_attached_object(info->node)));
+
+       /* Get info if we have a predefined name (_HID, etc.) */
+
+       info->predefined =
+           acpi_ut_match_predefined_method(info->node->name.ascii);
+
+       /* Get the full pathname to the object, for use in warning messages */
+
+       info->full_pathname = acpi_ns_get_external_pathname(info->node);
+       if (!info->full_pathname) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
-       ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", info->pathname,
-                         info->resolved_node,
-                         acpi_ns_get_attached_object(info->resolved_node)));
+       /* Count the number of arguments being passed in */
+
+       info->param_count = 0;
+       if (info->parameters) {
+               while (info->parameters[info->param_count]) {
+                       info->param_count++;
+               }
+
+               /* Warn on impossible argument count */
+
+               if (info->param_count > ACPI_METHOD_NUM_ARGS) {
+                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                             ACPI_WARN_ALWAYS,
+                                             "Excess arguments (%u) - using only %u",
+                                             info->param_count,
+                                             ACPI_METHOD_NUM_ARGS));
+
+                       info->param_count = ACPI_METHOD_NUM_ARGS;
+               }
+       }
+
+       /*
+        * For predefined names: Check that the declared argument count
+        * matches the ACPI spec -- otherwise this is a BIOS error.
+        */
+       acpi_ns_check_acpi_compliance(info->full_pathname, info->node,
+                                     info->predefined);
+
+       /*
+        * For all names: Check that the incoming argument count for
+        * this method/object matches the actual ASL/AML definition.
+        */
+       acpi_ns_check_argument_count(info->full_pathname, info->node,
+                                    info->param_count, info->predefined);
 
-       node = info->resolved_node;
+       /* For predefined names: Typecheck all incoming arguments */
+
+       acpi_ns_check_argument_types(info);
 
        /*
-        * Two major cases here:
+        * Three major evaluation cases:
         *
-        * 1) The object is a control method -- execute it
-        * 2) The object is not a method -- just return it's current value
+        * 1) Object types that cannot be evaluated by definition
+        * 2) The object is a control method -- execute it
+        * 3) The object is not a method -- just return it's current value
         */
-       if (acpi_ns_get_type(info->resolved_node) == ACPI_TYPE_METHOD) {
+       switch (acpi_ns_get_type(info->node)) {
+       case ACPI_TYPE_DEVICE:
+       case ACPI_TYPE_EVENT:
+       case ACPI_TYPE_MUTEX:
+       case ACPI_TYPE_REGION:
+       case ACPI_TYPE_THERMAL:
+       case ACPI_TYPE_LOCAL_SCOPE:
+               /*
+                * 1) Disallow evaluation of certain object types. For these,
+                *    object evaluation is undefined and not supported.
+                */
+               ACPI_ERROR((AE_INFO,
+                           "%s: Evaluation of object type [%s] is not supported",
+                           info->full_pathname,
+                           acpi_ut_get_type_name(info->node->type)));
+
+               status = AE_TYPE;
+               goto cleanup;
+
+       case ACPI_TYPE_METHOD:
                /*
-                * 1) Object is a control method - execute it
+                * 2) Object is a control method - execute it
                 */
 
                /* Verify that there is a method object associated with this node */
 
-               info->obj_desc =
-                   acpi_ns_get_attached_object(info->resolved_node);
                if (!info->obj_desc) {
                        ACPI_ERROR((AE_INFO,
-                                   "Control method has no attached sub-object"));
-                       return_ACPI_STATUS(AE_NULL_OBJECT);
+                                   "%s: Method has no attached sub-object",
+                                   info->full_pathname));
+                       status = AE_NULL_OBJECT;
+                       goto cleanup;
                }
 
-               /* Count the number of arguments being passed to the method */
-
-               if (info->parameters) {
-                       while (info->parameters[info->param_count]) {
-                               if (info->param_count > ACPI_METHOD_MAX_ARG) {
-                                       return_ACPI_STATUS(AE_LIMIT);
-                               }
-                               info->param_count++;
-                       }
-               }
-
-
-               ACPI_DUMP_PATHNAME(info->resolved_node, "ACPI: Execute Method",
-                                  ACPI_LV_INFO, _COMPONENT);
-
                ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-                                 "Method at AML address %p Length %X\n",
+                                 "**** Execute method [%s] at AML address %p length %X\n",
+                                 info->full_pathname,
                                  info->obj_desc->method.aml_start + 1,
                                  info->obj_desc->method.aml_length - 1));
 
@@ -184,81 +238,61 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
                acpi_ex_enter_interpreter();
                status = acpi_ps_execute_method(info);
                acpi_ex_exit_interpreter();
-       } else {
+               break;
+
+       default:
                /*
-                * 2) Object is not a method, return its current value
-                *
-                * Disallow certain object types. For these, "evaluation" is undefined.
+                * 3) All other non-method objects -- get the current object value
                 */
-               switch (info->resolved_node->type) {
-               case ACPI_TYPE_DEVICE:
-               case ACPI_TYPE_EVENT:
-               case ACPI_TYPE_MUTEX:
-               case ACPI_TYPE_REGION:
-               case ACPI_TYPE_THERMAL:
-               case ACPI_TYPE_LOCAL_SCOPE:
-
-                       ACPI_ERROR((AE_INFO,
-                                   "[%4.4s] Evaluation of object type [%s] is not supported",
-                                   info->resolved_node->name.ascii,
-                                   acpi_ut_get_type_name(info->resolved_node->
-                                                         type)));
-
-                       return_ACPI_STATUS(AE_TYPE);
-
-               default:
-                       break;
-               }
 
                /*
-                * Objects require additional resolution steps (e.g., the Node may be
-                * a field that must be read, etc.) -- we can't just grab the object
-                * out of the node.
+                * Some objects require additional resolution steps (e.g., the Node
+                * may be a field that must be read, etc.) -- we can't just grab
+                * the object out of the node.
                 *
                 * Use resolve_node_to_value() to get the associated value.
                 *
                 * NOTE: we can get away with passing in NULL for a walk state because
-                * resolved_node is guaranteed to not be a reference to either a method
+                * the Node is guaranteed to not be a reference to either a method
                 * local or a method argument (because this interface is never called
                 * from a running method.)
                 *
                 * Even though we do not directly invoke the interpreter for object
-                * resolution, we must lock it because we could access an opregion.
-                * The opregion access code assumes that the interpreter is locked.
+                * resolution, we must lock it because we could access an op_region.
+                * The op_region access code assumes that the interpreter is locked.
                 */
                acpi_ex_enter_interpreter();
 
-               /* Function has a strange interface */
+               /* TBD: resolve_node_to_value has a strange interface, fix */
+
+               info->return_object =
+                   ACPI_CAST_PTR(union acpi_operand_object, info->node);
 
                status =
-                   acpi_ex_resolve_node_to_value(&info->resolved_node, NULL);
+                   acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR
+                                                 (struct acpi_namespace_node,
+                                                  &info->return_object), NULL);
                acpi_ex_exit_interpreter();
 
-               /*
-                * If acpi_ex_resolve_node_to_value() succeeded, the return value was placed
-                * in resolved_node.
-                */
-               if (ACPI_SUCCESS(status)) {
-                       status = AE_CTRL_RETURN_VALUE;
-                       info->return_object =
-                           ACPI_CAST_PTR(union acpi_operand_object,
-                                         info->resolved_node);
-
-                       ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
-                                         "Returning object %p [%s]\n",
-                                         info->return_object,
-                                         acpi_ut_get_object_type_name(info->
-                                                                      return_object)));
+               if (ACPI_FAILURE(status)) {
+                       goto cleanup;
                }
+
+               ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Returned object %p [%s]\n",
+                                 info->return_object,
+                                 acpi_ut_get_object_type_name(info->
+                                                              return_object)));
+
+               status = AE_CTRL_RETURN_VALUE;  /* Always has a "return value" */
+               break;
        }
 
        /*
-        * Check input argument count against the ASL-defined count for a method.
-        * Also check predefined names: argument count and return value against
-        * the ACPI specification. Some incorrect return value types are repaired.
+        * For predefined names, check the return value against the ACPI
+        * specification. Some incorrect return value types are repaired.
         */
-       (void)acpi_ns_check_predefined_names(node, info->param_count,
-               status, &info->return_object);
+       (void)acpi_ns_check_return_value(info->node, info, info->param_count,
+                                        status, &info->return_object);
 
        /* Check if there is a return value that must be dealt with */
 
@@ -278,12 +312,15 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
 
        ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
                          "*** Completed evaluation of object %s ***\n",
-                         info->pathname));
+                         info->relative_pathname));
 
+ cleanup:
        /*
         * Namespace was unlocked by the handling acpi_ns* function, so we
-        * just return
+        * just free the pathname and return
         */
+       ACPI_FREE(info->full_pathname);
+       info->full_pathname = NULL;
        return_ACPI_STATUS(status);
 }
 
index 46f0f83417a1024613c39be6fe036996350107a7..dd2ceae3f7177aff169e56391292794c0651a74c 100644 (file)
@@ -176,7 +176,7 @@ acpi_status acpi_ns_initialize_devices(void)
         * part of the ACPI specification.
         */
        info.evaluate_info->prefix_node = acpi_gbl_root_node;
-       info.evaluate_info->pathname = METHOD_NAME__INI;
+       info.evaluate_info->relative_pathname = METHOD_NAME__INI;
        info.evaluate_info->parameters = NULL;
        info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE;
 
@@ -266,28 +266,34 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
 
        switch (type) {
        case ACPI_TYPE_REGION:
+
                info->op_region_count++;
                break;
 
        case ACPI_TYPE_BUFFER_FIELD:
+
                info->field_count++;
                break;
 
        case ACPI_TYPE_LOCAL_BANK_FIELD:
+
                info->field_count++;
                break;
 
        case ACPI_TYPE_BUFFER:
+
                info->buffer_count++;
                break;
 
        case ACPI_TYPE_PACKAGE:
+
                info->package_count++;
                break;
 
        default:
 
                /* No init required, just exit now */
+
                return (AE_OK);
        }
 
@@ -337,7 +343,9 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
                break;
 
        default:
+
                /* No other types can get here */
+
                break;
        }
 
@@ -416,6 +424,7 @@ acpi_ns_find_ini_methods(acpi_handle obj_handle,
                break;
 
        default:
+
                break;
        }
 
@@ -560,7 +569,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle,
 
        ACPI_MEMSET(info, 0, sizeof(struct acpi_evaluate_info));
        info->prefix_node = device_node;
-       info->pathname = METHOD_NAME__INI;
+       info->relative_pathname = METHOD_NAME__INI;
        info->parameters = NULL;
        info->flags = ACPI_IGNORE_RETURN_VALUE;
 
@@ -574,8 +583,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle,
 
                /* Ignore error and move on to next device */
 
-               char *scope_name =
-                   acpi_ns_get_external_pathname(info->resolved_node);
+               char *scope_name = acpi_ns_get_external_pathname(info->node);
 
                ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution",
                                scope_name));
index 8a52916148cb005a1dbe3da762788db2741b7a9a..24b71a01bf9398340c6c01f68c990ac7caa8c51f 100644 (file)
@@ -61,28 +61,29 @@ ACPI_MODULE_NAME("nspredef")
  * There are several areas that are validated:
  *
  *  1) The number of input arguments as defined by the method/object in the
- *      ASL is validated against the ACPI specification.
+ *     ASL is validated against the ACPI specification.
  *  2) The type of the return object (if any) is validated against the ACPI
- *      specification.
+ *     specification.
  *  3) For returned package objects, the count of package elements is
- *      validated, as well as the type of each package element. Nested
- *      packages are supported.
+ *     validated, as well as the type of each package element. Nested
+ *     packages are supported.
  *
  * For any problems found, a warning message is issued.
  *
  ******************************************************************************/
 /* Local prototypes */
 static acpi_status
-acpi_ns_check_reference(struct acpi_predefined_data *data,
+acpi_ns_check_reference(struct acpi_evaluate_info *info,
                        union acpi_operand_object *return_object);
 
 static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object);
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ns_check_predefined_names
+ * FUNCTION:    acpi_ns_check_return_value
  *
  * PARAMETERS:  node            - Namespace node for the method/object
+ *              info            - Method execution information block
  *              user_param_count - Number of parameters actually passed
  *              return_status   - Status from the object evaluation
  *              return_object_ptr - Pointer to the object returned from the
@@ -90,44 +91,25 @@ static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object);
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Check an ACPI name for a match in the predefined name list.
+ * DESCRIPTION: Check the value returned from a predefined name.
  *
  ******************************************************************************/
 
 acpi_status
-acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
-                              u32 user_param_count,
-                              acpi_status return_status,
-                              union acpi_operand_object **return_object_ptr)
+acpi_ns_check_return_value(struct acpi_namespace_node *node,
+                          struct acpi_evaluate_info *info,
+                          u32 user_param_count,
+                          acpi_status return_status,
+                          union acpi_operand_object **return_object_ptr)
 {
-       acpi_status status = AE_OK;
+       acpi_status status;
        const union acpi_predefined_info *predefined;
-       char *pathname;
-       struct acpi_predefined_data *data;
-
-       /* Match the name for this method/object against the predefined list */
-
-       predefined = acpi_ut_match_predefined_method(node->name.ascii);
-
-       /* Get the full pathname to the object, for use in warning messages */
-
-       pathname = acpi_ns_get_external_pathname(node);
-       if (!pathname) {
-               return (AE_OK); /* Could not get pathname, ignore */
-       }
-
-       /*
-        * Check that the parameter count for this method matches the ASL
-        * definition. For predefined names, ensure that both the caller and
-        * the method itself are in accordance with the ACPI specification.
-        */
-       acpi_ns_check_parameter_count(pathname, node, user_param_count,
-                                     predefined);
 
        /* If not a predefined name, we cannot validate the return object */
 
+       predefined = info->predefined;
        if (!predefined) {
-               goto cleanup;
+               return (AE_OK);
        }
 
        /*
@@ -135,7 +117,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
         * validate the return object
         */
        if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) {
-               goto cleanup;
+               return (AE_OK);
        }
 
        /*
@@ -154,25 +136,14 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
        if (acpi_gbl_disable_auto_repair ||
            (!predefined->info.expected_btypes) ||
            (predefined->info.expected_btypes == ACPI_RTYPE_ALL)) {
-               goto cleanup;
-       }
-
-       /* Create the parameter data block for object validation */
-
-       data = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_predefined_data));
-       if (!data) {
-               goto cleanup;
+               return (AE_OK);
        }
-       data->predefined = predefined;
-       data->node = node;
-       data->node_flags = node->flags;
-       data->pathname = pathname;
 
        /*
         * Check that the type of the main return object is what is expected
         * for this predefined name
         */
-       status = acpi_ns_check_object_type(data, return_object_ptr,
+       status = acpi_ns_check_object_type(info, return_object_ptr,
                                           predefined->info.expected_btypes,
                                           ACPI_NOT_PACKAGE_ELEMENT);
        if (ACPI_FAILURE(status)) {
@@ -184,10 +155,16 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
         * Note: Package may have been newly created by call above.
         */
        if ((*return_object_ptr)->common.type == ACPI_TYPE_PACKAGE) {
-               data->parent_package = *return_object_ptr;
-               status = acpi_ns_check_package(data, return_object_ptr);
+               info->parent_package = *return_object_ptr;
+               status = acpi_ns_check_package(info, return_object_ptr);
                if (ACPI_FAILURE(status)) {
-                       goto exit;
+
+                       /* We might be able to fix some errors */
+
+                       if ((status != AE_AML_OPERAND_TYPE) &&
+                           (status != AE_AML_OPERAND_VALUE)) {
+                               goto exit;
+                       }
                }
        }
 
@@ -199,7 +176,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
         * performed on a per-name basis, i.e., the code is specific to
         * particular predefined names.
         */
-       status = acpi_ns_complex_repairs(data, node, status, return_object_ptr);
+       status = acpi_ns_complex_repairs(info, node, status, return_object_ptr);
 
 exit:
        /*
@@ -207,112 +184,18 @@ exit:
         * or more objects, mark the parent node to suppress further warning
         * messages during the next evaluation of the same method/object.
         */
-       if (ACPI_FAILURE(status) || (data->flags & ACPI_OBJECT_REPAIRED)) {
+       if (ACPI_FAILURE(status) || (info->return_flags & ACPI_OBJECT_REPAIRED)) {
                node->flags |= ANOBJ_EVALUATED;
        }
-       ACPI_FREE(data);
 
-cleanup:
-       ACPI_FREE(pathname);
        return (status);
 }
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ns_check_parameter_count
- *
- * PARAMETERS:  pathname        - Full pathname to the node (for error msgs)
- *              node            - Namespace node for the method/object
- *              user_param_count - Number of args passed in by the caller
- *              predefined      - Pointer to entry in predefined name table
- *
- * RETURN:      None
- *
- * DESCRIPTION: Check that the declared (in ASL/AML) parameter count for a
- *              predefined name is what is expected (i.e., what is defined in
- *              the ACPI specification for this predefined name.)
- *
- ******************************************************************************/
-
-void
-acpi_ns_check_parameter_count(char *pathname,
-                             struct acpi_namespace_node *node,
-                             u32 user_param_count,
-                             const union acpi_predefined_info *predefined)
-{
-       u32 param_count;
-       u32 required_params_current;
-       u32 required_params_old;
-
-       /* Methods have 0-7 parameters. All other types have zero. */
-
-       param_count = 0;
-       if (node->type == ACPI_TYPE_METHOD) {
-               param_count = node->object->method.param_count;
-       }
-
-       if (!predefined) {
-               /*
-                * Check the parameter count for non-predefined methods/objects.
-                *
-                * Warning if too few or too many arguments have been passed by the
-                * caller. An incorrect number of arguments may not cause the method
-                * to fail. However, the method will fail if there are too few
-                * arguments and the method attempts to use one of the missing ones.
-                */
-               if (user_param_count < param_count) {
-                       ACPI_WARN_PREDEFINED((AE_INFO, pathname,
-                                             ACPI_WARN_ALWAYS,
-                                             "Insufficient arguments - needs %u, found %u",
-                                             param_count, user_param_count));
-               } else if (user_param_count > param_count) {
-                       ACPI_WARN_PREDEFINED((AE_INFO, pathname,
-                                             ACPI_WARN_ALWAYS,
-                                             "Excess arguments - needs %u, found %u",
-                                             param_count, user_param_count));
-               }
-               return;
-       }
-
-       /*
-        * Validate the user-supplied parameter count.
-        * Allow two different legal argument counts (_SCP, etc.)
-        */
-       required_params_current =
-           predefined->info.argument_list & METHOD_ARG_MASK;
-       required_params_old =
-           predefined->info.argument_list >> METHOD_ARG_BIT_WIDTH;
-
-       if (user_param_count != ACPI_UINT32_MAX) {
-               if ((user_param_count != required_params_current) &&
-                   (user_param_count != required_params_old)) {
-                       ACPI_WARN_PREDEFINED((AE_INFO, pathname,
-                                             ACPI_WARN_ALWAYS,
-                                             "Parameter count mismatch - "
-                                             "caller passed %u, ACPI requires %u",
-                                             user_param_count,
-                                             required_params_current));
-               }
-       }
-
-       /*
-        * Check that the ASL-defined parameter count is what is expected for
-        * this predefined name (parameter count as defined by the ACPI
-        * specification)
-        */
-       if ((param_count != required_params_current) &&
-           (param_count != required_params_old)) {
-               ACPI_WARN_PREDEFINED((AE_INFO, pathname, node->flags,
-                                     "Parameter count mismatch - ASL declared %u, ACPI requires %u",
-                                     param_count, required_params_current));
-       }
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ns_check_object_type
  *
- * PARAMETERS:  data            - Pointer to validation data structure
+ * PARAMETERS:  info            - Method execution information block
  *              return_object_ptr - Pointer to the object returned from the
  *                                evaluation of a method or object
  *              expected_btypes - Bitmap of expected return type(s)
@@ -328,7 +211,7 @@ acpi_ns_check_parameter_count(char *pathname,
  ******************************************************************************/
 
 acpi_status
-acpi_ns_check_object_type(struct acpi_predefined_data *data,
+acpi_ns_check_object_type(struct acpi_evaluate_info *info,
                          union acpi_operand_object **return_object_ptr,
                          u32 expected_btypes, u32 package_index)
 {
@@ -340,7 +223,8 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
 
        if (return_object &&
            ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) {
-               ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+               ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                     info->node_flags,
                                      "Invalid return type - Found a Namespace node [%4.4s] type %s",
                                      return_object->node.name.ascii,
                                      acpi_ut_get_type_name(return_object->node.
@@ -356,8 +240,8 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
         * from all of the predefined names (including elements of returned
         * packages)
         */
-       data->return_btype = acpi_ns_get_bitmapped_type(return_object);
-       if (data->return_btype == ACPI_RTYPE_ANY) {
+       info->return_btype = acpi_ns_get_bitmapped_type(return_object);
+       if (info->return_btype == ACPI_RTYPE_ANY) {
 
                /* Not one of the supported objects, must be incorrect */
                goto type_error_exit;
@@ -365,16 +249,18 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
 
        /* For reference objects, check that the reference type is correct */
 
-       if ((data->return_btype & expected_btypes) == ACPI_RTYPE_REFERENCE) {
-               status = acpi_ns_check_reference(data, return_object);
+       if ((info->return_btype & expected_btypes) == ACPI_RTYPE_REFERENCE) {
+               status = acpi_ns_check_reference(info, return_object);
                return (status);
        }
 
        /* Attempt simple repair of the returned object if necessary */
 
-       status = acpi_ns_simple_repair(data, expected_btypes,
+       status = acpi_ns_simple_repair(info, expected_btypes,
                                       package_index, return_object_ptr);
-       return (status);
+       if (ACPI_SUCCESS(status)) {
+               return (AE_OK); /* Successful repair */
+       }
 
       type_error_exit:
 
@@ -383,12 +269,14 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
        acpi_ut_get_expected_return_types(type_buffer, expected_btypes);
 
        if (package_index == ACPI_NOT_PACKAGE_ELEMENT) {
-               ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+               ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                     info->node_flags,
                                      "Return type mismatch - found %s, expected %s",
                                      acpi_ut_get_object_type_name
                                      (return_object), type_buffer));
        } else {
-               ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+               ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                     info->node_flags,
                                      "Return Package type mismatch at index %u - "
                                      "found %s, expected %s", package_index,
                                      acpi_ut_get_object_type_name
@@ -402,7 +290,7 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
  *
  * FUNCTION:    acpi_ns_check_reference
  *
- * PARAMETERS:  data            - Pointer to validation data structure
+ * PARAMETERS:  info            - Method execution information block
  *              return_object   - Object returned from the evaluation of a
  *                                method or object
  *
@@ -415,7 +303,7 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
  ******************************************************************************/
 
 static acpi_status
-acpi_ns_check_reference(struct acpi_predefined_data *data,
+acpi_ns_check_reference(struct acpi_evaluate_info *info,
                        union acpi_operand_object *return_object)
 {
 
@@ -428,7 +316,7 @@ acpi_ns_check_reference(struct acpi_predefined_data *data,
                return (AE_OK);
        }
 
-       ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
                              "Return type mismatch - unexpected reference object type [%s] %2.2X",
                              acpi_ut_get_reference_name(return_object),
                              return_object->reference.class));
@@ -462,26 +350,32 @@ static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object)
 
        switch (return_object->common.type) {
        case ACPI_TYPE_INTEGER:
+
                return_btype = ACPI_RTYPE_INTEGER;
                break;
 
        case ACPI_TYPE_BUFFER:
+
                return_btype = ACPI_RTYPE_BUFFER;
                break;
 
        case ACPI_TYPE_STRING:
+
                return_btype = ACPI_RTYPE_STRING;
                break;
 
        case ACPI_TYPE_PACKAGE:
+
                return_btype = ACPI_RTYPE_PACKAGE;
                break;
 
        case ACPI_TYPE_LOCAL_REFERENCE:
+
                return_btype = ACPI_RTYPE_REFERENCE;
                break;
 
        default:
+
                /* Not one of the supported objects, must be incorrect */
 
                return_btype = ACPI_RTYPE_ANY;
index 77cdd539de16c7030659a5df53cf706497e30540..6d55cef7916c4ba4715a9108697073822edc48ec 100644 (file)
@@ -51,12 +51,12 @@ ACPI_MODULE_NAME("nsprepkg")
 
 /* Local prototypes */
 static acpi_status
-acpi_ns_check_package_list(struct acpi_predefined_data *data,
+acpi_ns_check_package_list(struct acpi_evaluate_info *info,
                           const union acpi_predefined_info *package,
                           union acpi_operand_object **elements, u32 count);
 
 static acpi_status
-acpi_ns_check_package_elements(struct acpi_predefined_data *data,
+acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
                               union acpi_operand_object **elements,
                               u8 type1,
                               u32 count1,
@@ -66,7 +66,7 @@ acpi_ns_check_package_elements(struct acpi_predefined_data *data,
  *
  * FUNCTION:    acpi_ns_check_package
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              return_object_ptr   - Pointer to the object returned from the
  *                                    evaluation of a method or object
  *
@@ -78,7 +78,7 @@ acpi_ns_check_package_elements(struct acpi_predefined_data *data,
  ******************************************************************************/
 
 acpi_status
-acpi_ns_check_package(struct acpi_predefined_data *data,
+acpi_ns_check_package(struct acpi_evaluate_info *info,
                      union acpi_operand_object **return_object_ptr)
 {
        union acpi_operand_object *return_object = *return_object_ptr;
@@ -93,18 +93,18 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
 
        /* The package info for this name is in the next table entry */
 
-       package = data->predefined + 1;
+       package = info->predefined + 1;
 
        ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
                          "%s Validating return Package of Type %X, Count %X\n",
-                         data->pathname, package->ret_info.type,
+                         info->full_pathname, package->ret_info.type,
                          return_object->package.count));
 
        /*
         * For variable-length Packages, we can safely remove all embedded
         * and trailing NULL package elements
         */
-       acpi_ns_remove_null_elements(data, package->ret_info.type,
+       acpi_ns_remove_null_elements(info, package->ret_info.type,
                                     return_object);
 
        /* Extract package count and elements array */
@@ -121,7 +121,8 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                        return (AE_OK);
                }
 
-               ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+               ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                     info->node_flags,
                                      "Return Package has no elements (empty)"));
 
                return (AE_AML_OPERAND_VALUE);
@@ -135,7 +136,6 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
         */
        switch (package->ret_info.type) {
        case ACPI_PTYPE1_FIXED:
-
                /*
                 * The package count is fixed and there are no sub-packages
                 *
@@ -150,13 +150,13 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                        ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                                          "%s: Return Package is larger than needed - "
                                          "found %u, expected %u\n",
-                                         data->pathname, count,
+                                         info->full_pathname, count,
                                          expected_count));
                }
 
                /* Validate all elements of the returned package */
 
-               status = acpi_ns_check_package_elements(data, elements,
+               status = acpi_ns_check_package_elements(info, elements,
                                                        package->ret_info.
                                                        object_type1,
                                                        package->ret_info.
@@ -168,13 +168,12 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                break;
 
        case ACPI_PTYPE1_VAR:
-
                /*
                 * The package count is variable, there are no sub-packages, and all
                 * elements must be of the same type
                 */
                for (i = 0; i < count; i++) {
-                       status = acpi_ns_check_object_type(data, elements,
+                       status = acpi_ns_check_object_type(info, elements,
                                                           package->ret_info.
                                                           object_type1, i);
                        if (ACPI_FAILURE(status)) {
@@ -185,7 +184,6 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                break;
 
        case ACPI_PTYPE1_OPTION:
-
                /*
                 * The package count is variable, there are no sub-packages. There are
                 * a fixed number of required elements, and a variable number of
@@ -206,7 +204,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                                /* These are the required package elements (0, 1, or 2) */
 
                                status =
-                                   acpi_ns_check_object_type(data, elements,
+                                   acpi_ns_check_object_type(info, elements,
                                                              package->
                                                              ret_info3.
                                                              object_type[i],
@@ -218,7 +216,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                                /* These are the optional package elements */
 
                                status =
-                                   acpi_ns_check_object_type(data, elements,
+                                   acpi_ns_check_object_type(info, elements,
                                                              package->
                                                              ret_info3.
                                                              tail_object_type,
@@ -235,7 +233,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
 
                /* First element is the (Integer) revision */
 
-               status = acpi_ns_check_object_type(data, elements,
+               status = acpi_ns_check_object_type(info, elements,
                                                   ACPI_RTYPE_INTEGER, 0);
                if (ACPI_FAILURE(status)) {
                        return (status);
@@ -247,14 +245,14 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                /* Examine the sub-packages */
 
                status =
-                   acpi_ns_check_package_list(data, package, elements, count);
+                   acpi_ns_check_package_list(info, package, elements, count);
                break;
 
        case ACPI_PTYPE2_PKG_COUNT:
 
                /* First element is the (Integer) count of sub-packages to follow */
 
-               status = acpi_ns_check_object_type(data, elements,
+               status = acpi_ns_check_object_type(info, elements,
                                                   ACPI_RTYPE_INTEGER, 0);
                if (ACPI_FAILURE(status)) {
                        return (status);
@@ -275,7 +273,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                /* Examine the sub-packages */
 
                status =
-                   acpi_ns_check_package_list(data, package, elements, count);
+                   acpi_ns_check_package_list(info, package, elements, count);
                break;
 
        case ACPI_PTYPE2:
@@ -283,7 +281,6 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
        case ACPI_PTYPE2_MIN:
        case ACPI_PTYPE2_COUNT:
        case ACPI_PTYPE2_FIX_VAR:
-
                /*
                 * These types all return a single Package that consists of a
                 * variable number of sub-Packages.
@@ -300,7 +297,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                        /* Create the new outer package and populate it */
 
                        status =
-                           acpi_ns_wrap_with_package(data, return_object,
+                           acpi_ns_wrap_with_package(info, return_object,
                                                      return_object_ptr);
                        if (ACPI_FAILURE(status)) {
                                return (status);
@@ -316,14 +313,15 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                /* Examine the sub-packages */
 
                status =
-                   acpi_ns_check_package_list(data, package, elements, count);
+                   acpi_ns_check_package_list(info, package, elements, count);
                break;
 
        default:
 
                /* Should not get here if predefined info table is correct */
 
-               ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+               ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                     info->node_flags,
                                      "Invalid internal return type in table entry: %X",
                                      package->ret_info.type));
 
@@ -336,7 +334,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
 
        /* Error exit for the case with an incorrect package count */
 
-       ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
                              "Return Package is too small - found %u elements, expected %u",
                              count, expected_count));
 
@@ -347,7 +345,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
  *
  * FUNCTION:    acpi_ns_check_package_list
  *
- * PARAMETERS:  data            - Pointer to validation data structure
+ * PARAMETERS:  info            - Method execution information block
  *              package         - Pointer to package-specific info for method
  *              elements        - Element list of parent package. All elements
  *                                of this list should be of type Package.
@@ -360,7 +358,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
  ******************************************************************************/
 
 static acpi_status
-acpi_ns_check_package_list(struct acpi_predefined_data *data,
+acpi_ns_check_package_list(struct acpi_evaluate_info *info,
                           const union acpi_predefined_info *package,
                           union acpi_operand_object **elements, u32 count)
 {
@@ -381,11 +379,11 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
        for (i = 0; i < count; i++) {
                sub_package = *elements;
                sub_elements = sub_package->package.elements;
-               data->parent_package = sub_package;
+               info->parent_package = sub_package;
 
                /* Each sub-object must be of type Package */
 
-               status = acpi_ns_check_object_type(data, &sub_package,
+               status = acpi_ns_check_object_type(info, &sub_package,
                                                   ACPI_RTYPE_PACKAGE, i);
                if (ACPI_FAILURE(status)) {
                        return (status);
@@ -393,7 +391,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
 
                /* Examine the different types of expected sub-packages */
 
-               data->parent_package = sub_package;
+               info->parent_package = sub_package;
                switch (package->ret_info.type) {
                case ACPI_PTYPE2:
                case ACPI_PTYPE2_PKG_COUNT:
@@ -408,7 +406,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
                        }
 
                        status =
-                           acpi_ns_check_package_elements(data, sub_elements,
+                           acpi_ns_check_package_elements(info, sub_elements,
                                                           package->ret_info.
                                                           object_type1,
                                                           package->ret_info.
@@ -434,7 +432,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
                        }
 
                        status =
-                           acpi_ns_check_package_elements(data, sub_elements,
+                           acpi_ns_check_package_elements(info, sub_elements,
                                                           package->ret_info.
                                                           object_type1,
                                                           package->ret_info.
@@ -463,7 +461,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
 
                        for (j = 0; j < expected_count; j++) {
                                status =
-                                   acpi_ns_check_object_type(data,
+                                   acpi_ns_check_object_type(info,
                                                              &sub_elements[j],
                                                              package->
                                                              ret_info2.
@@ -487,7 +485,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
                        /* Check the type of each sub-package element */
 
                        status =
-                           acpi_ns_check_package_elements(data, sub_elements,
+                           acpi_ns_check_package_elements(info, sub_elements,
                                                           package->ret_info.
                                                           object_type1,
                                                           sub_package->package.
@@ -498,12 +496,11 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
                        break;
 
                case ACPI_PTYPE2_COUNT:
-
                        /*
                         * First element is the (Integer) count of elements, including
                         * the count field (the ACPI name is num_elements)
                         */
-                       status = acpi_ns_check_object_type(data, sub_elements,
+                       status = acpi_ns_check_object_type(info, sub_elements,
                                                           ACPI_RTYPE_INTEGER,
                                                           0);
                        if (ACPI_FAILURE(status)) {
@@ -537,7 +534,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
                        /* Check the type of each sub-package element */
 
                        status =
-                           acpi_ns_check_package_elements(data,
+                           acpi_ns_check_package_elements(info,
                                                           (sub_elements + 1),
                                                           package->ret_info.
                                                           object_type1,
@@ -562,7 +559,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
 
        /* The sub-package count was smaller than required */
 
-       ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
                              "Return Sub-Package[%u] is too small - found %u elements, expected %u",
                              i, sub_package->package.count, expected_count));
 
@@ -573,7 +570,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
  *
  * FUNCTION:    acpi_ns_check_package_elements
  *
- * PARAMETERS:  data            - Pointer to validation data structure
+ * PARAMETERS:  info            - Method execution information block
  *              elements        - Pointer to the package elements array
  *              type1           - Object type for first group
  *              count1          - Count for first group
@@ -589,7 +586,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
  ******************************************************************************/
 
 static acpi_status
-acpi_ns_check_package_elements(struct acpi_predefined_data *data,
+acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
                               union acpi_operand_object **elements,
                               u8 type1,
                               u32 count1,
@@ -605,7 +602,7 @@ acpi_ns_check_package_elements(struct acpi_predefined_data *data,
         * The second group can have a count of zero.
         */
        for (i = 0; i < count1; i++) {
-               status = acpi_ns_check_object_type(data, this_element,
+               status = acpi_ns_check_object_type(info, this_element,
                                                   type1, i + start_index);
                if (ACPI_FAILURE(status)) {
                        return (status);
@@ -614,7 +611,7 @@ acpi_ns_check_package_elements(struct acpi_predefined_data *data,
        }
 
        for (i = 0; i < count2; i++) {
-               status = acpi_ns_check_object_type(data, this_element,
+               status = acpi_ns_check_object_type(info, this_element,
                                                   type2,
                                                   (i + count1 + start_index));
                if (ACPI_FAILURE(status)) {
index 18f02e4ece01dbc626be1d6829ef27c3f9950590..f8e71ea60319b21b6c014c88c69efc0b5a2dc751 100644 (file)
@@ -130,7 +130,7 @@ static const struct acpi_simple_repair_info acpi_object_repair_info[] = {
  *
  * FUNCTION:    acpi_ns_simple_repair
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              expected_btypes     - Object types expected
  *              package_index       - Index of object within parent package (if
  *                                    applicable - ACPI_NOT_PACKAGE_ELEMENT
@@ -146,7 +146,7 @@ static const struct acpi_simple_repair_info acpi_object_repair_info[] = {
  ******************************************************************************/
 
 acpi_status
-acpi_ns_simple_repair(struct acpi_predefined_data *data,
+acpi_ns_simple_repair(struct acpi_evaluate_info *info,
                      u32 expected_btypes,
                      u32 package_index,
                      union acpi_operand_object **return_object_ptr)
@@ -162,12 +162,12 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
         * Special repairs for certain names that are in the repair table.
         * Check if this name is in the list of repairable names.
         */
-       predefined = acpi_ns_match_simple_repair(data->node,
-                                                data->return_btype,
+       predefined = acpi_ns_match_simple_repair(info->node,
+                                                info->return_btype,
                                                 package_index);
        if (predefined) {
                if (!return_object) {
-                       ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
                                              ACPI_WARN_ALWAYS,
                                              "Missing expected return value"));
                }
@@ -191,7 +191,7 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
         * Do not perform simple object repair unless the return type is not
         * expected.
         */
-       if (data->return_btype & expected_btypes) {
+       if (info->return_btype & expected_btypes) {
                return (AE_OK);
        }
 
@@ -211,7 +211,7 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
         */
        if (!return_object) {
                if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) {
-                       ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
                                              ACPI_WARN_ALWAYS,
                                              "Missing expected return value"));
 
@@ -247,14 +247,14 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
                 * for correct contents (expected object type or types).
                 */
                status =
-                   acpi_ns_wrap_with_package(data, return_object, &new_object);
+                   acpi_ns_wrap_with_package(info, return_object, &new_object);
                if (ACPI_SUCCESS(status)) {
                        /*
                         * The original object just had its reference count
                         * incremented for being inserted into the new package.
                         */
                        *return_object_ptr = new_object;        /* New Package object */
-                       data->flags |= ACPI_OBJECT_REPAIRED;
+                       info->return_flags |= ACPI_OBJECT_REPAIRED;
                        return (AE_OK);
                }
        }
@@ -277,7 +277,7 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
                 * package object as part of the repair, we don't need to
                 * change the reference count.
                 */
-               if (!(data->flags & ACPI_OBJECT_WRAPPED)) {
+               if (!(info->return_flags & ACPI_OBJECT_WRAPPED)) {
                        new_object->common.reference_count =
                            return_object->common.reference_count;
 
@@ -288,14 +288,14 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
 
                ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                                  "%s: Converted %s to expected %s at Package index %u\n",
-                                 data->pathname,
+                                 info->full_pathname,
                                  acpi_ut_get_object_type_name(return_object),
                                  acpi_ut_get_object_type_name(new_object),
                                  package_index));
        } else {
                ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                                  "%s: Converted %s to expected %s\n",
-                                 data->pathname,
+                                 info->full_pathname,
                                  acpi_ut_get_object_type_name(return_object),
                                  acpi_ut_get_object_type_name(new_object)));
        }
@@ -304,7 +304,7 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
 
        acpi_ut_remove_reference(return_object);
        *return_object_ptr = new_object;
-       data->flags |= ACPI_OBJECT_REPAIRED;
+       info->return_flags |= ACPI_OBJECT_REPAIRED;
        return (AE_OK);
 }
 
@@ -359,7 +359,7 @@ static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
  *
  * FUNCTION:    acpi_ns_repair_null_element
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              expected_btypes     - Object types expected
  *              package_index       - Index of object within parent package (if
  *                                    applicable - ACPI_NOT_PACKAGE_ELEMENT
@@ -374,7 +374,7 @@ static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
  ******************************************************************************/
 
 acpi_status
-acpi_ns_repair_null_element(struct acpi_predefined_data *data,
+acpi_ns_repair_null_element(struct acpi_evaluate_info * info,
                            u32 expected_btypes,
                            u32 package_index,
                            union acpi_operand_object **return_object_ptr)
@@ -424,16 +424,16 @@ acpi_ns_repair_null_element(struct acpi_predefined_data *data,
        /* Set the reference count according to the parent Package object */
 
        new_object->common.reference_count =
-           data->parent_package->common.reference_count;
+           info->parent_package->common.reference_count;
 
        ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                          "%s: Converted NULL package element to expected %s at index %u\n",
-                         data->pathname,
+                         info->full_pathname,
                          acpi_ut_get_object_type_name(new_object),
                          package_index));
 
        *return_object_ptr = new_object;
-       data->flags |= ACPI_OBJECT_REPAIRED;
+       info->return_flags |= ACPI_OBJECT_REPAIRED;
        return (AE_OK);
 }
 
@@ -441,7 +441,7 @@ acpi_ns_repair_null_element(struct acpi_predefined_data *data,
  *
  * FUNCTION:    acpi_ns_remove_null_elements
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              package_type        - An acpi_return_package_types value
  *              obj_desc            - A Package object
  *
@@ -454,7 +454,7 @@ acpi_ns_repair_null_element(struct acpi_predefined_data *data,
  *****************************************************************************/
 
 void
-acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
+acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
                             u8 package_type,
                             union acpi_operand_object *obj_desc)
 {
@@ -480,6 +480,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
        case ACPI_PTYPE2_MIN:
        case ACPI_PTYPE2_REV_FIXED:
        case ACPI_PTYPE2_FIX_VAR:
+
                break;
 
        default:
@@ -511,7 +512,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
        if (new_count < count) {
                ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                                  "%s: Found and removed %u NULL elements\n",
-                                 data->pathname, (count - new_count)));
+                                 info->full_pathname, (count - new_count)));
 
                /* NULL terminate list and update the package count */
 
@@ -524,7 +525,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
  *
  * FUNCTION:    acpi_ns_wrap_with_package
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              original_object     - Pointer to the object to repair.
  *              obj_desc_ptr        - The new package object is returned here
  *
@@ -545,7 +546,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
  ******************************************************************************/
 
 acpi_status
-acpi_ns_wrap_with_package(struct acpi_predefined_data *data,
+acpi_ns_wrap_with_package(struct acpi_evaluate_info *info,
                          union acpi_operand_object *original_object,
                          union acpi_operand_object **obj_desc_ptr)
 {
@@ -566,12 +567,12 @@ acpi_ns_wrap_with_package(struct acpi_predefined_data *data,
 
        ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                          "%s: Wrapped %s with expected Package object\n",
-                         data->pathname,
+                         info->full_pathname,
                          acpi_ut_get_object_type_name(original_object)));
 
        /* Return the new object in the object pointer */
 
        *obj_desc_ptr = pkg_obj_desc;
-       data->flags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED;
+       info->return_flags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED;
        return (AE_OK);
 }
index 149e9b9c2c1b1e3fbb8349de7338697b540d976d..c84603ee83ae084312f3936324a1bfb524b64f08 100644 (file)
@@ -54,7 +54,7 @@ ACPI_MODULE_NAME("nsrepair2")
  * be repaired on a per-name basis.
  */
 typedef
-acpi_status(*acpi_repair_function) (struct acpi_predefined_data *data,
+acpi_status(*acpi_repair_function) (struct acpi_evaluate_info * info,
                                    union acpi_operand_object
                                    **return_object_ptr);
 
@@ -71,45 +71,57 @@ static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
                                                                   *node);
 
 static acpi_status
-acpi_ns_repair_ALR(struct acpi_predefined_data *data,
+acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);
 
 static acpi_status
-acpi_ns_repair_CID(struct acpi_predefined_data *data,
+acpi_ns_repair_CID(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);
 
 static acpi_status
-acpi_ns_repair_FDE(struct acpi_predefined_data *data,
+acpi_ns_repair_CST(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);
 
 static acpi_status
-acpi_ns_repair_HID(struct acpi_predefined_data *data,
+acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);
 
 static acpi_status
-acpi_ns_repair_PSS(struct acpi_predefined_data *data,
+acpi_ns_repair_HID(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);
 
 static acpi_status
-acpi_ns_repair_TSS(struct acpi_predefined_data *data,
+acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr);
 
 static acpi_status
-acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
+acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
+                  union acpi_operand_object **return_object_ptr);
+
+static acpi_status
+acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
+                  union acpi_operand_object **return_object_ptr);
+
+static acpi_status
+acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
                          union acpi_operand_object *return_object,
+                         u32 start_index,
                          u32 expected_count,
                          u32 sort_index,
                          u8 sort_direction, char *sort_key_name);
 
-static void
-acpi_ns_sort_list(union acpi_operand_object **elements,
-                 u32 count, u32 index, u8 sort_direction);
-
 /* Values for sort_direction above */
 
 #define ACPI_SORT_ASCENDING     0
 #define ACPI_SORT_DESCENDING    1
 
+static void
+acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);
+
+static void
+acpi_ns_sort_list(union acpi_operand_object **elements,
+                 u32 count, u32 index, u8 sort_direction);
+
 /*
  * This table contains the names of the predefined methods for which we can
  * perform more complex repairs.
@@ -118,9 +130,11 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
  *
  * _ALR: Sort the list ascending by ambient_illuminance
  * _CID: Strings: uppercase all, remove any leading asterisk
+ * _CST: Sort the list ascending by C state type
  * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
  * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
  * _HID: Strings: uppercase all, remove any leading asterisk
+ * _PRT: Fix reversed source_name and source_index
  * _PSS: Sort the list descending by Power
  * _TSS: Sort the list descending by Power
  *
@@ -134,9 +148,11 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
 static const struct acpi_repair_info acpi_ns_repairable_names[] = {
        {"_ALR", acpi_ns_repair_ALR},
        {"_CID", acpi_ns_repair_CID},
+       {"_CST", acpi_ns_repair_CST},
        {"_FDE", acpi_ns_repair_FDE},
        {"_GTM", acpi_ns_repair_FDE},   /* _GTM has same repair as _FDE */
        {"_HID", acpi_ns_repair_HID},
+       {"_PRT", acpi_ns_repair_PRT},
        {"_PSS", acpi_ns_repair_PSS},
        {"_TSS", acpi_ns_repair_TSS},
        {{0, 0, 0, 0}, NULL}    /* Table terminator */
@@ -150,7 +166,7 @@ static const struct acpi_repair_info acpi_ns_repairable_names[] = {
  *
  * FUNCTION:    acpi_ns_complex_repairs
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              node                - Namespace node for the method/object
  *              validate_status     - Original status of earlier validation
  *              return_object_ptr   - Pointer to the object returned from the
@@ -165,7 +181,7 @@ static const struct acpi_repair_info acpi_ns_repairable_names[] = {
  *****************************************************************************/
 
 acpi_status
-acpi_ns_complex_repairs(struct acpi_predefined_data *data,
+acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
                        struct acpi_namespace_node *node,
                        acpi_status validate_status,
                        union acpi_operand_object **return_object_ptr)
@@ -180,7 +196,7 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
                return (validate_status);
        }
 
-       status = predefined->repair_function(data, return_object_ptr);
+       status = predefined->repair_function(info, return_object_ptr);
        return (status);
 }
 
@@ -219,7 +235,7 @@ static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
  *
  * FUNCTION:    acpi_ns_repair_ALR
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              return_object_ptr   - Pointer to the object returned from the
  *                                    evaluation of a method or object
  *
@@ -231,13 +247,13 @@ static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
  *****************************************************************************/
 
 static acpi_status
-acpi_ns_repair_ALR(struct acpi_predefined_data *data,
+acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
 {
        union acpi_operand_object *return_object = *return_object_ptr;
        acpi_status status;
 
-       status = acpi_ns_check_sorted_list(data, return_object, 2, 1,
+       status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
                                           ACPI_SORT_ASCENDING,
                                           "AmbientIlluminance");
 
@@ -248,7 +264,7 @@ acpi_ns_repair_ALR(struct acpi_predefined_data *data,
  *
  * FUNCTION:    acpi_ns_repair_FDE
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              return_object_ptr   - Pointer to the object returned from the
  *                                    evaluation of a method or object
  *
@@ -262,7 +278,7 @@ acpi_ns_repair_ALR(struct acpi_predefined_data *data,
  *****************************************************************************/
 
 static acpi_status
-acpi_ns_repair_FDE(struct acpi_predefined_data *data,
+acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
 {
        union acpi_operand_object *return_object = *return_object_ptr;
@@ -285,8 +301,8 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
                /* We can only repair if we have exactly 5 BYTEs */
 
                if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
-                       ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
-                                             data->node_flags,
+                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                             info->node_flags,
                                              "Incorrect return buffer length %u, expected %u",
                                              return_object->buffer.length,
                                              ACPI_FDE_DWORD_BUFFER_SIZE));
@@ -316,10 +332,11 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
 
                ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                                  "%s Expanded Byte Buffer to expected DWord Buffer\n",
-                                 data->pathname));
+                                 info->full_pathname));
                break;
 
        default:
+
                return (AE_AML_OPERAND_TYPE);
        }
 
@@ -328,7 +345,7 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
        acpi_ut_remove_reference(return_object);
        *return_object_ptr = buffer_object;
 
-       data->flags |= ACPI_OBJECT_REPAIRED;
+       info->return_flags |= ACPI_OBJECT_REPAIRED;
        return (AE_OK);
 }
 
@@ -336,7 +353,7 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
  *
  * FUNCTION:    acpi_ns_repair_CID
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              return_object_ptr   - Pointer to the object returned from the
  *                                    evaluation of a method or object
  *
@@ -349,7 +366,7 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
  *****************************************************************************/
 
 static acpi_status
-acpi_ns_repair_CID(struct acpi_predefined_data *data,
+acpi_ns_repair_CID(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
 {
        acpi_status status;
@@ -362,7 +379,7 @@ acpi_ns_repair_CID(struct acpi_predefined_data *data,
        /* Check for _CID as a simple string */
 
        if (return_object->common.type == ACPI_TYPE_STRING) {
-               status = acpi_ns_repair_HID(data, return_object_ptr);
+               status = acpi_ns_repair_HID(info, return_object_ptr);
                return (status);
        }
 
@@ -379,7 +396,7 @@ acpi_ns_repair_CID(struct acpi_predefined_data *data,
                original_element = *element_ptr;
                original_ref_count = original_element->common.reference_count;
 
-               status = acpi_ns_repair_HID(data, element_ptr);
+               status = acpi_ns_repair_HID(info, element_ptr);
                if (ACPI_FAILURE(status)) {
                        return (status);
                }
@@ -402,11 +419,97 @@ acpi_ns_repair_CID(struct acpi_predefined_data *data,
        return (AE_OK);
 }
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_repair_CST
+ *
+ * PARAMETERS:  info                - Method execution information block
+ *              return_object_ptr   - Pointer to the object returned from the
+ *                                    evaluation of a method or object
+ *
+ * RETURN:      Status. AE_OK if object is OK or was repaired successfully
+ *
+ * DESCRIPTION: Repair for the _CST object:
+ *              1. Sort the list ascending by C state type
+ *              2. Ensure type cannot be zero
+ *              3. A sub-package count of zero means _CST is meaningless
+ *              4. Count must match the number of C state sub-packages
+ *
+ *****************************************************************************/
+
+static acpi_status
+acpi_ns_repair_CST(struct acpi_evaluate_info *info,
+                  union acpi_operand_object **return_object_ptr)
+{
+       union acpi_operand_object *return_object = *return_object_ptr;
+       union acpi_operand_object **outer_elements;
+       u32 outer_element_count;
+       union acpi_operand_object *obj_desc;
+       acpi_status status;
+       u8 removing;
+       u32 i;
+
+       ACPI_FUNCTION_NAME(ns_repair_CST);
+
+       /*
+        * Check if the C-state type values are proportional.
+        */
+       outer_element_count = return_object->package.count - 1;
+       i = 0;
+       while (i < outer_element_count) {
+               outer_elements = &return_object->package.elements[i + 1];
+               removing = FALSE;
+
+               if ((*outer_elements)->package.count == 0) {
+                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                             info->node_flags,
+                                             "SubPackage[%u] - removing entry due to zero count",
+                                             i));
+                       removing = TRUE;
+                       goto remove_element;
+               }
+
+               obj_desc = (*outer_elements)->package.elements[1];      /* Index1 = Type */
+               if ((u32)obj_desc->integer.value == 0) {
+                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                             info->node_flags,
+                                             "SubPackage[%u] - removing entry due to invalid Type(0)",
+                                             i));
+                       removing = TRUE;
+               }
+
+             remove_element:
+               if (removing) {
+                       acpi_ns_remove_element(return_object, i + 1);
+                       outer_element_count--;
+               } else {
+                       i++;
+               }
+       }
+
+       /* Update top-level package count, Type "Integer" checked elsewhere */
+
+       obj_desc = return_object->package.elements[0];
+       obj_desc->integer.value = outer_element_count;
+
+       /*
+        * Entries (subpackages) in the _CST Package must be sorted by the
+        * C-state type, in ascending order.
+        */
+       status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
+                                          ACPI_SORT_ASCENDING, "C-State Type");
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       return (AE_OK);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_ns_repair_HID
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              return_object_ptr   - Pointer to the object returned from the
  *                                    evaluation of a method or object
  *
@@ -418,7 +521,7 @@ acpi_ns_repair_CID(struct acpi_predefined_data *data,
  *****************************************************************************/
 
 static acpi_status
-acpi_ns_repair_HID(struct acpi_predefined_data *data,
+acpi_ns_repair_HID(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
 {
        union acpi_operand_object *return_object = *return_object_ptr;
@@ -435,12 +538,13 @@ acpi_ns_repair_HID(struct acpi_predefined_data *data,
        }
 
        if (return_object->string.length == 0) {
-               ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+               ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                     info->node_flags,
                                      "Invalid zero-length _HID or _CID string"));
 
                /* Return AE_OK anyway, let driver handle it */
 
-               data->flags |= ACPI_OBJECT_REPAIRED;
+               info->return_flags |= ACPI_OBJECT_REPAIRED;
                return (AE_OK);
        }
 
@@ -464,7 +568,7 @@ acpi_ns_repair_HID(struct acpi_predefined_data *data,
 
                ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                                  "%s: Removed invalid leading asterisk\n",
-                                 data->pathname));
+                                 info->full_pathname));
        }
 
        /*
@@ -486,53 +590,69 @@ acpi_ns_repair_HID(struct acpi_predefined_data *data,
 
 /******************************************************************************
  *
- * FUNCTION:    acpi_ns_repair_TSS
+ * FUNCTION:    acpi_ns_repair_PRT
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              return_object_ptr   - Pointer to the object returned from the
  *                                    evaluation of a method or object
  *
  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
  *
- * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
- *              descending by the power dissipation values.
+ * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
+ *              source_name and source_index field, a common BIOS bug.
  *
  *****************************************************************************/
 
 static acpi_status
-acpi_ns_repair_TSS(struct acpi_predefined_data *data,
+acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
 {
-       union acpi_operand_object *return_object = *return_object_ptr;
-       acpi_status status;
-       struct acpi_namespace_node *node;
+       union acpi_operand_object *package_object = *return_object_ptr;
+       union acpi_operand_object **top_object_list;
+       union acpi_operand_object **sub_object_list;
+       union acpi_operand_object *obj_desc;
+       u32 element_count;
+       u32 index;
 
-       /*
-        * We can only sort the _TSS return package if there is no _PSS in the
-        * same scope. This is because if _PSS is present, the ACPI specification
-        * dictates that the _TSS Power Dissipation field is to be ignored, and
-        * therefore some BIOSs leave garbage values in the _TSS Power field(s).
-        * In this case, it is best to just return the _TSS package as-is.
-        * (May, 2011)
-        */
-       status =
-           acpi_ns_get_node(data->node, "^_PSS", ACPI_NS_NO_UPSEARCH, &node);
-       if (ACPI_SUCCESS(status)) {
-               return (AE_OK);
-       }
+       /* Each element in the _PRT package is a subpackage */
 
-       status = acpi_ns_check_sorted_list(data, return_object, 5, 1,
-                                          ACPI_SORT_DESCENDING,
-                                          "PowerDissipation");
+       top_object_list = package_object->package.elements;
+       element_count = package_object->package.count;
 
-       return (status);
+       for (index = 0; index < element_count; index++) {
+               sub_object_list = (*top_object_list)->package.elements;
+
+               /*
+                * If the BIOS has erroneously reversed the _PRT source_name (index 2)
+                * and the source_index (index 3), fix it. _PRT is important enough to
+                * workaround this BIOS error. This also provides compatibility with
+                * other ACPI implementations.
+                */
+               obj_desc = sub_object_list[3];
+               if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
+                       sub_object_list[3] = sub_object_list[2];
+                       sub_object_list[2] = obj_desc;
+                       info->return_flags |= ACPI_OBJECT_REPAIRED;
+
+                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                             info->node_flags,
+                                             "PRT[%X]: Fixed reversed SourceName and SourceIndex",
+                                             index));
+               }
+
+               /* Point to the next union acpi_operand_object in the top level package */
+
+               top_object_list++;
+       }
+
+       return (AE_OK);
 }
 
 /******************************************************************************
  *
  * FUNCTION:    acpi_ns_repair_PSS
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              return_object_ptr   - Pointer to the object returned from the
  *                                    evaluation of a method or object
  *
@@ -546,7 +666,7 @@ acpi_ns_repair_TSS(struct acpi_predefined_data *data,
  *****************************************************************************/
 
 static acpi_status
-acpi_ns_repair_PSS(struct acpi_predefined_data *data,
+acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
                   union acpi_operand_object **return_object_ptr)
 {
        union acpi_operand_object *return_object = *return_object_ptr;
@@ -564,7 +684,7 @@ acpi_ns_repair_PSS(struct acpi_predefined_data *data,
         * incorrectly sorted, sort it. We sort by cpu_frequency, since this
         * should be proportional to the power.
         */
-       status = acpi_ns_check_sorted_list(data, return_object, 6, 0,
+       status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
                                           ACPI_SORT_DESCENDING,
                                           "CpuFrequency");
        if (ACPI_FAILURE(status)) {
@@ -584,8 +704,8 @@ acpi_ns_repair_PSS(struct acpi_predefined_data *data,
                obj_desc = elements[1]; /* Index1 = power_dissipation */
 
                if ((u32) obj_desc->integer.value > previous_value) {
-                       ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
-                                             data->node_flags,
+                       ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+                                             info->node_flags,
                                              "SubPackage[%u,%u] - suspicious power dissipation values",
                                              i - 1, i));
                }
@@ -597,12 +717,57 @@ acpi_ns_repair_PSS(struct acpi_predefined_data *data,
        return (AE_OK);
 }
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_repair_TSS
+ *
+ * PARAMETERS:  info                - Method execution information block
+ *              return_object_ptr   - Pointer to the object returned from the
+ *                                    evaluation of a method or object
+ *
+ * RETURN:      Status. AE_OK if object is OK or was repaired successfully
+ *
+ * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
+ *              descending by the power dissipation values.
+ *
+ *****************************************************************************/
+
+static acpi_status
+acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
+                  union acpi_operand_object **return_object_ptr)
+{
+       union acpi_operand_object *return_object = *return_object_ptr;
+       acpi_status status;
+       struct acpi_namespace_node *node;
+
+       /*
+        * We can only sort the _TSS return package if there is no _PSS in the
+        * same scope. This is because if _PSS is present, the ACPI specification
+        * dictates that the _TSS Power Dissipation field is to be ignored, and
+        * therefore some BIOSs leave garbage values in the _TSS Power field(s).
+        * In this case, it is best to just return the _TSS package as-is.
+        * (May, 2011)
+        */
+       status = acpi_ns_get_node(info->node, "^_PSS",
+                                 ACPI_NS_NO_UPSEARCH, &node);
+       if (ACPI_SUCCESS(status)) {
+               return (AE_OK);
+       }
+
+       status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
+                                          ACPI_SORT_DESCENDING,
+                                          "PowerDissipation");
+
+       return (status);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_ns_check_sorted_list
  *
- * PARAMETERS:  data                - Pointer to validation data structure
+ * PARAMETERS:  info                - Method execution information block
  *              return_object       - Pointer to the top-level returned object
+ *              start_index         - Index of the first sub-package
  *              expected_count      - Minimum length of each sub-package
  *              sort_index          - Sub-package entry to sort on
  *              sort_direction      - Ascending or descending
@@ -617,8 +782,9 @@ acpi_ns_repair_PSS(struct acpi_predefined_data *data,
  *****************************************************************************/
 
 static acpi_status
-acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
+acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
                          union acpi_operand_object *return_object,
+                         u32 start_index,
                          u32 expected_count,
                          u32 sort_index,
                          u8 sort_direction, char *sort_key_name)
@@ -643,12 +809,14 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
         * Any NULL elements should have been removed by earlier call
         * to acpi_ns_remove_null_elements.
         */
-       outer_elements = return_object->package.elements;
        outer_element_count = return_object->package.count;
-       if (!outer_element_count) {
+       if (!outer_element_count || start_index >= outer_element_count) {
                return (AE_AML_PACKAGE_LIMIT);
        }
 
+       outer_elements = &return_object->package.elements[start_index];
+       outer_element_count -= start_index;
+
        previous_value = 0;
        if (sort_direction == ACPI_SORT_DESCENDING) {
                previous_value = ACPI_UINT32_MAX;
@@ -685,15 +853,16 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
                     (obj_desc->integer.value < previous_value)) ||
                    ((sort_direction == ACPI_SORT_DESCENDING) &&
                     (obj_desc->integer.value > previous_value))) {
-                       acpi_ns_sort_list(return_object->package.elements,
+                       acpi_ns_sort_list(&return_object->package.
+                                         elements[start_index],
                                          outer_element_count, sort_index,
                                          sort_direction);
 
-                       data->flags |= ACPI_OBJECT_REPAIRED;
+                       info->return_flags |= ACPI_OBJECT_REPAIRED;
 
                        ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
                                          "%s: Repaired unsorted list - now sorted by %s\n",
-                                         data->pathname, sort_key_name));
+                                         info->full_pathname, sort_key_name));
                        return (AE_OK);
                }
 
@@ -752,3 +921,52 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
                }
        }
 }
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_remove_element
+ *
+ * PARAMETERS:  obj_desc            - Package object element list
+ *              index               - Index of element to remove
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Remove the requested element of a package and delete it.
+ *
+ *****************************************************************************/
+
+static void
+acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
+{
+       union acpi_operand_object **source;
+       union acpi_operand_object **dest;
+       u32 count;
+       u32 new_count;
+       u32 i;
+
+       ACPI_FUNCTION_NAME(ns_remove_element);
+
+       count = obj_desc->package.count;
+       new_count = count - 1;
+
+       source = obj_desc->package.elements;
+       dest = source;
+
+       /* Examine all elements of the package object, remove matched index */
+
+       for (i = 0; i < count; i++) {
+               if (i == index) {
+                       acpi_ut_remove_reference(*source);      /* Remove one ref for being in pkg */
+                       acpi_ut_remove_reference(*source);
+               } else {
+                       *dest = *source;
+                       dest++;
+               }
+               source++;
+       }
+
+       /* NULL terminate list and update the package count */
+
+       *dest = NULL;
+       obj_desc->package.count = new_count;
+}
index 2808586fad30c61a7bb6c5e014cde4b5a5dcff15..08c0b5beec888c65ea0d175f2795bb1be0f95227 100644 (file)
@@ -419,10 +419,12 @@ acpi_ns_externalize_name(u32 internal_name_length,
 
        switch (internal_name[0]) {
        case AML_ROOT_PREFIX:
+
                prefix_length = 1;
                break;
 
        case AML_PARENT_PREFIX:
+
                for (i = 0; i < internal_name_length; i++) {
                        if (ACPI_IS_PARENT_PREFIX(internal_name[i])) {
                                prefix_length = i + 1;
@@ -438,6 +440,7 @@ acpi_ns_externalize_name(u32 internal_name_length,
                break;
 
        default:
+
                break;
        }
 
index fc69949151bb9cc073d61b9702eb6ef1c5fa91fd..f553cfdb71ddd6ec350b63077f6eda49f30daac9 100644 (file)
@@ -187,8 +187,6 @@ acpi_evaluate_object(acpi_handle handle,
                return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
-       info->pathname = pathname;
-
        /* Convert and validate the device handle */
 
        info->prefix_node = acpi_ns_validate_handle(handle);
@@ -198,17 +196,64 @@ acpi_evaluate_object(acpi_handle handle,
        }
 
        /*
-        * If there are parameters to be passed to a control method, the external
-        * objects must all be converted to internal objects
+        * Get the actual namespace node for the target object.
+        * Handles these cases:
+        *
+        * 1) Null node, valid pathname from root (absolute path)
+        * 2) Node and valid pathname (path relative to Node)
+        * 3) Node, Null pathname
+        */
+       if ((pathname) && (ACPI_IS_ROOT_PREFIX(pathname[0]))) {
+
+               /* The path is fully qualified, just evaluate by name */
+
+               info->prefix_node = NULL;
+       } else if (!handle) {
+               /*
+                * A handle is optional iff a fully qualified pathname is specified.
+                * Since we've already handled fully qualified names above, this is
+                * an error.
+                */
+               if (!pathname) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                         "Both Handle and Pathname are NULL"));
+               } else {
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                         "Null Handle with relative pathname [%s]",
+                                         pathname));
+               }
+
+               status = AE_BAD_PARAMETER;
+               goto cleanup;
+       }
+
+       info->relative_pathname = pathname;
+
+       /*
+        * Convert all external objects passed as arguments to the
+        * internal version(s).
         */
        if (external_params && external_params->count) {
+               info->param_count = (u16)external_params->count;
+
+               /* Warn on impossible argument count */
+
+               if (info->param_count > ACPI_METHOD_NUM_ARGS) {
+                       ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+                                             ACPI_WARN_ALWAYS,
+                                             "Excess arguments (%u) - using only %u",
+                                             info->param_count,
+                                             ACPI_METHOD_NUM_ARGS));
+
+                       info->param_count = ACPI_METHOD_NUM_ARGS;
+               }
+
                /*
                 * Allocate a new parameter block for the internal objects
                 * Add 1 to count to allow for null terminated internal list
                 */
-               info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size)
-                                                        external_params->
-                                                        count +
+               info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size) info->
+                                                        param_count +
                                                         1) * sizeof(void *));
                if (!info->parameters) {
                        status = AE_NO_MEMORY;
@@ -217,7 +262,7 @@ acpi_evaluate_object(acpi_handle handle,
 
                /* Convert each external object in the list to an internal object */
 
-               for (i = 0; i < external_params->count; i++) {
+               for (i = 0; i < info->param_count; i++) {
                        status =
                            acpi_ut_copy_eobject_to_iobject(&external_params->
                                                            pointer[i],
@@ -227,43 +272,96 @@ acpi_evaluate_object(acpi_handle handle,
                                goto cleanup;
                        }
                }
-               info->parameters[external_params->count] = NULL;
+
+               info->parameters[info->param_count] = NULL;
        }
 
+#if 0
+
        /*
-        * Three major cases:
-        * 1) Fully qualified pathname
-        * 2) No handle, not fully qualified pathname (error)
-        * 3) Valid handle
+        * Begin incoming argument count analysis. Check for too few args
+        * and too many args.
         */
-       if ((pathname) && (ACPI_IS_ROOT_PREFIX(pathname[0]))) {
 
-               /* The path is fully qualified, just evaluate by name */
+       switch (acpi_ns_get_type(info->node)) {
+       case ACPI_TYPE_METHOD:
+
+               /* Check incoming argument count against the method definition */
+
+               if (info->obj_desc->method.param_count > info->param_count) {
+                       ACPI_ERROR((AE_INFO,
+                                   "Insufficient arguments (%u) - %u are required",
+                                   info->param_count,
+                                   info->obj_desc->method.param_count));
+
+                       status = AE_MISSING_ARGUMENTS;
+                       goto cleanup;
+               }
+
+               else if (info->obj_desc->method.param_count < info->param_count) {
+                       ACPI_WARNING((AE_INFO,
+                                     "Excess arguments (%u) - only %u are required",
+                                     info->param_count,
+                                     info->obj_desc->method.param_count));
+
+                       /* Just pass the required number of arguments */
+
+                       info->param_count = info->obj_desc->method.param_count;
+               }
 
-               info->prefix_node = NULL;
-               status = acpi_ns_evaluate(info);
-       } else if (!handle) {
                /*
-                * A handle is optional iff a fully qualified pathname is specified.
-                * Since we've already handled fully qualified names above, this is
-                * an error
+                * Any incoming external objects to be passed as arguments to the
+                * method must be converted to internal objects
                 */
-               if (!pathname) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "Both Handle and Pathname are NULL"));
-               } else {
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "Null Handle with relative pathname [%s]",
-                                         pathname));
+               if (info->param_count) {
+                       /*
+                        * Allocate a new parameter block for the internal objects
+                        * Add 1 to count to allow for null terminated internal list
+                        */
+                       info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size)
+                                                                info->
+                                                                param_count +
+                                                                1) *
+                                                               sizeof(void *));
+                       if (!info->parameters) {
+                               status = AE_NO_MEMORY;
+                               goto cleanup;
+                       }
+
+                       /* Convert each external object in the list to an internal object */
+
+                       for (i = 0; i < info->param_count; i++) {
+                               status =
+                                   acpi_ut_copy_eobject_to_iobject
+                                   (&external_params->pointer[i],
+                                    &info->parameters[i]);
+                               if (ACPI_FAILURE(status)) {
+                                       goto cleanup;
+                               }
+                       }
+
+                       info->parameters[info->param_count] = NULL;
                }
+               break;
 
-               status = AE_BAD_PARAMETER;
-       } else {
-               /* We have a namespace a node and a possible relative path */
+       default:
+
+               /* Warn if arguments passed to an object that is not a method */
 
-               status = acpi_ns_evaluate(info);
+               if (info->param_count) {
+                       ACPI_WARNING((AE_INFO,
+                                     "%u arguments were passed to a non-method ACPI object",
+                                     info->param_count));
+               }
+               break;
        }
 
+#endif
+
+       /* Now we can evaluate the object */
+
+       status = acpi_ns_evaluate(info);
+
        /*
         * If we are expecting a return value, and all went well above,
         * copy the return value to an external object.
@@ -413,6 +511,7 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info)
                break;
 
        default:
+
                return;
        }
 
index 9f25a3d4e992c0dc890325f8ed0029942c3bac5b..91a5a69db80c316552e13f9704eb9435f9b94a30 100644 (file)
@@ -629,24 +629,28 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
 
                                switch (opcode) {
                                case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
+
                                        buffer_length =
                                            ACPI_GET8(parser_state->aml);
                                        parser_state->aml += 1;
                                        break;
 
                                case AML_WORD_OP:       /* AML_WORDDATA_ARG */
+
                                        buffer_length =
                                            ACPI_GET16(parser_state->aml);
                                        parser_state->aml += 2;
                                        break;
 
                                case AML_DWORD_OP:      /* AML_DWORDATA_ARG */
+
                                        buffer_length =
                                            ACPI_GET32(parser_state->aml);
                                        parser_state->aml += 4;
                                        break;
 
                                default:
+
                                        buffer_length = 0;
                                        break;
                                }
index 63c4554474817b591fdc0d71771dde8f2cf970ed..065b44ae538f28b7595fe9af1870b5c824052237 100644 (file)
@@ -164,7 +164,6 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
                        case AML_IF_OP:
                        case AML_ELSE_OP:
                        case AML_WHILE_OP:
-
                                /*
                                 * Currently supported module-level opcodes are:
                                 * IF/ELSE/WHILE. These appear to be the most common,
@@ -289,6 +288,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
                default:
 
                        /* No action for all other opcodes */
+
                        break;
                }
 
index 12c4028002b145e0fef8b9ed60ab9f00ccd100dc..95dc608a66a85b3b01e5a461b58a39f4a02b20f7 100644 (file)
@@ -402,6 +402,7 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
 
        switch (status) {
        case AE_OK:
+
                break;
 
        case AE_CTRL_TRANSFER:
index abc4c48b2eddd7c18acb854a5eeb960d73080393..86198a9139b52a653d24d6758ba63ed0d04df800 100644 (file)
@@ -176,10 +176,10 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
 
                switch (parent_info->class) {
                case AML_CLASS_CONTROL:
+
                        break;
 
                case AML_CLASS_CREATE:
-
                        /*
                         * These opcodes contain term_arg operands. The current
                         * op must be replaced by a placeholder return op
@@ -192,7 +192,6 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
                        break;
 
                case AML_CLASS_NAMED_OBJECT:
-
                        /*
                         * These opcodes contain term_arg operands. The current
                         * op must be replaced by a placeholder return op
index c1934bf04f0af56f16db267dcdc5d3a914b749ab..877dc0de8df3e19da7057a8fd99042eb2d6f80b6 100644 (file)
@@ -308,7 +308,9 @@ union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op)
                break;
 
        default:
+
                /* All others have no children */
+
                break;
        }
 
index f682542689656d5ce98ba93db973fad907d41899..11b99ab20bb3a3c1a96cd5322149a4fefe7fbb4a 100644 (file)
@@ -125,7 +125,7 @@ static void acpi_ps_start_trace(struct acpi_evaluate_info *info)
        }
 
        if ((!acpi_gbl_trace_method_name) ||
-           (acpi_gbl_trace_method_name != info->resolved_node->name.integer)) {
+           (acpi_gbl_trace_method_name != info->node->name.integer)) {
                goto exit;
        }
 
@@ -170,7 +170,7 @@ static void acpi_ps_stop_trace(struct acpi_evaluate_info *info)
        }
 
        if ((!acpi_gbl_trace_method_name) ||
-           (acpi_gbl_trace_method_name != info->resolved_node->name.integer)) {
+           (acpi_gbl_trace_method_name != info->node->name.integer)) {
                goto exit;
        }
 
@@ -226,15 +226,14 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
 
        /* Validate the Info and method Node */
 
-       if (!info || !info->resolved_node) {
+       if (!info || !info->node) {
                return_ACPI_STATUS(AE_NULL_ENTRY);
        }
 
        /* Init for new method, wait on concurrency semaphore */
 
        status =
-           acpi_ds_begin_method_execution(info->resolved_node, info->obj_desc,
-                                          NULL);
+           acpi_ds_begin_method_execution(info->node, info->obj_desc, NULL);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
@@ -253,8 +252,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
         */
        ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
                          "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n",
-                         info->resolved_node->name.ascii, info->resolved_node,
-                         info->obj_desc));
+                         info->node->name.ascii, info->node, info->obj_desc));
 
        /* Create and init a Root Node */
 
@@ -275,7 +273,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
                goto cleanup;
        }
 
-       status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
+       status = acpi_ds_init_aml_walk(walk_state, op, info->node,
                                       info->obj_desc->method.aml_start,
                                       info->obj_desc->method.aml_length, info,
                                       info->pass_number);
index 72077fa1eea5ecd7e5c489e3b65632c0be639ef2..b62a0f4f4f9bb527cd49fc95279b7032ba1a689a 100644 (file)
@@ -352,6 +352,7 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
                        break;
 
                default:
+
                        break;
                }
 
@@ -539,6 +540,7 @@ acpi_rs_get_list_length(u8 * aml_buffer,
                        break;
 
                default:
+
                        break;
                }
 
@@ -650,8 +652,9 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
 
                name_found = FALSE;
 
-               for (table_index = 0; table_index < 4 && !name_found;
-                    table_index++) {
+               for (table_index = 0;
+                    table_index < package_element->package.count
+                    && !name_found; table_index++) {
                        if (*sub_object_list && /* Null object allowed */
                            ((ACPI_TYPE_STRING ==
                              (*sub_object_list)->common.type) ||
index f8b55b426c9d9b83abfe7f1d1a42692406cf0cc7..65f3e1c5b5989f61bdcb03e6620cdd1a7371dba9 100644 (file)
@@ -273,17 +273,6 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
                 */
                user_prt->length = (sizeof(struct acpi_pci_routing_table) - 4);
 
-               /* Each element of the top-level package must also be a package */
-
-               if ((*top_object_list)->common.type != ACPI_TYPE_PACKAGE) {
-                       ACPI_ERROR((AE_INFO,
-                                   "(PRT[%u]) Need sub-package, found %s",
-                                   index,
-                                   acpi_ut_get_object_type_name
-                                   (*top_object_list)));
-                       return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
-               }
-
                /* Each sub-package must be of length 4 */
 
                if ((*top_object_list)->package.count != 4) {
@@ -326,22 +315,6 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
 
                user_prt->pin = (u32) obj_desc->integer.value;
 
-               /*
-                * If the BIOS has erroneously reversed the _PRT source_name (index 2)
-                * and the source_index (index 3), fix it. _PRT is important enough to
-                * workaround this BIOS error. This also provides compatibility with
-                * other ACPI implementations.
-                */
-               obj_desc = sub_object_list[3];
-               if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
-                       sub_object_list[3] = sub_object_list[2];
-                       sub_object_list[2] = obj_desc;
-
-                       ACPI_WARNING((AE_INFO,
-                                     "(PRT[%X].Source) SourceName and SourceIndex are reversed, fixed",
-                                     index));
-               }
-
                /*
                 * 3) Third subobject: Dereference the PRT.source_name
                 * The name may be unresolved (slack mode), so allow a null object
index b5fc0db2e87bb4a78ddbaa707ee91a886b4e7215..8a2d4986b0aa576695ed2f479703cfa8dc4fd139 100644 (file)
@@ -120,17 +120,20 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
                        /* Strings */
 
                case ACPI_RSD_LITERAL:
+
                        acpi_rs_out_string(name,
                                           ACPI_CAST_PTR(char, table->pointer));
                        break;
 
                case ACPI_RSD_STRING:
+
                        acpi_rs_out_string(name, ACPI_CAST_PTR(char, target));
                        break;
 
                        /* Data items, 8/16/32/64 bit */
 
                case ACPI_RSD_UINT8:
+
                        if (table->pointer) {
                                acpi_rs_out_string(name, ACPI_CAST_PTR(char,
                                                                       table->
@@ -142,20 +145,24 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
                        break;
 
                case ACPI_RSD_UINT16:
+
                        acpi_rs_out_integer16(name, ACPI_GET16(target));
                        break;
 
                case ACPI_RSD_UINT32:
+
                        acpi_rs_out_integer32(name, ACPI_GET32(target));
                        break;
 
                case ACPI_RSD_UINT64:
+
                        acpi_rs_out_integer64(name, ACPI_GET64(target));
                        break;
 
                        /* Flags: 1-bit and 2-bit flags supported */
 
                case ACPI_RSD_1BITFLAG:
+
                        acpi_rs_out_string(name, ACPI_CAST_PTR(char,
                                                               table->
                                                               pointer[*target &
@@ -163,6 +170,7 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
                        break;
 
                case ACPI_RSD_2BITFLAG:
+
                        acpi_rs_out_string(name, ACPI_CAST_PTR(char,
                                                               table->
                                                               pointer[*target &
@@ -170,6 +178,7 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
                        break;
 
                case ACPI_RSD_3BITFLAG:
+
                        acpi_rs_out_string(name, ACPI_CAST_PTR(char,
                                                               table->
                                                               pointer[*target &
@@ -258,6 +267,7 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
                        break;
 
                default:
+
                        acpi_os_printf("**** Invalid table opcode [%X] ****\n",
                                       table->opcode);
                        return;
index d5bf05a96096ad785897966876929b02dba60c02..80d12994e0d078f10b8842d6c5ee3d8a4c965c35 100644 (file)
@@ -194,7 +194,6 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
                        break;
 
                case ACPI_RSC_COUNT_GPIO_RES:
-
                        /*
                         * Vendor data is optional (length/offset may both be zero)
                         * Examine vendor data length field first
@@ -410,12 +409,14 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
                         */
                        switch (info->resource_offset) {
                        case ACPI_RSC_COMPARE_AML_LENGTH:
+
                                if (aml_resource_length != info->value) {
                                        goto exit;
                                }
                                break;
 
                        case ACPI_RSC_COMPARE_VALUE:
+
                                if (ACPI_GET8(source) != info->value) {
                                        goto exit;
                                }
index a44953c6f75da74d7c0e160078eff90b5abfc5ba..480b6b40c5eaa3527ce58b4f76f2b8a23b16db97 100644 (file)
@@ -147,6 +147,7 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type)
                case ACPI_RSC_MOVE_GPIO_RES:
                case ACPI_RSC_MOVE_SERIAL_VEN:
                case ACPI_RSC_MOVE_SERIAL_RES:
+
                        ACPI_MEMCPY(destination, source, item_count);
                        return;
 
@@ -157,21 +158,25 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type)
                         */
                case ACPI_RSC_MOVE16:
                case ACPI_RSC_MOVE_GPIO_PIN:
+
                        ACPI_MOVE_16_TO_16(&ACPI_CAST_PTR(u16, destination)[i],
                                           &ACPI_CAST_PTR(u16, source)[i]);
                        break;
 
                case ACPI_RSC_MOVE32:
+
                        ACPI_MOVE_32_TO_32(&ACPI_CAST_PTR(u32, destination)[i],
                                           &ACPI_CAST_PTR(u32, source)[i]);
                        break;
 
                case ACPI_RSC_MOVE64:
+
                        ACPI_MOVE_64_TO_64(&ACPI_CAST_PTR(u64, destination)[i],
                                           &ACPI_CAST_PTR(u64, source)[i]);
                        break;
 
                default:
+
                        return;
                }
        }
@@ -736,7 +741,7 @@ acpi_rs_set_srs_method_data(struct acpi_namespace_node *node,
        }
 
        info->prefix_node = node;
-       info->pathname = METHOD_NAME__SRS;
+       info->relative_pathname = METHOD_NAME__SRS;
        info->parameters = args;
        info->flags = ACPI_IGNORE_RETURN_VALUE;
 
index c0e5d2d3ce6757380928c9e50d1f2de0f158160a..94e3517554f9d52d121dd4f31469ddb4a9ec6567 100644 (file)
@@ -402,6 +402,7 @@ acpi_resource_to_address64(struct acpi_resource *resource,
                break;
 
        default:
+
                return (AE_BAD_PARAMETER);
        }
 
index e57cd38004e33c3adb3b7850bc25b4f23f577430..42a13c0d7015360ab44c684ab9645500fc63f1d8 100644 (file)
@@ -141,8 +141,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
                ACPI_BIOS_ERROR((AE_INFO,
                                 "Table has invalid signature [%4.4s] (0x%8.8X), "
                                 "must be SSDT or OEMx",
-                                acpi_ut_valid_acpi_name(*(u32 *)table_desc->
-                                                        pointer->
+                                acpi_ut_valid_acpi_name(table_desc->pointer->
                                                         signature) ?
                                 table_desc->pointer->signature : "????",
                                 *(u32 *)table_desc->pointer->signature));
@@ -471,15 +470,19 @@ void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
        }
        switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
        case ACPI_TABLE_ORIGIN_MAPPED:
+
                acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
                break;
+
        case ACPI_TABLE_ORIGIN_ALLOCATED:
+
                ACPI_FREE(table_desc->pointer);
                break;
 
                /* Not mapped or allocated, there is nothing we can do */
 
        default:
+
                return;
        }
 
diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c
new file mode 100644 (file)
index 0000000..dc963f8
--- /dev/null
@@ -0,0 +1,237 @@
+/******************************************************************************
+ *
+ * Module Name: tbprint - Table output utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "actables.h"
+
+#define _COMPONENT          ACPI_TABLES
+ACPI_MODULE_NAME("tbprint")
+
+/* Local prototypes */
+static void acpi_tb_fix_string(char *string, acpi_size length);
+
+static void
+acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
+                            struct acpi_table_header *header);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_fix_string
+ *
+ * PARAMETERS:  string              - String to be repaired
+ *              length              - Maximum length
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Replace every non-printable or non-ascii byte in the string
+ *              with a question mark '?'.
+ *
+ ******************************************************************************/
+
+static void acpi_tb_fix_string(char *string, acpi_size length)
+{
+
+       while (length && *string) {
+               if (!ACPI_IS_PRINT(*string)) {
+                       *string = '?';
+               }
+               string++;
+               length--;
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_cleanup_table_header
+ *
+ * PARAMETERS:  out_header          - Where the cleaned header is returned
+ *              header              - Input ACPI table header
+ *
+ * RETURN:      Returns the cleaned header in out_header
+ *
+ * DESCRIPTION: Copy the table header and ensure that all "string" fields in
+ *              the header consist of printable characters.
+ *
+ ******************************************************************************/
+
+static void
+acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
+                            struct acpi_table_header *header)
+{
+
+       ACPI_MEMCPY(out_header, header, sizeof(struct acpi_table_header));
+
+       acpi_tb_fix_string(out_header->signature, ACPI_NAME_SIZE);
+       acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE);
+       acpi_tb_fix_string(out_header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
+       acpi_tb_fix_string(out_header->asl_compiler_id, ACPI_NAME_SIZE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_print_table_header
+ *
+ * PARAMETERS:  address             - Table physical address
+ *              header              - Table header
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+                          struct acpi_table_header *header)
+{
+       struct acpi_table_header local_header;
+
+       /*
+        * The reason that the Address is cast to a void pointer is so that we
+        * can use %p which will work properly on both 32-bit and 64-bit hosts.
+        */
+       if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
+
+               /* FACS only has signature and length fields */
+
+               ACPI_INFO((AE_INFO, "%4.4s %p %05X",
+                          header->signature, ACPI_CAST_PTR(void, address),
+                          header->length));
+       } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
+
+               /* RSDP has no common fields */
+
+               ACPI_MEMCPY(local_header.oem_id,
+                           ACPI_CAST_PTR(struct acpi_table_rsdp,
+                                         header)->oem_id, ACPI_OEM_ID_SIZE);
+               acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE);
+
+               ACPI_INFO((AE_INFO, "RSDP %p %05X (v%.2d %6.6s)",
+                          ACPI_CAST_PTR(void, address),
+                          (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
+                           revision >
+                           0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
+                                              header)->length : 20,
+                          ACPI_CAST_PTR(struct acpi_table_rsdp,
+                                        header)->revision,
+                          local_header.oem_id));
+       } else {
+               /* Standard ACPI table with full common header */
+
+               acpi_tb_cleanup_table_header(&local_header, header);
+
+               ACPI_INFO((AE_INFO,
+                          "%4.4s %p %05X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
+                          local_header.signature, ACPI_CAST_PTR(void, address),
+                          local_header.length, local_header.revision,
+                          local_header.oem_id, local_header.oem_table_id,
+                          local_header.oem_revision,
+                          local_header.asl_compiler_id,
+                          local_header.asl_compiler_revision));
+       }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_validate_checksum
+ *
+ * PARAMETERS:  table               - ACPI table to verify
+ *              length              - Length of entire table
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
+ *              exception on bad checksum.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
+{
+       u8 checksum;
+
+       /* Compute the checksum on the table */
+
+       checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
+
+       /* Checksum ok? (should be zero) */
+
+       if (checksum) {
+               ACPI_BIOS_WARNING((AE_INFO,
+                                  "Incorrect checksum in table [%4.4s] - 0x%2.2X, "
+                                  "should be 0x%2.2X",
+                                  table->signature, table->checksum,
+                                  (u8)(table->checksum - checksum)));
+
+#if (ACPI_CHECKSUM_ABORT)
+               return (AE_BAD_CHECKSUM);
+#endif
+       }
+
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_checksum
+ *
+ * PARAMETERS:  buffer          - Pointer to memory region to be checked
+ *              length          - Length of this memory region
+ *
+ * RETURN:      Checksum (u8)
+ *
+ * DESCRIPTION: Calculates circular checksum of memory region.
+ *
+ ******************************************************************************/
+
+u8 acpi_tb_checksum(u8 *buffer, u32 length)
+{
+       u8 sum = 0;
+       u8 *end = buffer + length;
+
+       while (buffer < end) {
+               sum = (u8)(sum + *(buffer++));
+       }
+
+       return (sum);
+}
index ce3d5db39a9c742d49fc7aa9103121942da73c6a..bffdfc7b832254068378320a94385abdd359c715 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Module Name: tbutils   - table utilities
+ * Module Name: tbutils - ACPI Table utilities
  *
  *****************************************************************************/
 
 ACPI_MODULE_NAME("tbutils")
 
 /* Local prototypes */
-static void acpi_tb_fix_string(char *string, acpi_size length);
-
-static void
-acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
-                            struct acpi_table_header *header);
-
 static acpi_physical_address
 acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
 
@@ -174,189 +168,6 @@ u8 acpi_tb_tables_loaded(void)
        return (FALSE);
 }
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_fix_string
- *
- * PARAMETERS:  string              - String to be repaired
- *              length              - Maximum length
- *
- * RETURN:      None
- *
- * DESCRIPTION: Replace every non-printable or non-ascii byte in the string
- *              with a question mark '?'.
- *
- ******************************************************************************/
-
-static void acpi_tb_fix_string(char *string, acpi_size length)
-{
-
-       while (length && *string) {
-               if (!ACPI_IS_PRINT(*string)) {
-                       *string = '?';
-               }
-               string++;
-               length--;
-       }
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_cleanup_table_header
- *
- * PARAMETERS:  out_header          - Where the cleaned header is returned
- *              header              - Input ACPI table header
- *
- * RETURN:      Returns the cleaned header in out_header
- *
- * DESCRIPTION: Copy the table header and ensure that all "string" fields in
- *              the header consist of printable characters.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
-                            struct acpi_table_header *header)
-{
-
-       ACPI_MEMCPY(out_header, header, sizeof(struct acpi_table_header));
-
-       acpi_tb_fix_string(out_header->signature, ACPI_NAME_SIZE);
-       acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE);
-       acpi_tb_fix_string(out_header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
-       acpi_tb_fix_string(out_header->asl_compiler_id, ACPI_NAME_SIZE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_print_table_header
- *
- * PARAMETERS:  address             - Table physical address
- *              header              - Table header
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
- *
- ******************************************************************************/
-
-void
-acpi_tb_print_table_header(acpi_physical_address address,
-                          struct acpi_table_header *header)
-{
-       struct acpi_table_header local_header;
-
-       /*
-        * The reason that the Address is cast to a void pointer is so that we
-        * can use %p which will work properly on both 32-bit and 64-bit hosts.
-        */
-       if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
-
-               /* FACS only has signature and length fields */
-
-               ACPI_INFO((AE_INFO, "%4.4s %p %05X",
-                          header->signature, ACPI_CAST_PTR(void, address),
-                          header->length));
-       } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
-
-               /* RSDP has no common fields */
-
-               ACPI_MEMCPY(local_header.oem_id,
-                           ACPI_CAST_PTR(struct acpi_table_rsdp,
-                                         header)->oem_id, ACPI_OEM_ID_SIZE);
-               acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE);
-
-               ACPI_INFO((AE_INFO, "RSDP %p %05X (v%.2d %6.6s)",
-                          ACPI_CAST_PTR (void, address),
-                          (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
-                           revision >
-                           0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
-                                              header)->length : 20,
-                          ACPI_CAST_PTR(struct acpi_table_rsdp,
-                                        header)->revision,
-                          local_header.oem_id));
-       } else {
-               /* Standard ACPI table with full common header */
-
-               acpi_tb_cleanup_table_header(&local_header, header);
-
-               ACPI_INFO((AE_INFO,
-                          "%4.4s %p %05X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
-                          local_header.signature, ACPI_CAST_PTR(void, address),
-                          local_header.length, local_header.revision,
-                          local_header.oem_id, local_header.oem_table_id,
-                          local_header.oem_revision,
-                          local_header.asl_compiler_id,
-                          local_header.asl_compiler_revision));
-
-       }
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_validate_checksum
- *
- * PARAMETERS:  table               - ACPI table to verify
- *              length              - Length of entire table
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
- *              exception on bad checksum.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
-{
-       u8 checksum;
-
-       /* Compute the checksum on the table */
-
-       checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
-
-       /* Checksum ok? (should be zero) */
-
-       if (checksum) {
-               ACPI_BIOS_WARNING((AE_INFO,
-                                  "Incorrect checksum in table [%4.4s] - 0x%2.2X, "
-                                  "should be 0x%2.2X",
-                                  table->signature, table->checksum,
-                                  (u8)(table->checksum - checksum)));
-
-#if (ACPI_CHECKSUM_ABORT)
-
-               return (AE_BAD_CHECKSUM);
-#endif
-       }
-
-       return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_checksum
- *
- * PARAMETERS:  buffer          - Pointer to memory region to be checked
- *              length          - Length of this memory region
- *
- * RETURN:      Checksum (u8)
- *
- * DESCRIPTION: Calculates circular checksum of memory region.
- *
- ******************************************************************************/
-
-u8 acpi_tb_checksum(u8 *buffer, u32 length)
-{
-       u8 sum = 0;
-       u8 *end = buffer + length;
-
-       while (buffer < end) {
-               sum = (u8) (sum + *(buffer++));
-       }
-
-       return (sum);
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_tb_check_dsdt_header
index 67e046ec8f0afaedfec54d273b3193a9cffbb63a..0ba9e328d5d7b0c6fa199f4c7c8bc11ad135c9a1 100644 (file)
@@ -53,8 +53,6 @@ ACPI_MODULE_NAME("tbxfload")
 /* Local prototypes */
 static acpi_status acpi_tb_load_namespace(void);
 
-static int no_auto_ssdt;
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_load_tables
@@ -180,8 +178,16 @@ static acpi_status acpi_tb_load_namespace(void)
                        continue;
                }
 
-               if (no_auto_ssdt) {
-                       printk(KERN_WARNING "ACPI: SSDT ignored due to \"acpi_no_auto_ssdt\"\n");
+               /*
+                * Optionally do not load any SSDTs from the RSDT/XSDT. This can
+                * be useful for debugging ACPI problems on some machines.
+                */
+               if (acpi_gbl_disable_ssdt_table_load) {
+                       ACPI_INFO((AE_INFO, "Ignoring %4.4s at %p",
+                                  acpi_gbl_root_table_list.tables[i].signature.
+                                  ascii, ACPI_CAST_PTR(void,
+                                                       acpi_gbl_root_table_list.
+                                                       tables[i].address)));
                        continue;
                }
 
@@ -376,14 +382,3 @@ acpi_status acpi_unload_parent_table(acpi_handle object)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_unload_parent_table)
-
-static int __init acpi_no_auto_ssdt_setup(char *s) {
-
-        printk(KERN_NOTICE "ACPI: SSDT auto-load disabled\n");
-
-        no_auto_ssdt = 1;
-
-        return 1;
-}
-
-__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c
new file mode 100644 (file)
index 0000000..11fde93
--- /dev/null
@@ -0,0 +1,201 @@
+/******************************************************************************
+ *
+ * Module Name: utbuffer - Buffer dump routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utbuffer")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_dump_buffer
+ *
+ * PARAMETERS:  buffer              - Buffer to dump
+ *              count               - Amount to dump, in bytes
+ *              display             - BYTE, WORD, DWORD, or QWORD display:
+ *                                      DB_BYTE_DISPLAY
+ *                                      DB_WORD_DISPLAY
+ *                                      DB_DWORD_DISPLAY
+ *                                      DB_QWORD_DISPLAY
+ *              base_offset         - Beginning buffer offset (display only)
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Generic dump buffer in both hex and ascii.
+ *
+ ******************************************************************************/
+void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset)
+{
+       u32 i = 0;
+       u32 j;
+       u32 temp32;
+       u8 buf_char;
+
+       if (!buffer) {
+               acpi_os_printf("Null Buffer Pointer in DumpBuffer!\n");
+               return;
+       }
+
+       if ((count < 4) || (count & 0x01)) {
+               display = DB_BYTE_DISPLAY;
+       }
+
+       /* Nasty little dump buffer routine! */
+
+       while (i < count) {
+
+               /* Print current offset */
+
+               acpi_os_printf("%6.4X: ", (base_offset + i));
+
+               /* Print 16 hex chars */
+
+               for (j = 0; j < 16;) {
+                       if (i + j >= count) {
+
+                               /* Dump fill spaces */
+
+                               acpi_os_printf("%*s", ((display * 2) + 1), " ");
+                               j += display;
+                               continue;
+                       }
+
+                       switch (display) {
+                       case DB_BYTE_DISPLAY:
+                       default:        /* Default is BYTE display */
+
+                               acpi_os_printf("%02X ",
+                                              buffer[(acpi_size) i + j]);
+                               break;
+
+                       case DB_WORD_DISPLAY:
+
+                               ACPI_MOVE_16_TO_32(&temp32,
+                                                  &buffer[(acpi_size) i + j]);
+                               acpi_os_printf("%04X ", temp32);
+                               break;
+
+                       case DB_DWORD_DISPLAY:
+
+                               ACPI_MOVE_32_TO_32(&temp32,
+                                                  &buffer[(acpi_size) i + j]);
+                               acpi_os_printf("%08X ", temp32);
+                               break;
+
+                       case DB_QWORD_DISPLAY:
+
+                               ACPI_MOVE_32_TO_32(&temp32,
+                                                  &buffer[(acpi_size) i + j]);
+                               acpi_os_printf("%08X", temp32);
+
+                               ACPI_MOVE_32_TO_32(&temp32,
+                                                  &buffer[(acpi_size) i + j +
+                                                          4]);
+                               acpi_os_printf("%08X ", temp32);
+                               break;
+                       }
+
+                       j += display;
+               }
+
+               /*
+                * Print the ASCII equivalent characters but watch out for the bad
+                * unprintable ones (printable chars are 0x20 through 0x7E)
+                */
+               acpi_os_printf(" ");
+               for (j = 0; j < 16; j++) {
+                       if (i + j >= count) {
+                               acpi_os_printf("\n");
+                               return;
+                       }
+
+                       buf_char = buffer[(acpi_size) i + j];
+                       if (ACPI_IS_PRINT(buf_char)) {
+                               acpi_os_printf("%c", buf_char);
+                       } else {
+                               acpi_os_printf(".");
+                       }
+               }
+
+               /* Done with that line. */
+
+               acpi_os_printf("\n");
+               i += 16;
+       }
+
+       return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_debug_dump_buffer
+ *
+ * PARAMETERS:  buffer              - Buffer to dump
+ *              count               - Amount to dump, in bytes
+ *              display             - BYTE, WORD, DWORD, or QWORD display:
+ *                                      DB_BYTE_DISPLAY
+ *                                      DB_WORD_DISPLAY
+ *                                      DB_DWORD_DISPLAY
+ *                                      DB_QWORD_DISPLAY
+ *              component_ID        - Caller's component ID
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Generic dump buffer in both hex and ascii.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id)
+{
+
+       /* Only dump the buffer if tracing is enabled */
+
+       if (!((ACPI_LV_TABLES & acpi_dbg_level) &&
+             (component_id & acpi_dbg_layer))) {
+               return;
+       }
+
+       acpi_ut_dump_buffer(buffer, count, display, 0);
+}
index e4c9291fc0a3f530bfaea472895f6217a23f8b99..1731c27c36a682e5d47beba328096ff9c633043a 100644 (file)
@@ -178,7 +178,6 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object,
 
                switch (internal_object->reference.class) {
                case ACPI_REFCLASS_NAME:
-
                        /*
                         * For namepath, return the object handle ("reference")
                         * We are referring to the namespace node
@@ -264,7 +263,6 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type,
 
        switch (object_type) {
        case ACPI_COPY_TYPE_SIMPLE:
-
                /*
                 * This is a simple or null object
                 */
@@ -278,7 +276,6 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type,
                break;
 
        case ACPI_COPY_TYPE_PACKAGE:
-
                /*
                 * Build the package object
                 */
@@ -304,6 +301,7 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type,
                break;
 
        default:
+
                return (AE_BAD_PARAMETER);
        }
 
@@ -481,6 +479,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
                return_ACPI_STATUS(AE_OK);
 
        default:
+
                /* All other types are not supported */
 
                ACPI_ERROR((AE_INFO,
@@ -544,7 +543,9 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
                break;
 
        default:
+
                /* Other types can't get here */
+
                break;
        }
 
@@ -800,7 +801,9 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
                break;
 
        default:
+
                /* Nothing to do for other simple objects */
+
                break;
        }
 
@@ -868,7 +871,6 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type,
                break;
 
        case ACPI_COPY_TYPE_PACKAGE:
-
                /*
                 * This object is a package - go down another nesting level
                 * Create and build the package object
@@ -891,6 +893,7 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type,
                break;
 
        default:
+
                return (AE_BAD_PARAMETER);
        }
 
index c57d9cc07ba913c9576792f395ffcea08a76fc03..5796e11a0671d32fad4329262e05b51d038cd38e 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Module Name: utdebug - Debug print routines
+ * Module Name: utdebug - Debug print/trace routines
  *
  *****************************************************************************/
 
@@ -543,149 +543,3 @@ acpi_ut_ptr_exit(u32 line_number,
 }
 
 #endif
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_dump_buffer
- *
- * PARAMETERS:  buffer              - Buffer to dump
- *              count               - Amount to dump, in bytes
- *              display             - BYTE, WORD, DWORD, or QWORD display
- *              offset              - Beginning buffer offset (display only)
- *
- * RETURN:      None
- *
- * DESCRIPTION: Generic dump buffer in both hex and ascii.
- *
- ******************************************************************************/
-
-void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset)
-{
-       u32 i = 0;
-       u32 j;
-       u32 temp32;
-       u8 buf_char;
-
-       if (!buffer) {
-               acpi_os_printf("Null Buffer Pointer in DumpBuffer!\n");
-               return;
-       }
-
-       if ((count < 4) || (count & 0x01)) {
-               display = DB_BYTE_DISPLAY;
-       }
-
-       /* Nasty little dump buffer routine! */
-
-       while (i < count) {
-
-               /* Print current offset */
-
-               acpi_os_printf("%6.4X: ", (base_offset + i));
-
-               /* Print 16 hex chars */
-
-               for (j = 0; j < 16;) {
-                       if (i + j >= count) {
-
-                               /* Dump fill spaces */
-
-                               acpi_os_printf("%*s", ((display * 2) + 1), " ");
-                               j += display;
-                               continue;
-                       }
-
-                       switch (display) {
-                       case DB_BYTE_DISPLAY:
-                       default:        /* Default is BYTE display */
-
-                               acpi_os_printf("%02X ",
-                                              buffer[(acpi_size) i + j]);
-                               break;
-
-                       case DB_WORD_DISPLAY:
-
-                               ACPI_MOVE_16_TO_32(&temp32,
-                                                  &buffer[(acpi_size) i + j]);
-                               acpi_os_printf("%04X ", temp32);
-                               break;
-
-                       case DB_DWORD_DISPLAY:
-
-                               ACPI_MOVE_32_TO_32(&temp32,
-                                                  &buffer[(acpi_size) i + j]);
-                               acpi_os_printf("%08X ", temp32);
-                               break;
-
-                       case DB_QWORD_DISPLAY:
-
-                               ACPI_MOVE_32_TO_32(&temp32,
-                                                  &buffer[(acpi_size) i + j]);
-                               acpi_os_printf("%08X", temp32);
-
-                               ACPI_MOVE_32_TO_32(&temp32,
-                                                  &buffer[(acpi_size) i + j +
-                                                          4]);
-                               acpi_os_printf("%08X ", temp32);
-                               break;
-                       }
-
-                       j += display;
-               }
-
-               /*
-                * Print the ASCII equivalent characters but watch out for the bad
-                * unprintable ones (printable chars are 0x20 through 0x7E)
-                */
-               acpi_os_printf(" ");
-               for (j = 0; j < 16; j++) {
-                       if (i + j >= count) {
-                               acpi_os_printf("\n");
-                               return;
-                       }
-
-                       buf_char = buffer[(acpi_size) i + j];
-                       if (ACPI_IS_PRINT(buf_char)) {
-                               acpi_os_printf("%c", buf_char);
-                       } else {
-                               acpi_os_printf(".");
-                       }
-               }
-
-               /* Done with that line. */
-
-               acpi_os_printf("\n");
-               i += 16;
-       }
-
-       return;
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_debug_dump_buffer
- *
- * PARAMETERS:  buffer              - Buffer to dump
- *              count               - Amount to dump, in bytes
- *              display             - BYTE, WORD, DWORD, or QWORD display
- *              component_ID        - Caller's component ID
- *
- * RETURN:      None
- *
- * DESCRIPTION: Generic dump buffer in both hex and ascii.
- *
- ******************************************************************************/
-
-void
-acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id)
-{
-
-       /* Only dump the buffer if tracing is enabled */
-
-       if (!((ACPI_LV_TABLES & acpi_dbg_level) &&
-             (component_id & acpi_dbg_layer))) {
-               return;
-       }
-
-       acpi_ut_dump_buffer(buffer, count, display, 0);
-}
index 29b930250b6fe01a7822a229dc0f45ed80290a52..d6b33f29d32754a50eef108ce1287b59886b013b 100644 (file)
@@ -303,6 +303,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
                break;
 
        default:
+
                break;
        }
 
@@ -508,7 +509,6 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
                case ACPI_TYPE_PROCESSOR:
                case ACPI_TYPE_POWER:
                case ACPI_TYPE_THERMAL:
-
                        /*
                         * Update the notify objects for these types (if present)
                         * Two lists, system and device notify handlers.
@@ -623,6 +623,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
 
                case ACPI_TYPE_REGION:
                default:
+
                        break;  /* No subobjects for all other types */
                }
 
diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c
new file mode 100644 (file)
index 0000000..154fdca
--- /dev/null
@@ -0,0 +1,289 @@
+/*******************************************************************************
+ *
+ * Module Name: uterror - Various internal error/warning output functions
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("uterror")
+
+/*
+ * This module contains internal error functions that may
+ * be configured out.
+ */
+#if !defined (ACPI_NO_ERROR_MESSAGES)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_predefined_warning
+ *
+ * PARAMETERS:  module_name     - Caller's module name (for error output)
+ *              line_number     - Caller's line number (for error output)
+ *              pathname        - Full pathname to the node
+ *              node_flags      - From Namespace node for the method/object
+ *              format          - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Warnings for the predefined validation module. Messages are
+ *              only emitted the first time a problem with a particular
+ *              method/object is detected. This prevents a flood of error
+ *              messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+                          u32 line_number,
+                          char *pathname,
+                          u8 node_flags, const char *format, ...)
+{
+       va_list arg_list;
+
+       /*
+        * Warning messages for this method/object will be disabled after the
+        * first time a validation fails or an object is successfully repaired.
+        */
+       if (node_flags & ANOBJ_EVALUATED) {
+               return;
+       }
+
+       acpi_os_printf(ACPI_MSG_WARNING "%s: ", pathname);
+
+       va_start(arg_list, format);
+       acpi_os_vprintf(format, arg_list);
+       ACPI_MSG_SUFFIX;
+       va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_predefined_info
+ *
+ * PARAMETERS:  module_name     - Caller's module name (for error output)
+ *              line_number     - Caller's line number (for error output)
+ *              pathname        - Full pathname to the node
+ *              node_flags      - From Namespace node for the method/object
+ *              format          - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Info messages for the predefined validation module. Messages
+ *              are only emitted the first time a problem with a particular
+ *              method/object is detected. This prevents a flood of
+ *              messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_info(const char *module_name,
+                       u32 line_number,
+                       char *pathname, u8 node_flags, const char *format, ...)
+{
+       va_list arg_list;
+
+       /*
+        * Warning messages for this method/object will be disabled after the
+        * first time a validation fails or an object is successfully repaired.
+        */
+       if (node_flags & ANOBJ_EVALUATED) {
+               return;
+       }
+
+       acpi_os_printf(ACPI_MSG_INFO "%s: ", pathname);
+
+       va_start(arg_list, format);
+       acpi_os_vprintf(format, arg_list);
+       ACPI_MSG_SUFFIX;
+       va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_predefined_bios_error
+ *
+ * PARAMETERS:  module_name     - Caller's module name (for error output)
+ *              line_number     - Caller's line number (for error output)
+ *              pathname        - Full pathname to the node
+ *              node_flags      - From Namespace node for the method/object
+ *              format          - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: BIOS error message for predefined names. Messages
+ *              are only emitted the first time a problem with a particular
+ *              method/object is detected. This prevents a flood of
+ *              messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_bios_error(const char *module_name,
+                             u32 line_number,
+                             char *pathname,
+                             u8 node_flags, const char *format, ...)
+{
+       va_list arg_list;
+
+       /*
+        * Warning messages for this method/object will be disabled after the
+        * first time a validation fails or an object is successfully repaired.
+        */
+       if (node_flags & ANOBJ_EVALUATED) {
+               return;
+       }
+
+       acpi_os_printf(ACPI_MSG_BIOS_ERROR "%s: ", pathname);
+
+       va_start(arg_list, format);
+       acpi_os_vprintf(format, arg_list);
+       ACPI_MSG_SUFFIX;
+       va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_namespace_error
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              internal_name       - Name or path of the namespace node
+ *              lookup_status       - Exception code from NS lookup
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print error message with the full pathname for the NS node.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_namespace_error(const char *module_name,
+                       u32 line_number,
+                       const char *internal_name, acpi_status lookup_status)
+{
+       acpi_status status;
+       u32 bad_name;
+       char *name = NULL;
+
+       ACPI_MSG_REDIRECT_BEGIN;
+       acpi_os_printf(ACPI_MSG_ERROR);
+
+       if (lookup_status == AE_BAD_CHARACTER) {
+
+               /* There is a non-ascii character in the name */
+
+               ACPI_MOVE_32_TO_32(&bad_name,
+                                  ACPI_CAST_PTR(u32, internal_name));
+               acpi_os_printf("[0x%.8X] (NON-ASCII)", bad_name);
+       } else {
+               /* Convert path to external format */
+
+               status = acpi_ns_externalize_name(ACPI_UINT32_MAX,
+                                                 internal_name, NULL, &name);
+
+               /* Print target name */
+
+               if (ACPI_SUCCESS(status)) {
+                       acpi_os_printf("[%s]", name);
+               } else {
+                       acpi_os_printf("[COULD NOT EXTERNALIZE NAME]");
+               }
+
+               if (name) {
+                       ACPI_FREE(name);
+               }
+       }
+
+       acpi_os_printf(" Namespace lookup failure, %s",
+                      acpi_format_exception(lookup_status));
+
+       ACPI_MSG_SUFFIX;
+       ACPI_MSG_REDIRECT_END;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_method_error
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              message             - Error message to use on failure
+ *              prefix_node         - Prefix relative to the path
+ *              path                - Path to the node (optional)
+ *              method_status       - Execution status
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print error message with the full pathname for the method.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_method_error(const char *module_name,
+                    u32 line_number,
+                    const char *message,
+                    struct acpi_namespace_node *prefix_node,
+                    const char *path, acpi_status method_status)
+{
+       acpi_status status;
+       struct acpi_namespace_node *node = prefix_node;
+
+       ACPI_MSG_REDIRECT_BEGIN;
+       acpi_os_printf(ACPI_MSG_ERROR);
+
+       if (path) {
+               status =
+                   acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
+                                    &node);
+               if (ACPI_FAILURE(status)) {
+                       acpi_os_printf("[Could not get node by pathname]");
+               }
+       }
+
+       acpi_ns_print_node_pathname(node, message);
+       acpi_os_printf(", %s", acpi_format_exception(method_status));
+
+       ACPI_MSG_SUFFIX;
+       ACPI_MSG_REDIRECT_END;
+}
+
+#endif                         /* ACPI_NO_ERROR_MESSAGES */
index c3f3a7e7bdc7fd6bc51ba43b1d8ff8e3c6d6eb76..ee83adb97b1e73827a6a7740de03edb3680e2a28 100644 (file)
@@ -68,7 +68,7 @@ ACPI_MODULE_NAME("uteval")
  ******************************************************************************/
 
 acpi_status
-acpi_ut_evaluate_object(struct acpi_namespace_node * prefix_node,
+acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
                        char *path,
                        u32 expected_return_btypes,
                        union acpi_operand_object **return_desc)
@@ -87,7 +87,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node * prefix_node,
        }
 
        info->prefix_node = prefix_node;
-       info->pathname = path;
+       info->relative_pathname = path;
 
        /* Evaluate the object/method */
 
@@ -123,22 +123,27 @@ acpi_ut_evaluate_object(struct acpi_namespace_node * prefix_node,
 
        switch ((info->return_object)->common.type) {
        case ACPI_TYPE_INTEGER:
+
                return_btype = ACPI_BTYPE_INTEGER;
                break;
 
        case ACPI_TYPE_BUFFER:
+
                return_btype = ACPI_BTYPE_BUFFER;
                break;
 
        case ACPI_TYPE_STRING:
+
                return_btype = ACPI_BTYPE_STRING;
                break;
 
        case ACPI_TYPE_PACKAGE:
+
                return_btype = ACPI_BTYPE_PACKAGE;
                break;
 
        default:
+
                return_btype = 0;
                break;
        }
index b543a144941a295a81c7aa9f237b56ac07e1a748..ff6d9e8aa8423ef04ed68ec18023d61ee570493b 100644 (file)
@@ -146,6 +146,7 @@ const struct acpi_exception_info *acpi_ut_validate_exception(acpi_status status)
                break;
 
        default:
+
                break;
        }
 
index 43a170a74a6139ae3aa10ae1120b27f773103085..fa69071db4181dc100e3242053756944590679f8 100644 (file)
@@ -341,14 +341,17 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
 
                switch (cid_objects[i]->common.type) {
                case ACPI_TYPE_INTEGER:
+
                        string_area_size += ACPI_EISAID_STRING_SIZE;
                        break;
 
                case ACPI_TYPE_STRING:
+
                        string_area_size += cid_objects[i]->string.length + 1;
                        break;
 
                default:
+
                        status = AE_TYPE;
                        goto cleanup;
                }
index 785fdd07ae5673db012d27b1519dce75e85c3827..02f9101b65e47c29dc974020a8701322c9dc3824 100644 (file)
@@ -382,10 +382,12 @@ acpi_ut_display_init_pathname(u8 type,
 
        switch (type) {
        case ACPI_TYPE_METHOD:
+
                acpi_os_printf("Executing  ");
                break;
 
        default:
+
                acpi_os_printf("Initializing ");
                break;
        }
index 1099f5c069f8287fb354f148c9f8d681fcc94e44..aa61f66ee861ed1de71fee8bb72d0e412627382c 100644 (file)
@@ -129,6 +129,7 @@ union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char
                break;
 
        default:
+
                /* All others have no secondary object */
                break;
        }
@@ -353,6 +354,7 @@ u8 acpi_ut_valid_internal_object(void *object)
                return (TRUE);
 
        default:
+
                ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
                                  "%p is not not an ACPI operand obj [%s]\n",
                                  object, acpi_ut_get_descriptor_name(object)));
@@ -509,7 +511,6 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
 
                switch (internal_object->reference.class) {
                case ACPI_REFCLASS_NAME:
-
                        /*
                         * Get the actual length of the full pathname to this object.
                         * The reference will be converted to the pathname to the object
@@ -525,7 +526,6 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
                        break;
 
                default:
-
                        /*
                         * No other reference opcodes are supported.
                         * Notably, Locals and Args are not supported, but this may be
@@ -585,7 +585,6 @@ acpi_ut_get_element_length(u8 object_type,
 
        switch (object_type) {
        case ACPI_COPY_TYPE_SIMPLE:
-
                /*
                 * Simple object - just get the size (Null object/entry is handled
                 * here also) and sum it into the running package length
index 29459479148fe7b1e23f7b0fe64ea85a0c48b7bb..2b1ce4cd32073fc23e6bcb7d6c5666d156ae6432 100644 (file)
@@ -147,6 +147,11 @@ void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes)
        u32 i;
        u32 j;
 
+       if (!expected_btypes) {
+               ACPI_STRCPY(buffer, "NONE");
+               return;
+       }
+
        j = 1;
        buffer[0] = 0;
        this_rtype = ACPI_RTYPE_INTEGER;
@@ -328,9 +333,7 @@ static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types)
 
        /* First field in the types list is the count of args to follow */
 
-       arg_count = (argument_types & METHOD_ARG_MASK);
-       argument_types >>= METHOD_ARG_BIT_WIDTH;
-
+       arg_count = METHOD_GET_ARG_COUNT(argument_types);
        if (arg_count > METHOD_PREDEF_ARGS_MAX) {
                printf("**** Invalid argument count (%u) "
                       "in predefined info structure\n", arg_count);
@@ -340,7 +343,8 @@ static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types)
        /* Get each argument from the list, convert to ascii, store to buffer */
 
        for (i = 0; i < arg_count; i++) {
-               this_argument_type = (argument_types & METHOD_ARG_MASK);
+               this_argument_type = METHOD_GET_NEXT_TYPE(argument_types);
+
                if (!this_argument_type
                    || (this_argument_type > METHOD_MAX_ARG_TYPE)) {
                        printf("**** Invalid argument type (%u) "
@@ -351,10 +355,6 @@ static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types)
 
                strcat(buffer,
                       ut_external_type_names[this_argument_type] + sub_index);
-
-               /* Shift to next argument type field */
-
-               argument_types >>= METHOD_ARG_BIT_WIDTH;
                sub_index = 0;
        }
 
index b3e36a81aa4d1360b9280d2edd6d9d5f9e7330dd..c53759b76a3f97d0fe5558f36ad9b656fbc905fa 100644 (file)
@@ -186,10 +186,13 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
        switch (base) {
        case ACPI_ANY_BASE:
        case 16:
+
                break;
 
        default:
+
                /* Invalid Base */
+
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
@@ -355,36 +358,44 @@ void acpi_ut_print_string(char *string, u8 max_length)
 
                switch (string[i]) {
                case 0x07:
+
                        acpi_os_printf("\\a");  /* BELL */
                        break;
 
                case 0x08:
+
                        acpi_os_printf("\\b");  /* BACKSPACE */
                        break;
 
                case 0x0C:
+
                        acpi_os_printf("\\f");  /* FORMFEED */
                        break;
 
                case 0x0A:
+
                        acpi_os_printf("\\n");  /* LINEFEED */
                        break;
 
                case 0x0D:
+
                        acpi_os_printf("\\r");  /* CARRIAGE RETURN */
                        break;
 
                case 0x09:
+
                        acpi_os_printf("\\t");  /* HORIZONTAL TAB */
                        break;
 
                case 0x0B:
+
                        acpi_os_printf("\\v");  /* VERTICAL TAB */
                        break;
 
                case '\'':      /* Single Quote */
                case '\"':      /* Double Quote */
                case '\\':      /* Backslash */
+
                        acpi_os_printf("\\%c", (int)string[i]);
                        break;
 
@@ -451,7 +462,8 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position)
  *
  * FUNCTION:    acpi_ut_valid_acpi_name
  *
- * PARAMETERS:  name            - The name to be examined
+ * PARAMETERS:  name            - The name to be examined. Does not have to
+ *                                be NULL terminated string.
  *
  * RETURN:      TRUE if the name is valid, FALSE otherwise
  *
@@ -462,15 +474,14 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position)
  *
  ******************************************************************************/
 
-u8 acpi_ut_valid_acpi_name(u32 name)
+u8 acpi_ut_valid_acpi_name(char *name)
 {
        u32 i;
 
        ACPI_FUNCTION_ENTRY();
 
        for (i = 0; i < ACPI_NAME_SIZE; i++) {
-               if (!acpi_ut_valid_acpi_char
-                   ((ACPI_CAST_PTR(char, &name))[i], i)) {
+               if (!acpi_ut_valid_acpi_char(name[i], i)) {
                        return (FALSE);
                }
        }
index 62774c7b76a81402633d417277be05c5953239d0..160f13f4aab51a196200184c60cc625a5de4acc6 100644 (file)
@@ -603,6 +603,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
                                        switch (ACPI_GET_DESCRIPTOR_TYPE
                                                (descriptor)) {
                                        case ACPI_DESC_TYPE_OPERAND:
+
                                                if (element->size ==
                                                    sizeof(union
                                                           acpi_operand_object))
@@ -613,6 +614,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
                                                break;
 
                                        case ACPI_DESC_TYPE_PARSER:
+
                                                if (element->size ==
                                                    sizeof(union
                                                           acpi_parse_object)) {
@@ -622,6 +624,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
                                                break;
 
                                        case ACPI_DESC_TYPE_NAMED:
+
                                                if (element->size ==
                                                    sizeof(struct
                                                           acpi_namespace_node))
@@ -632,6 +635,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
                                                break;
 
                                        default:
+
                                                break;
                                        }
 
@@ -639,6 +643,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
 
                                        switch (descriptor_type) {
                                        case ACPI_DESC_TYPE_OPERAND:
+
                                                acpi_os_printf
                                                    ("%12.12s RefCount 0x%04X\n",
                                                     acpi_ut_get_type_name
@@ -649,6 +654,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
                                                break;
 
                                        case ACPI_DESC_TYPE_PARSER:
+
                                                acpi_os_printf
                                                    ("AmlOpcode 0x%04hX\n",
                                                     descriptor->op.asl.
@@ -656,6 +662,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
                                                break;
 
                                        case ACPI_DESC_TYPE_NAMED:
+
                                                acpi_os_printf("%4.4s\n",
                                                               acpi_ut_get_node_name
                                                               (&descriptor->
@@ -663,6 +670,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
                                                break;
 
                                        default:
+
                                                acpi_os_printf("\n");
                                                break;
                                        }
index 976b6c734fce961b44a94773a4e8357b02727735..e966a2e47b765e6c097ca7973b54fa2d987ab6cd 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/export.h>
 #include <acpi/acpi.h>
 #include "accommon.h"
-#include "acnamesp.h"
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utxferror")
@@ -52,43 +51,7 @@ ACPI_MODULE_NAME("utxferror")
 /*
  * This module is used for the in-kernel ACPICA as well as the ACPICA
  * tools/applications.
- *
- * For the iASL compiler case, the output is redirected to stderr so that
- * any of the various ACPI errors and warnings do not appear in the output
- * files, for either the compiler or disassembler portions of the tool.
  */
-#ifdef ACPI_ASL_COMPILER
-#include <stdio.h>
-extern FILE *acpi_gbl_output_file;
-
-#define ACPI_MSG_REDIRECT_BEGIN \
-       FILE                            *output_file = acpi_gbl_output_file; \
-       acpi_os_redirect_output (stderr);
-
-#define ACPI_MSG_REDIRECT_END \
-       acpi_os_redirect_output (output_file);
-
-#else
-/*
- * non-iASL case - no redirection, nothing to do
- */
-#define ACPI_MSG_REDIRECT_BEGIN
-#define ACPI_MSG_REDIRECT_END
-#endif
-/*
- * Common message prefixes
- */
-#define ACPI_MSG_ERROR          "ACPI Error: "
-#define ACPI_MSG_EXCEPTION      "ACPI Exception: "
-#define ACPI_MSG_WARNING        "ACPI Warning: "
-#define ACPI_MSG_INFO           "ACPI: "
-#define ACPI_MSG_BIOS_ERROR     "ACPI BIOS Bug: Error: "
-#define ACPI_MSG_BIOS_WARNING   "ACPI BIOS Bug: Warning: "
-/*
- * Common message suffix
- */
-#define ACPI_MSG_SUFFIX \
-       acpi_os_printf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
 /*******************************************************************************
  *
  * FUNCTION:    acpi_error
@@ -285,200 +248,3 @@ acpi_bios_warning(const char *module_name,
 }
 
 ACPI_EXPORT_SYMBOL(acpi_bios_warning)
-
-/*
- * The remainder of this module contains internal error functions that may
- * be configured out.
- */
-#if !defined (ACPI_NO_ERROR_MESSAGES) && !defined (ACPI_BIN_APP)
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_predefined_warning
- *
- * PARAMETERS:  module_name     - Caller's module name (for error output)
- *              line_number     - Caller's line number (for error output)
- *              pathname        - Full pathname to the node
- *              node_flags      - From Namespace node for the method/object
- *              format          - Printf format string + additional args
- *
- * RETURN:      None
- *
- * DESCRIPTION: Warnings for the predefined validation module. Messages are
- *              only emitted the first time a problem with a particular
- *              method/object is detected. This prevents a flood of error
- *              messages for methods that are repeatedly evaluated.
- *
- ******************************************************************************/
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_warning(const char *module_name,
-                          u32 line_number,
-                          char *pathname,
-                          u8 node_flags, const char *format, ...)
-{
-       va_list arg_list;
-
-       /*
-        * Warning messages for this method/object will be disabled after the
-        * first time a validation fails or an object is successfully repaired.
-        */
-       if (node_flags & ANOBJ_EVALUATED) {
-               return;
-       }
-
-       acpi_os_printf(ACPI_MSG_WARNING "For %s: ", pathname);
-
-       va_start(arg_list, format);
-       acpi_os_vprintf(format, arg_list);
-       ACPI_MSG_SUFFIX;
-       va_end(arg_list);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_predefined_info
- *
- * PARAMETERS:  module_name     - Caller's module name (for error output)
- *              line_number     - Caller's line number (for error output)
- *              pathname        - Full pathname to the node
- *              node_flags      - From Namespace node for the method/object
- *              format          - Printf format string + additional args
- *
- * RETURN:      None
- *
- * DESCRIPTION: Info messages for the predefined validation module. Messages
- *              are only emitted the first time a problem with a particular
- *              method/object is detected. This prevents a flood of
- *              messages for methods that are repeatedly evaluated.
- *
- ******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_info(const char *module_name,
-                       u32 line_number,
-                       char *pathname, u8 node_flags, const char *format, ...)
-{
-       va_list arg_list;
-
-       /*
-        * Warning messages for this method/object will be disabled after the
-        * first time a validation fails or an object is successfully repaired.
-        */
-       if (node_flags & ANOBJ_EVALUATED) {
-               return;
-       }
-
-       acpi_os_printf(ACPI_MSG_INFO "For %s: ", pathname);
-
-       va_start(arg_list, format);
-       acpi_os_vprintf(format, arg_list);
-       ACPI_MSG_SUFFIX;
-       va_end(arg_list);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_namespace_error
- *
- * PARAMETERS:  module_name         - Caller's module name (for error output)
- *              line_number         - Caller's line number (for error output)
- *              internal_name       - Name or path of the namespace node
- *              lookup_status       - Exception code from NS lookup
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print error message with the full pathname for the NS node.
- *
- ******************************************************************************/
-
-void
-acpi_ut_namespace_error(const char *module_name,
-                       u32 line_number,
-                       const char *internal_name, acpi_status lookup_status)
-{
-       acpi_status status;
-       u32 bad_name;
-       char *name = NULL;
-
-       ACPI_MSG_REDIRECT_BEGIN;
-       acpi_os_printf(ACPI_MSG_ERROR);
-
-       if (lookup_status == AE_BAD_CHARACTER) {
-
-               /* There is a non-ascii character in the name */
-
-               ACPI_MOVE_32_TO_32(&bad_name,
-                                  ACPI_CAST_PTR(u32, internal_name));
-               acpi_os_printf("[0x%.8X] (NON-ASCII)", bad_name);
-       } else {
-               /* Convert path to external format */
-
-               status = acpi_ns_externalize_name(ACPI_UINT32_MAX,
-                                                 internal_name, NULL, &name);
-
-               /* Print target name */
-
-               if (ACPI_SUCCESS(status)) {
-                       acpi_os_printf("[%s]", name);
-               } else {
-                       acpi_os_printf("[COULD NOT EXTERNALIZE NAME]");
-               }
-
-               if (name) {
-                       ACPI_FREE(name);
-               }
-       }
-
-       acpi_os_printf(" Namespace lookup failure, %s",
-                      acpi_format_exception(lookup_status));
-
-       ACPI_MSG_SUFFIX;
-       ACPI_MSG_REDIRECT_END;
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_method_error
- *
- * PARAMETERS:  module_name         - Caller's module name (for error output)
- *              line_number         - Caller's line number (for error output)
- *              message             - Error message to use on failure
- *              prefix_node         - Prefix relative to the path
- *              path                - Path to the node (optional)
- *              method_status       - Execution status
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print error message with the full pathname for the method.
- *
- ******************************************************************************/
-
-void
-acpi_ut_method_error(const char *module_name,
-                    u32 line_number,
-                    const char *message,
-                    struct acpi_namespace_node *prefix_node,
-                    const char *path, acpi_status method_status)
-{
-       acpi_status status;
-       struct acpi_namespace_node *node = prefix_node;
-
-       ACPI_MSG_REDIRECT_BEGIN;
-       acpi_os_printf(ACPI_MSG_ERROR);
-
-       if (path) {
-               status =
-                   acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
-                                    &node);
-               if (ACPI_FAILURE(status)) {
-                       acpi_os_printf("[Could not get node by pathname]");
-               }
-       }
-
-       acpi_ns_print_node_pathname(node, message);
-       acpi_os_printf(", %s", acpi_format_exception(method_status));
-
-       ACPI_MSG_SUFFIX;
-       ACPI_MSG_REDIRECT_END;
-}
-
-#endif                         /* ACPI_NO_ERROR_MESSAGES */
index 8d457b55c55aafe0c27fa51ab0da644e93fd0486..fb57d03e698bd3b7ae2d4194d69dc3478ca09025 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/seq_file.h>
 #include <linux/nmi.h>
 #include <linux/delay.h>
+#include <linux/mm.h>
 #include <acpi/acpi.h>
 
 #include "apei-internal.h"
 #define SPIN_UNIT              100                     /* 100ns */
 /* Firmware should respond within 1 milliseconds */
 #define FIRMWARE_TIMEOUT       (1 * NSEC_PER_MSEC)
+#define ACPI5_VENDOR_BIT       BIT(31)
+#define MEM_ERROR_MASK         (ACPI_EINJ_MEMORY_CORRECTABLE | \
+                               ACPI_EINJ_MEMORY_UNCORRECTABLE | \
+                               ACPI_EINJ_MEMORY_FATAL)
 
 /*
  * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action.
@@ -367,7 +372,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
         * This will cause resource conflict with regular memory.  So
         * remove it from trigger table resources.
         */
-       if ((param_extension || acpi5) && (type & 0x0038) && param2) {
+       if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) {
                struct apei_resources addr_resources;
                apei_resources_init(&addr_resources);
                trigger_param_region = einj_get_trigger_parameter_region(
@@ -427,7 +432,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
                struct set_error_type_with_address *v5param = einj_param;
 
                v5param->type = type;
-               if (type & 0x80000000) {
+               if (type & ACPI5_VENDOR_BIT) {
                        switch (vendor_flags) {
                        case SETWA_FLAGS_APICID:
                                v5param->apicid = param1;
@@ -512,7 +517,34 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
 static int einj_error_inject(u32 type, u64 param1, u64 param2)
 {
        int rc;
+       unsigned long pfn;
 
+       /*
+        * We need extra sanity checks for memory errors.
+        * Other types leap directly to injection.
+        */
+
+       /* ensure param1/param2 existed */
+       if (!(param_extension || acpi5))
+               goto inject;
+
+       /* ensure injection is memory related */
+       if (type & ACPI5_VENDOR_BIT) {
+               if (vendor_flags != SETWA_FLAGS_MEM)
+                       goto inject;
+       } else if (!(type & MEM_ERROR_MASK))
+               goto inject;
+
+       /*
+        * Disallow crazy address masks that give BIOS leeway to pick
+        * injection address almost anywhere. Insist on page or
+        * better granularity and that target address is normal RAM.
+        */
+       pfn = PFN_DOWN(param1 & param2);
+       if (!page_is_ram(pfn) || ((param2 & PAGE_MASK) != PAGE_MASK))
+               return -EINVAL;
+
+inject:
        mutex_lock(&einj_mutex);
        rc = __einj_error_inject(type, param1, param2);
        mutex_unlock(&einj_mutex);
@@ -590,7 +622,7 @@ static int error_type_set(void *data, u64 val)
         * Vendor defined types have 0x80000000 bit set, and
         * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE
         */
-       vendor = val & 0x80000000;
+       vendor = val & ACPI5_VENDOR_BIT;
        tval = val & 0x7fffffff;
 
        /* Only one error type can be specified */
@@ -694,6 +726,7 @@ static int __init einj_init(void)
        if (rc)
                goto err_release;
 
+       rc = -ENOMEM;
        einj_param = einj_get_parameter_address();
        if ((param_extension || acpi5) && einj_param) {
                fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
index 6d894bfd8b8fe8d7aa8f22642a42aa26ce9a68eb..f7b3b39e94fc3b0bcf4e6d5e90e91652f2583990 100644 (file)
@@ -1180,20 +1180,28 @@ static int __init erst_init(void)
        if (!erst_erange.vaddr)
                goto err_release_erange;
 
+       pr_info(ERST_PFX
+       "Error Record Serialization Table (ERST) support is initialized.\n");
+
        buf = kmalloc(erst_erange.size, GFP_KERNEL);
        spin_lock_init(&erst_info.buf_lock);
        if (buf) {
                erst_info.buf = buf + sizeof(struct cper_pstore_record);
                erst_info.bufsize = erst_erange.size -
                                    sizeof(struct cper_pstore_record);
-               if (pstore_register(&erst_info)) {
-                       pr_info(ERST_PFX "Could not register with persistent store\n");
+               rc = pstore_register(&erst_info);
+               if (rc) {
+                       if (rc != -EPERM)
+                               pr_info(ERST_PFX
+                               "Could not register with persistent store\n");
+                       erst_info.buf = NULL;
+                       erst_info.bufsize = 0;
                        kfree(buf);
                }
-       }
-
-       pr_info(ERST_PFX
-       "Error Record Serialization Table (ERST) support is initialized.\n");
+       } else
+               pr_err(ERST_PFX
+               "Failed to allocate %lld bytes for persistent store error log\n",
+               erst_erange.size);
 
        return 0;
 
index fcd7d91cec34af25ed8ccfc32188a24b677c641b..ec9b57d428a1e028a0cdf3215e3ebddad9634818 100644 (file)
@@ -449,9 +449,19 @@ static void ghes_do_proc(struct ghes *ghes,
                            pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
                                unsigned int devfn;
                                int aer_severity;
+
                                devfn = PCI_DEVFN(pcie_err->device_id.device,
                                                  pcie_err->device_id.function);
                                aer_severity = cper_severity_to_aer(sev);
+
+                               /*
+                                * If firmware reset the component to contain
+                                * the error, we must reinitialize it before
+                                * use, so treat it as a fatal AER error.
+                                */
+                               if (gdata->flags & CPER_SEC_RESET)
+                                       aer_severity = AER_FATAL;
+
                                aer_recover_queue(pcie_err->device_id.segment,
                                                  pcie_err->device_id.bus,
                                                  devfn, aer_severity,
index e7100459ac4ad0ab8432e3912841fa0da2988245..082b4dd252a82ab17f7fe7249913e1f7030d35fd 100644 (file)
@@ -425,7 +425,7 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
 {
        int result = -EFAULT;
        acpi_status status = 0;
-       char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)?
+       char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags) ?
                        "_BIX" : "_BIF";
 
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -661,11 +661,11 @@ static void find_battery(const struct dmi_header *dm, void *private)
 static void acpi_battery_quirks(struct acpi_battery *battery)
 {
        if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
-               return ;
+               return;
 
-        if (battery->full_charge_capacity == 100 &&
-            battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
-            battery->capacity_now >=0 && battery->capacity_now <= 100) {
+       if (battery->full_charge_capacity == 100 &&
+               battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
+               battery->capacity_now >= 0 && battery->capacity_now <= 100) {
                set_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags);
                battery->full_charge_capacity = battery->design_capacity;
                battery->capacity_now = (battery->capacity_now *
@@ -673,7 +673,7 @@ static void acpi_battery_quirks(struct acpi_battery *battery)
        }
 
        if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags))
-               return ;
+               return;
 
        if (battery->power_unit && dmi_name_in_vendors("LENOVO")) {
                const char *s;
@@ -761,7 +761,7 @@ static int acpi_battery_print_info(struct seq_file *seq, int result)
                goto end;
 
        seq_printf(seq, "present:                 %s\n",
-                  acpi_battery_present(battery)?"yes":"no");
+                  acpi_battery_present(battery) ? "yes" : "no");
        if (!acpi_battery_present(battery))
                goto end;
        if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
@@ -817,12 +817,12 @@ static int acpi_battery_print_state(struct seq_file *seq, int result)
                goto end;
 
        seq_printf(seq, "present:                 %s\n",
-                  acpi_battery_present(battery)?"yes":"no");
+                  acpi_battery_present(battery) ? "yes" : "no");
        if (!acpi_battery_present(battery))
                goto end;
 
        seq_printf(seq, "capacity state:          %s\n",
-                       (battery->state & 0x04)?"critical":"ok");
+                       (battery->state & 0x04) ? "critical" : "ok");
        if ((battery->state & 0x01) && (battery->state & 0x02))
                seq_printf(seq,
                           "charging state:          charging/discharging\n");
index 292de3cab9cc0d4ac42cc551c80f3efdbdfeaf6b..a5bb33bab4485307f7969b19ff9d9ea9cb3f67e2 100644 (file)
@@ -91,8 +91,7 @@ static struct dmi_system_id dsdt_dmi_table[] __initdata = {
 
 int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
 {
-       acpi_status status = AE_OK;
-
+       acpi_status status;
 
        if (!device)
                return -EINVAL;
@@ -162,7 +161,7 @@ EXPORT_SYMBOL(acpi_bus_private_data_handler);
 
 int acpi_bus_get_private_data(acpi_handle handle, void **data)
 {
-       acpi_status status = AE_OK;
+       acpi_status status;
 
        if (!*data)
                return -EINVAL;
@@ -361,7 +360,7 @@ extern int event_is_open;
 int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
 {
        struct acpi_bus_event *event;
-       unsigned long flags = 0;
+       unsigned long flags;
 
        /* drop event on the floor if no one's listening */
        if (!event_is_open)
@@ -400,7 +399,7 @@ EXPORT_SYMBOL(acpi_bus_generate_proc_event);
 
 int acpi_bus_receive_event(struct acpi_bus_event *event)
 {
-       unsigned long flags = 0;
+       unsigned long flags;
        struct acpi_bus_event *entry = NULL;
 
        DECLARE_WAITQUEUE(wait, current);
@@ -593,7 +592,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
 
 static int __init acpi_bus_init_irq(void)
 {
-       acpi_status status = AE_OK;
+       acpi_status status;
        union acpi_object arg = { ACPI_TYPE_INTEGER };
        struct acpi_object_list arg_list = { 1, &arg };
        char *message = NULL;
@@ -640,7 +639,7 @@ u8 acpi_gbl_permanent_mmap;
 
 void __init acpi_early_init(void)
 {
-       acpi_status status = AE_OK;
+       acpi_status status;
 
        if (acpi_disabled)
                return;
@@ -714,8 +713,8 @@ void __init acpi_early_init(void)
 
 static int __init acpi_bus_init(void)
 {
-       int result = 0;
-       acpi_status status = AE_OK;
+       int result;
+       acpi_status status;
        extern acpi_status acpi_os_initialize1(void);
 
        acpi_os_initialize1();
index 31c217a42839dce40ee2039cd38f36d935bda543..e9e8bb24785b45e267b810fe8a7582ab22468d35 100644 (file)
@@ -419,62 +419,73 @@ bool acpi_bus_can_wakeup(acpi_handle handle)
 EXPORT_SYMBOL(acpi_bus_can_wakeup);
 
 /**
- * acpi_device_power_state - Get preferred power state of ACPI device.
+ * acpi_dev_pm_get_state - Get preferred power state of ACPI device.
  * @dev: Device whose preferred target power state to return.
  * @adev: ACPI device node corresponding to @dev.
  * @target_state: System state to match the resultant device state.
- * @d_max_in: Deepest low-power state to take into consideration.
- * @d_min_p: Location to store the upper limit of the allowed states range.
- * Return value: Preferred power state of the device on success, -ENODEV
- * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure
+ * @d_min_p: Location to store the highest power state available to the device.
+ * @d_max_p: Location to store the lowest power state available to the device.
  *
- * Find the lowest power (highest number) ACPI device power state that the
- * device can be in while the system is in the state represented by
- * @target_state.  If @d_min_p is set, the highest power (lowest number) device
- * power state that @dev can be in for the given system sleep state is stored
- * at the location pointed to by it.
+ * Find the lowest power (highest number) and highest power (lowest number) ACPI
+ * device power states that the device can be in while the system is in the
+ * state represented by @target_state.  Store the integer numbers representing
+ * those stats in the memory locations pointed to by @d_max_p and @d_min_p,
+ * respectively.
  *
  * Callers must ensure that @dev and @adev are valid pointers and that @adev
  * actually corresponds to @dev before using this function.
+ *
+ * Returns 0 on success or -ENODATA when one of the ACPI methods fails or
+ * returns a value that doesn't make sense.  The memory locations pointed to by
+ * @d_max_p and @d_min_p are only modified on success.
  */
-int acpi_device_power_state(struct device *dev, struct acpi_device *adev,
-                           u32 target_state, int d_max_in, int *d_min_p)
+static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
+                                u32 target_state, int *d_min_p, int *d_max_p)
 {
-       char acpi_method[] = "_SxD";
-       unsigned long long d_min, d_max;
+       char method[] = { '_', 'S', '0' + target_state, 'D', '\0' };
+       acpi_handle handle = adev->handle;
+       unsigned long long ret;
+       int d_min, d_max;
        bool wakeup = false;
+       acpi_status status;
 
-       if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3)
-               return -EINVAL;
-
-       if (d_max_in > ACPI_STATE_D3_HOT) {
-               enum pm_qos_flags_status stat;
-
-               stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF);
-               if (stat == PM_QOS_FLAGS_ALL)
-                       d_max_in = ACPI_STATE_D3_HOT;
-       }
-
-       acpi_method[2] = '0' + target_state;
        /*
-        * If the sleep state is S0, the lowest limit from ACPI is D3,
-        * but if the device has _S0W, we will use the value from _S0W
-        * as the lowest limit from ACPI.  Finally, we will constrain
-        * the lowest limit with the specified one.
+        * If the system state is S0, the lowest power state the device can be
+        * in is D3cold, unless the device has _S0W and is supposed to signal
+        * wakeup, in which case the return value of _S0W has to be used as the
+        * lowest power state available to the device.
         */
        d_min = ACPI_STATE_D0;
-       d_max = ACPI_STATE_D3;
+       d_max = ACPI_STATE_D3_COLD;
 
        /*
         * If present, _SxD methods return the minimum D-state (highest power
         * state) we can use for the corresponding S-states.  Otherwise, the
         * minimum D-state is D0 (ACPI 3.x).
-        *
-        * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer
-        * provided -- that's our fault recovery, we ignore retval.
         */
        if (target_state > ACPI_STATE_S0) {
-               acpi_evaluate_integer(adev->handle, acpi_method, NULL, &d_min);
+               /*
+                * We rely on acpi_evaluate_integer() not clobbering the integer
+                * provided if AE_NOT_FOUND is returned.
+                */
+               ret = d_min;
+               status = acpi_evaluate_integer(handle, method, NULL, &ret);
+               if ((ACPI_FAILURE(status) && status != AE_NOT_FOUND)
+                   || ret > ACPI_STATE_D3_COLD)
+                       return -ENODATA;
+
+               /*
+                * We need to handle legacy systems where D3hot and D3cold are
+                * the same and 3 is returned in both cases, so fall back to
+                * D3cold if D3hot is not a valid state.
+                */
+               if (!adev->power.states[ret].flags.valid) {
+                       if (ret == ACPI_STATE_D3_HOT)
+                               ret = ACPI_STATE_D3_COLD;
+                       else
+                               return -ENODATA;
+               }
+               d_min = ret;
                wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid
                        && adev->wakeup.sleep_state >= target_state;
        } else if (dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) !=
@@ -490,38 +501,30 @@ int acpi_device_power_state(struct device *dev, struct acpi_device *adev,
         * can wake the system.  _S0W may be valid, too.
         */
        if (wakeup) {
-               acpi_status status;
-
-               acpi_method[3] = 'W';
-               status = acpi_evaluate_integer(adev->handle, acpi_method, NULL,
-                                               &d_max);
-               if (ACPI_FAILURE(status)) {
-                       if (target_state != ACPI_STATE_S0 ||
-                           status != AE_NOT_FOUND)
+               method[3] = 'W';
+               status = acpi_evaluate_integer(handle, method, NULL, &ret);
+               if (status == AE_NOT_FOUND) {
+                       if (target_state > ACPI_STATE_S0)
                                d_max = d_min;
-               } else if (d_max < d_min) {
-                       /* Warn the user of the broken DSDT */
-                       printk(KERN_WARNING "ACPI: Wrong value from %s\n",
-                               acpi_method);
-                       /* Sanitize it */
-                       d_min = d_max;
+               } else if (ACPI_SUCCESS(status) && ret <= ACPI_STATE_D3_COLD) {
+                       /* Fall back to D3cold if ret is not a valid state. */
+                       if (!adev->power.states[ret].flags.valid)
+                               ret = ACPI_STATE_D3_COLD;
+
+                       d_max = ret > d_min ? ret : d_min;
+               } else {
+                       return -ENODATA;
                }
        }
 
-       if (d_max_in < d_min)
-               return -EINVAL;
        if (d_min_p)
                *d_min_p = d_min;
-       /* constrain d_max with specified lowest limit (max number) */
-       if (d_max > d_max_in) {
-               for (d_max = d_max_in; d_max > d_min; d_max--) {
-                       if (adev->power.states[d_max].flags.valid)
-                               break;
-               }
-       }
-       return d_max;
+
+       if (d_max_p)
+               *d_max_p = d_max;
+
+       return 0;
 }
-EXPORT_SYMBOL_GPL(acpi_device_power_state);
 
 /**
  * acpi_pm_device_sleep_state - Get preferred power state of ACPI device.
@@ -529,7 +532,8 @@ EXPORT_SYMBOL_GPL(acpi_device_power_state);
  * @d_min_p: Location to store the upper limit of the allowed states range.
  * @d_max_in: Deepest low-power state to take into consideration.
  * Return value: Preferred power state of the device on success, -ENODEV
- * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure
+ * if there's no 'struct acpi_device' for @dev, -EINVAL if @d_max_in is
+ * incorrect, or -ENODATA on ACPI method failure.
  *
  * The caller must ensure that @dev is valid before using this function.
  */
@@ -537,14 +541,43 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in)
 {
        acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
        struct acpi_device *adev;
+       int ret, d_min, d_max;
+
+       if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3_COLD)
+               return -EINVAL;
+
+       if (d_max_in > ACPI_STATE_D3_HOT) {
+               enum pm_qos_flags_status stat;
+
+               stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF);
+               if (stat == PM_QOS_FLAGS_ALL)
+                       d_max_in = ACPI_STATE_D3_HOT;
+       }
 
        if (!handle || acpi_bus_get_device(handle, &adev)) {
                dev_dbg(dev, "ACPI handle without context in %s!\n", __func__);
                return -ENODEV;
        }
 
-       return acpi_device_power_state(dev, adev, acpi_target_system_state(),
-                                      d_max_in, d_min_p);
+       ret = acpi_dev_pm_get_state(dev, adev, acpi_target_system_state(),
+                                   &d_min, &d_max);
+       if (ret)
+               return ret;
+
+       if (d_max_in < d_min)
+               return -EINVAL;
+
+       if (d_max > d_max_in) {
+               for (d_max = d_max_in; d_max > d_min; d_max--) {
+                       if (adev->power.states[d_max].flags.valid)
+                               break;
+               }
+       }
+
+       if (d_min_p)
+               *d_min_p = d_min;
+
+       return d_max;
 }
 EXPORT_SYMBOL(acpi_pm_device_sleep_state);
 
@@ -695,17 +728,13 @@ struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
 static int acpi_dev_pm_low_power(struct device *dev, struct acpi_device *adev,
                                 u32 system_state)
 {
-       int power_state;
+       int ret, state;
 
        if (!acpi_device_power_manageable(adev))
                return 0;
 
-       power_state = acpi_device_power_state(dev, adev, system_state,
-                                             ACPI_STATE_D3, NULL);
-       if (power_state < ACPI_STATE_D0 || power_state > ACPI_STATE_D3)
-               return -EIO;
-
-       return acpi_device_set_power(adev, power_state);
+       ret = acpi_dev_pm_get_state(dev, adev, system_state, NULL, &state);
+       return ret ? ret : acpi_device_set_power(adev, state);
 }
 
 /**
@@ -908,7 +937,6 @@ static struct dev_pm_domain acpi_general_pm_domain = {
 #ifdef CONFIG_PM_RUNTIME
                .runtime_suspend = acpi_subsys_runtime_suspend,
                .runtime_resume = acpi_subsys_runtime_resume,
-               .runtime_idle = pm_generic_runtime_idle,
 #endif
 #ifdef CONFIG_PM_SLEEP
                .prepare = acpi_subsys_prepare,
index edc00818c80321086ff3938f5df3cf2afae04d61..80403c1a89f8969919c868e0fb3238e056adb581 100644 (file)
@@ -983,6 +983,10 @@ static struct dmi_system_id __initdata ec_dmi_table[] = {
        ec_enlarge_storm_threshold, "CLEVO hardware", {
        DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."),
        DMI_MATCH(DMI_PRODUCT_NAME, "M720T/M730T"),}, NULL},
+       {
+       ec_skip_dsdt_scan, "HP Folio 13", {
+       DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+       DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13"),}, NULL},
        {},
 };
 
index 7586544fddb41b9cc1761a294dc57f79245d6286..4e7b798900f21df7bf60c75d2132e2ad86e89e38 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/acpi.h>
 #include <linux/debugfs.h>
 #include <linux/module.h>
+#include <linux/uaccess.h>
 #include "internal.h"
 
 MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
@@ -34,7 +35,6 @@ static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
         * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
         */
        unsigned int size = EC_SPACE_SIZE;
-       u8 *data = (u8 *) buf;
        loff_t init_off = *off;
        int err = 0;
 
@@ -47,9 +47,15 @@ static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
                size = count;
 
        while (size) {
-               err = ec_read(*off, &data[*off - init_off]);
+               u8 byte_read;
+               err = ec_read(*off, &byte_read);
                if (err)
                        return err;
+               if (put_user(byte_read, buf + *off - init_off)) {
+                       if (*off - init_off)
+                               return *off - init_off; /* partial read */
+                       return -EFAULT;
+               }
                *off += 1;
                size--;
        }
@@ -65,7 +71,6 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
 
        unsigned int size = count;
        loff_t init_off = *off;
-       u8 *data = (u8 *) buf;
        int err = 0;
 
        if (*off >= EC_SPACE_SIZE)
@@ -76,7 +81,12 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
        }
 
        while (size) {
-               u8 byte_write = data[*off - init_off];
+               u8 byte_write;
+               if (get_user(byte_write, buf + *off - init_off)) {
+                       if (*off - init_off)
+                               return *off - init_off; /* partial write */
+                       return -EFAULT;
+               }
                err = ec_write(*off, byte_write);
                if (err)
                        return err;
index 40a84cc6740c6c6522afc6bac6d5d5d2178a86bd..f68095756fb7465bc034ca5335f9345a806dd97d 100644 (file)
@@ -81,13 +81,15 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
 static acpi_status do_acpi_find_child(acpi_handle handle, u32 lvl_not_used,
                                      void *addr_p, void **ret_p)
 {
-       unsigned long long addr;
+       unsigned long long addr, sta;
        acpi_status status;
 
        status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
        if (ACPI_SUCCESS(status) && addr == *((u64 *)addr_p)) {
                *ret_p = handle;
-               return AE_CTRL_TERMINATE;
+               status = acpi_bus_get_status_handle(handle, &sta);
+               if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_ENABLED))
+                       return AE_CTRL_TERMINATE;
        }
        return AE_OK;
 }
@@ -105,7 +107,7 @@ acpi_handle acpi_get_child(acpi_handle parent, u64 address)
 }
 EXPORT_SYMBOL(acpi_get_child);
 
-static int acpi_bind_one(struct device *dev, acpi_handle handle)
+int acpi_bind_one(struct device *dev, acpi_handle handle)
 {
        struct acpi_device *acpi_dev;
        acpi_status status;
@@ -188,8 +190,9 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
        kfree(physical_node);
        goto err;
 }
+EXPORT_SYMBOL_GPL(acpi_bind_one);
 
-static int acpi_unbind_one(struct device *dev)
+int acpi_unbind_one(struct device *dev)
 {
        struct acpi_device_physical_node *entry;
        struct acpi_device *acpi_dev;
@@ -238,6 +241,7 @@ err:
        dev_err(dev, "Oops, 'acpi_handle' corrupt\n");
        return -EINVAL;
 }
+EXPORT_SYMBOL_GPL(acpi_unbind_one);
 
 static int acpi_platform_notify(struct device *dev)
 {
index c610a76d92c4b4bdf5deafae76252110460d5ed2..3a50a34fe176b34bb77a3ff8cfff9588fe523da8 100644 (file)
@@ -33,6 +33,7 @@ static inline void acpi_pci_slot_init(void) { }
 void acpi_pci_root_init(void);
 void acpi_pci_link_init(void);
 void acpi_pci_root_hp_init(void);
+void acpi_processor_init(void);
 void acpi_platform_init(void);
 int acpi_sysfs_init(void);
 #ifdef CONFIG_ACPI_CONTAINER
@@ -50,6 +51,13 @@ void acpi_memory_hotplug_init(void);
 #else
 static inline void acpi_memory_hotplug_init(void) {}
 #endif
+#ifdef CONFIG_X86
+void acpi_cmos_rtc_init(void);
+#else
+static inline void acpi_cmos_rtc_init(void) {}
+#endif
+
+extern bool acpi_force_hot_remove;
 
 void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
                                    const char *name);
@@ -81,6 +89,8 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
                             int type, unsigned long long sta);
 void acpi_device_add_finalize(struct acpi_device *device);
 void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
+int acpi_bind_one(struct device *dev, acpi_handle handle);
+int acpi_unbind_one(struct device *dev);
 
 /* --------------------------------------------------------------------------
                                   Power Resource
index e72186340fec50212f5da151a1e7137dde31d019..6ab2c350552061893ded7355d376406de5d98ed8 100644 (file)
@@ -835,19 +835,9 @@ void acpi_os_stall(u32 us)
  */
 u64 acpi_os_get_timer(void)
 {
-       static u64 t;
-
-#ifdef CONFIG_HPET
-       /* TBD: use HPET if available */
-#endif
-
-#ifdef CONFIG_X86_PM_TIMER
-       /* TBD: default to PM timer if HPET was not available */
-#endif
-       if (!t)
-               printk(KERN_ERR PREFIX "acpi_os_get_timer() TBD\n");
-
-       return ++t;
+       u64 time_ns = ktime_to_ns(ktime_get());
+       do_div(time_ns, 100);
+       return time_ns;
 }
 
 acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
@@ -1715,6 +1705,17 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
 }
 #endif
 
+static int __init acpi_no_auto_ssdt_setup(char *s)
+{
+        printk(KERN_NOTICE PREFIX "SSDT auto-load disabled\n");
+
+        acpi_gbl_disable_ssdt_table_load = TRUE;
+
+        return 1;
+}
+
+__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
+
 acpi_status __init acpi_os_initialize(void)
 {
        acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
index e427dc516c76d1d8d73b5a91c7d4f1f73b83cfbf..5917839321b8bb01254f57e0cde630f637ff76b2 100644 (file)
@@ -65,10 +65,6 @@ static struct acpi_scan_handler pci_root_handler = {
        .detach = acpi_pci_root_remove,
 };
 
-/* Lock to protect both acpi_pci_roots lists */
-static DEFINE_MUTEX(acpi_pci_root_lock);
-static LIST_HEAD(acpi_pci_roots);
-
 static DEFINE_MUTEX(osc_lock);
 
 /**
@@ -100,13 +96,12 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
 {
        struct resource *res = data;
        struct acpi_resource_address64 address;
+       acpi_status status;
 
-       if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
-           resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
-           resource->type != ACPI_RESOURCE_TYPE_ADDRESS64)
+       status = acpi_resource_to_address64(resource, &address);
+       if (ACPI_FAILURE(status))
                return AE_OK;
 
-       acpi_resource_to_address64(resource, &address);
        if ((address.address_length > 0) &&
            (address.resource_type == ACPI_BUS_NUMBER_RANGE)) {
                res->start = address.minimum;
@@ -382,23 +377,24 @@ static int acpi_pci_root_add(struct acpi_device *device,
        int result;
        struct acpi_pci_root *root;
        u32 flags, base_flags;
+       acpi_handle handle = device->handle;
 
        root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
        if (!root)
                return -ENOMEM;
 
        segment = 0;
-       status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
+       status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL,
                                       &segment);
        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-               printk(KERN_ERR PREFIX "can't evaluate _SEG\n");
+               dev_err(&device->dev,  "can't evaluate _SEG\n");
                result = -ENODEV;
                goto end;
        }
 
        /* Check _CRS first, then _BBN.  If no _BBN, default to zero. */
        root->secondary.flags = IORESOURCE_BUS;
-       status = try_get_root_bridge_busnr(device->handle, &root->secondary);
+       status = try_get_root_bridge_busnr(handle, &root->secondary);
        if (ACPI_FAILURE(status)) {
                /*
                 * We need both the start and end of the downstream bus range
@@ -407,33 +403,32 @@ static int acpi_pci_root_add(struct acpi_device *device,
                 * can do is assume [_BBN-0xFF] or [0-0xFF].
                 */
                root->secondary.end = 0xFF;
-               printk(KERN_WARNING FW_BUG PREFIX
-                      "no secondary bus range in _CRS\n");
-               status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN,
+               dev_warn(&device->dev,
+                        FW_BUG "no secondary bus range in _CRS\n");
+               status = acpi_evaluate_integer(handle, METHOD_NAME__BBN,
                                               NULL, &bus);
                if (ACPI_SUCCESS(status))
                        root->secondary.start = bus;
                else if (status == AE_NOT_FOUND)
                        root->secondary.start = 0;
                else {
-                       printk(KERN_ERR PREFIX "can't evaluate _BBN\n");
+                       dev_err(&device->dev, "can't evaluate _BBN\n");
                        result = -ENODEV;
                        goto end;
                }
        }
 
-       INIT_LIST_HEAD(&root->node);
        root->device = device;
        root->segment = segment & 0xFFFF;
        strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
        device->driver_data = root;
 
-       printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n",
+       pr_info(PREFIX "%s [%s] (domain %04x %pR)\n",
               acpi_device_name(device), acpi_device_bid(device),
               root->segment, &root->secondary);
 
-       root->mcfg_addr = acpi_pci_root_get_mcfg_addr(device->handle);
+       root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle);
 
        /*
         * All supported architectures that use ACPI have support for
@@ -446,10 +441,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
         * TBD: Need PCI interface for enumeration/configuration of roots.
         */
 
-       mutex_lock(&acpi_pci_root_lock);
-       list_add_tail(&root->node, &acpi_pci_roots);
-       mutex_unlock(&acpi_pci_root_lock);
-
        /*
         * Scan the Root Bridge
         * --------------------
@@ -459,11 +450,11 @@ static int acpi_pci_root_add(struct acpi_device *device,
         */
        root->bus = pci_acpi_scan_root(root);
        if (!root->bus) {
-               printk(KERN_ERR PREFIX
-                           "Bus %04x:%02x not present in PCI namespace\n",
-                           root->segment, (unsigned int)root->secondary.start);
+               dev_err(&device->dev,
+                       "Bus %04x:%02x not present in PCI namespace\n",
+                       root->segment, (unsigned int)root->secondary.start);
                result = -ENODEV;
-               goto out_del_root;
+               goto end;
        }
 
        /* Indicate support for various _OSC capabilities. */
@@ -502,7 +493,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
                dev_info(&device->dev,
                        "Requesting ACPI _OSC control (0x%02x)\n", flags);
 
-               status = acpi_pci_osc_control_set(device->handle, &flags,
+               status = acpi_pci_osc_control_set(handle, &flags,
                                       OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
                if (ACPI_SUCCESS(status)) {
                        dev_info(&device->dev,
@@ -519,8 +510,8 @@ static int acpi_pci_root_add(struct acpi_device *device,
                                "ACPI _OSC request failed (%s), "
                                "returned control mask: 0x%02x\n",
                                acpi_format_exception(status), flags);
-                       pr_info("ACPI _OSC control for PCIe not granted, "
-                               "disabling ASPM\n");
+                       dev_info(&device->dev,
+                                "ACPI _OSC control for PCIe not granted, disabling ASPM\n");
                        pcie_no_aspm();
                }
        } else {
@@ -536,20 +527,14 @@ static int acpi_pci_root_add(struct acpi_device *device,
        if (system_state != SYSTEM_BOOTING) {
                pcibios_resource_survey_bus(root->bus);
                pci_assign_unassigned_bus_resources(root->bus);
-       }
 
-       /* need to after hot-added ioapic is registered */
-       if (system_state != SYSTEM_BOOTING)
+               /* need to after hot-added ioapic is registered */
                pci_enable_bridges(root->bus);
+       }
 
        pci_bus_add_devices(root->bus);
        return 1;
 
-out_del_root:
-       mutex_lock(&acpi_pci_root_lock);
-       list_del(&root->node);
-       mutex_unlock(&acpi_pci_root_lock);
-
 end:
        kfree(root);
        return result;
@@ -566,9 +551,6 @@ static void acpi_pci_root_remove(struct acpi_device *device)
 
        pci_remove_root_bus(root->bus);
 
-       mutex_lock(&acpi_pci_root_lock);
-       list_del(&root->node);
-       mutex_unlock(&acpi_pci_root_lock);
        kfree(root);
 }
 
@@ -588,12 +570,13 @@ static void handle_root_bridge_insertion(acpi_handle handle)
        struct acpi_device *device;
 
        if (!acpi_bus_get_device(handle, &device)) {
-               printk(KERN_DEBUG "acpi device exists...\n");
+               dev_printk(KERN_DEBUG, &device->dev,
+                          "acpi device already exists; ignoring notify\n");
                return;
        }
 
        if (acpi_bus_scan(handle))
-               printk(KERN_ERR "cannot add bridge to acpi list\n");
+               acpi_handle_err(handle, "cannot add bridge to acpi list\n");
 }
 
 static void handle_root_bridge_removal(struct acpi_device *device)
@@ -622,7 +605,6 @@ static void handle_root_bridge_removal(struct acpi_device *device)
 static void _handle_hotplug_event_root(struct work_struct *work)
 {
        struct acpi_pci_root *root;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };
        struct acpi_hp_work *hp_work;
        acpi_handle handle;
        u32 type;
@@ -634,13 +616,12 @@ static void _handle_hotplug_event_root(struct work_struct *work)
        acpi_scan_lock_acquire();
 
        root = acpi_pci_find_root(handle);
-       acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
        switch (type) {
        case ACPI_NOTIFY_BUS_CHECK:
                /* bus enumerate */
-               printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__,
-                                (char *)buffer.pointer);
+               acpi_handle_printk(KERN_DEBUG, handle,
+                                  "Bus check notify on %s\n", __func__);
                if (root)
                        acpiphp_check_host_bridge(handle);
                else
@@ -650,28 +631,28 @@ static void _handle_hotplug_event_root(struct work_struct *work)
 
        case ACPI_NOTIFY_DEVICE_CHECK:
                /* device check */
-               printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__,
-                                (char *)buffer.pointer);
+               acpi_handle_printk(KERN_DEBUG, handle,
+                                  "Device check notify on %s\n", __func__);
                if (!root)
                        handle_root_bridge_insertion(handle);
                break;
 
        case ACPI_NOTIFY_EJECT_REQUEST:
                /* request device eject */
-               printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__,
-                                (char *)buffer.pointer);
+               acpi_handle_printk(KERN_DEBUG, handle,
+                                  "Device eject notify on %s\n", __func__);
                if (root)
                        handle_root_bridge_removal(root->device);
                break;
        default:
-               printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n",
-                                type, (char *)buffer.pointer);
+               acpi_handle_warn(handle,
+                                "notify_handler: unknown event type 0x%x\n",
+                                type);
                break;
        }
 
        acpi_scan_lock_release();
        kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
-       kfree(buffer.pointer);
 }
 
 static void handle_hotplug_event_root(acpi_handle handle, u32 type,
@@ -685,9 +666,6 @@ static acpi_status __init
 find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        acpi_status status;
-       char objname[64];
-       struct acpi_buffer buffer = { .length = sizeof(objname),
-                                     .pointer = objname };
        int *count = (int *)context;
 
        if (!acpi_is_root_bridge(handle))
@@ -695,16 +673,15 @@ find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
 
        (*count)++;
 
-       acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
        status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
                                        handle_hotplug_event_root, NULL);
        if (ACPI_FAILURE(status))
-               printk(KERN_DEBUG "acpi root: %s notify handler is not installed, exit status: %u\n",
-                                 objname, (unsigned int)status);
+               acpi_handle_printk(KERN_DEBUG, handle,
+                       "notify handler is not installed, exit status: %u\n",
+                        (unsigned int)status);
        else
-               printk(KERN_DEBUG "acpi root: %s notify handler is installed\n",
-                                objname);
+               acpi_handle_printk(KERN_DEBUG, handle,
+                                  "notify handler is installed\n");
 
        return AE_OK;
 }
index c266cdc117840bcdfc7909c2605840501b2c87c2..823be116619e9d802ed2ca7cc9fc2f1c924b5119 100644 (file)
@@ -1,11 +1,13 @@
 /*
- * acpi_processor.c - ACPI Processor Driver ($Revision: 71 $)
+ * processor_driver.c - ACPI Processor Driver
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
  *  Copyright (C) 2004       Dominik Brodowski <linux@brodo.de>
  *  Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
  *                     - Added processor hotplug support
+ *  Copyright (C) 2013, Intel Corporation
+ *                      Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *  TBD:
- *     1. Make # power states dynamic.
- *     2. Support duty_cycle values that span bit 4.
- *     3. Optimize by having scheduler determine business instead of
- *        having us try to calculate it here.
- *     4. Need C1 timing -- must modify kernel (IRQ handler) to get this.
  */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/pm.h>
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
-#include <linux/dmi.h>
-#include <linux/moduleparam.h>
 #include <linux/cpuidle.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
-#include <linux/memory_hotplug.h>
-
-#include <asm/io.h>
-#include <asm/cpu.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-#include <asm/smp.h>
-#include <asm/acpi.h>
-
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
+
 #include <acpi/processor.h>
 
+#include "internal.h"
+
 #define PREFIX "ACPI: "
 
-#define ACPI_PROCESSOR_CLASS           "processor"
-#define ACPI_PROCESSOR_DEVICE_NAME     "Processor"
-#define ACPI_PROCESSOR_FILE_INFO       "info"
-#define ACPI_PROCESSOR_FILE_THROTTLING "throttling"
-#define ACPI_PROCESSOR_FILE_LIMIT      "limit"
 #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
 #define ACPI_PROCESSOR_NOTIFY_POWER    0x81
 #define ACPI_PROCESSOR_NOTIFY_THROTTLING       0x82
-#define ACPI_PROCESSOR_DEVICE_HID      "ACPI0007"
-
-#define ACPI_PROCESSOR_LIMIT_USER      0
-#define ACPI_PROCESSOR_LIMIT_THERMAL   1
 
 #define _COMPONENT             ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_driver");
@@ -81,12 +54,8 @@ MODULE_AUTHOR("Paul Diefenbaugh");
 MODULE_DESCRIPTION("ACPI Processor Driver");
 MODULE_LICENSE("GPL");
 
-static int acpi_processor_add(struct acpi_device *device);
-static int acpi_processor_remove(struct acpi_device *device);
-static void acpi_processor_notify(struct acpi_device *device, u32 event);
-static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr);
-static int acpi_processor_handle_eject(struct acpi_processor *pr);
-static int acpi_processor_start(struct acpi_processor *pr);
+static int acpi_processor_start(struct device *dev);
+static int acpi_processor_stop(struct device *dev);
 
 static const struct acpi_device_id processor_device_ids[] = {
        {ACPI_PROCESSOR_OBJECT_HID, 0},
@@ -95,295 +64,24 @@ static const struct acpi_device_id processor_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, processor_device_ids);
 
-static struct acpi_driver acpi_processor_driver = {
+static struct device_driver acpi_processor_driver = {
        .name = "processor",
-       .class = ACPI_PROCESSOR_CLASS,
-       .ids = processor_device_ids,
-       .ops = {
-               .add = acpi_processor_add,
-               .remove = acpi_processor_remove,
-               .notify = acpi_processor_notify,
-               },
+       .bus = &cpu_subsys,
+       .acpi_match_table = processor_device_ids,
+       .probe = acpi_processor_start,
+       .remove = acpi_processor_stop,
 };
 
-#define INSTALL_NOTIFY_HANDLER         1
-#define UNINSTALL_NOTIFY_HANDLER       2
-
-DEFINE_PER_CPU(struct acpi_processor *, processors);
-EXPORT_PER_CPU_SYMBOL(processors);
-
-struct acpi_processor_errata errata __read_mostly;
-
-/* --------------------------------------------------------------------------
-                                Errata Handling
-   -------------------------------------------------------------------------- */
-
-static int acpi_processor_errata_piix4(struct pci_dev *dev)
-{
-       u8 value1 = 0;
-       u8 value2 = 0;
-
-
-       if (!dev)
-               return -EINVAL;
-
-       /*
-        * Note that 'dev' references the PIIX4 ACPI Controller.
-        */
-
-       switch (dev->revision) {
-       case 0:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
-               break;
-       case 1:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n"));
-               break;
-       case 2:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n"));
-               break;
-       case 3:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n"));
-               break;
-       default:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n"));
-               break;
-       }
-
-       switch (dev->revision) {
-
-       case 0:         /* PIIX4 A-step */
-       case 1:         /* PIIX4 B-step */
-               /*
-                * See specification changes #13 ("Manual Throttle Duty Cycle")
-                * and #14 ("Enabling and Disabling Manual Throttle"), plus
-                * erratum #5 ("STPCLK# Deassertion Time") from the January
-                * 2002 PIIX4 specification update.  Applies to only older
-                * PIIX4 models.
-                */
-               errata.piix4.throttle = 1;
-
-       case 2:         /* PIIX4E */
-       case 3:         /* PIIX4M */
-               /*
-                * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
-                * Livelock") from the January 2002 PIIX4 specification update.
-                * Applies to all PIIX4 models.
-                */
-
-               /*
-                * BM-IDE
-                * ------
-                * Find the PIIX4 IDE Controller and get the Bus Master IDE
-                * Status register address.  We'll use this later to read
-                * each IDE controller's DMA status to make sure we catch all
-                * DMA activity.
-                */
-               dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
-                                    PCI_DEVICE_ID_INTEL_82371AB,
-                                    PCI_ANY_ID, PCI_ANY_ID, NULL);
-               if (dev) {
-                       errata.piix4.bmisx = pci_resource_start(dev, 4);
-                       pci_dev_put(dev);
-               }
-
-               /*
-                * Type-F DMA
-                * ----------
-                * Find the PIIX4 ISA Controller and read the Motherboard
-                * DMA controller's status to see if Type-F (Fast) DMA mode
-                * is enabled (bit 7) on either channel.  Note that we'll
-                * disable C3 support if this is enabled, as some legacy
-                * devices won't operate well if fast DMA is disabled.
-                */
-               dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
-                                    PCI_DEVICE_ID_INTEL_82371AB_0,
-                                    PCI_ANY_ID, PCI_ANY_ID, NULL);
-               if (dev) {
-                       pci_read_config_byte(dev, 0x76, &value1);
-                       pci_read_config_byte(dev, 0x77, &value2);
-                       if ((value1 & 0x80) || (value2 & 0x80))
-                               errata.piix4.fdma = 1;
-                       pci_dev_put(dev);
-               }
-
-               break;
-       }
-
-       if (errata.piix4.bmisx)
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Bus master activity detection (BM-IDE) erratum enabled\n"));
-       if (errata.piix4.fdma)
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Type-F DMA livelock erratum (C3 disabled)\n"));
-
-       return 0;
-}
-
-static int acpi_processor_errata(struct acpi_processor *pr)
+static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
 {
-       int result = 0;
-       struct pci_dev *dev = NULL;
-
-
-       if (!pr)
-               return -EINVAL;
-
-       /*
-        * PIIX4
-        */
-       dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
-                            PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID,
-                            PCI_ANY_ID, NULL);
-       if (dev) {
-               result = acpi_processor_errata_piix4(dev);
-               pci_dev_put(dev);
-       }
-
-       return result;
-}
-
-/* --------------------------------------------------------------------------
-                                 Driver Interface
-   -------------------------------------------------------------------------- */
-
-static int acpi_processor_get_info(struct acpi_device *device)
-{
-       acpi_status status = 0;
-       union acpi_object object = { 0 };
-       struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
+       struct acpi_device *device = data;
        struct acpi_processor *pr;
-       int cpu_index, device_declaration = 0;
-       static int cpu0_initialized;
-
-       pr = acpi_driver_data(device);
-       if (!pr)
-               return -EINVAL;
-
-       if (num_online_cpus() > 1)
-               errata.smp = TRUE;
-
-       acpi_processor_errata(pr);
-
-       /*
-        * Check to see if we have bus mastering arbitration control.  This
-        * is required for proper C3 usage (to maintain cache coherency).
-        */
-       if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
-               pr->flags.bm_control = 1;
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Bus mastering arbitration control present\n"));
-       } else
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "No bus mastering arbitration control\n"));
-
-       if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) {
-               /* Declared with "Processor" statement; match ProcessorID */
-               status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
-               if (ACPI_FAILURE(status)) {
-                       dev_err(&device->dev,
-                               "Failed to evaluate processor object (0x%x)\n",
-                               status);
-                       return -ENODEV;
-               }
-
-               /*
-                * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
-                *      >>> 'acpi_get_processor_id(acpi_id, &id)' in
-                *      arch/xxx/acpi.c
-                */
-               pr->acpi_id = object.processor.proc_id;
-       } else {
-               /*
-                * Declared with "Device" statement; match _UID.
-                * Note that we don't handle string _UIDs yet.
-                */
-               unsigned long long value;
-               status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
-                                               NULL, &value);
-               if (ACPI_FAILURE(status)) {
-                       dev_err(&device->dev,
-                               "Failed to evaluate processor _UID (0x%x)\n",
-                               status);
-                       return -ENODEV;
-               }
-               device_declaration = 1;
-               pr->acpi_id = value;
-       }
-       cpu_index = acpi_get_cpuid(pr->handle, device_declaration, pr->acpi_id);
-
-       /* Handle UP system running SMP kernel, with no LAPIC in MADT */
-       if (!cpu0_initialized && (cpu_index == -1) &&
-           (num_online_cpus() == 1)) {
-               cpu_index = 0;
-       }
-
-       cpu0_initialized = 1;
-
-       pr->id = cpu_index;
-
-       /*
-        *  Extra Processor objects may be enumerated on MP systems with
-        *  less than the max # of CPUs. They should be ignored _iff
-        *  they are physically not present.
-        */
-       if (pr->id == -1) {
-               if (ACPI_FAILURE(acpi_processor_hotadd_init(pr)))
-                       return -ENODEV;
-       }
-       /*
-        * On some boxes several processors use the same processor bus id.
-        * But they are located in different scope. For example:
-        * \_SB.SCK0.CPU0
-        * \_SB.SCK1.CPU0
-        * Rename the processor device bus id. And the new bus id will be
-        * generated as the following format:
-        * CPU+CPU ID.
-        */
-       sprintf(acpi_device_bid(device), "CPU%X", pr->id);
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
-                         pr->acpi_id));
-
-       if (!object.processor.pblk_address)
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
-       else if (object.processor.pblk_length != 6)
-               dev_err(&device->dev, "Invalid PBLK length [%d]\n",
-                           object.processor.pblk_length);
-       else {
-               pr->throttling.address = object.processor.pblk_address;
-               pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
-               pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
-
-               pr->pblk = object.processor.pblk_address;
-
-               /*
-                * We don't care about error returns - we just try to mark
-                * these reserved so that nobody else is confused into thinking
-                * that this region might be unused..
-                *
-                * (In particular, allocating the IO range for Cardbus)
-                */
-               request_region(pr->throttling.address, 6, "ACPI CPU throttle");
-       }
-
-       /*
-        * If ACPI describes a slot number for this CPU, we can use it
-        * ensure we get the right value in the "physical id" field
-        * of /proc/cpuinfo
-        */
-       status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer);
-       if (ACPI_SUCCESS(status))
-               arch_fix_phys_package_id(pr->id, object.integer.value);
-
-       return 0;
-}
-
-static DEFINE_PER_CPU(void *, processor_device_array);
-
-static void acpi_processor_notify(struct acpi_device *device, u32 event)
-{
-       struct acpi_processor *pr = acpi_driver_data(device);
        int saved;
 
+       if (device->handle != handle)
+               return;
+
+       pr = acpi_driver_data(device);
        if (!pr)
                return;
 
@@ -420,55 +118,62 @@ static void acpi_processor_notify(struct acpi_device *device, u32 event)
        return;
 }
 
-static int acpi_cpu_soft_notify(struct notifier_block *nfb,
-               unsigned long action, void *hcpu)
+static __cpuinit int __acpi_processor_start(struct acpi_device *device);
+
+static int __cpuinit acpi_cpu_soft_notify(struct notifier_block *nfb,
+                                         unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
        struct acpi_processor *pr = per_cpu(processors, cpu);
+       struct acpi_device *device;
+
+       if (!pr || acpi_bus_get_device(pr->handle, &device))
+               return NOTIFY_DONE;
 
-       if (action == CPU_ONLINE && pr) {
-               /* CPU got physically hotplugged and onlined the first time:
-                * Initialize missing things
+       if (action == CPU_ONLINE) {
+               /*
+                * CPU got physically hotplugged and onlined for the first time:
+                * Initialize missing things.
                 */
                if (pr->flags.need_hotplug_init) {
+                       int ret;
+
                        pr_info("Will online and init hotplugged CPU: %d\n",
                                pr->id);
-                       WARN(acpi_processor_start(pr), "Failed to start CPU:"
-                               " %d\n", pr->id);
                        pr->flags.need_hotplug_init = 0;
-               /* Normal CPU soft online event */
+                       ret = __acpi_processor_start(device);
+                       WARN(ret, "Failed to start CPU: %d\n", pr->id);
                } else {
+                       /* Normal CPU soft online event. */
                        acpi_processor_ppc_has_changed(pr, 0);
                        acpi_processor_hotplug(pr);
                        acpi_processor_reevaluate_tstate(pr, action);
                        acpi_processor_tstate_has_changed(pr);
                }
-       }
-       if (action == CPU_DEAD && pr) {
-               /* invalidate the flag.throttling after one CPU is offline */
+       } else if (action == CPU_DEAD) {
+               /* Invalidate flag.throttling after the CPU is offline. */
                acpi_processor_reevaluate_tstate(pr, action);
        }
        return NOTIFY_OK;
 }
 
-static struct notifier_block acpi_cpu_notifier =
+static struct notifier_block __refdata acpi_cpu_notifier =
 {
            .notifier_call = acpi_cpu_soft_notify,
 };
 
-/*
- * acpi_processor_start() is called by the cpu_hotplug_notifier func:
- * acpi_cpu_soft_notify(). Getting it __cpuinit{data} is difficult, the
- * root cause seem to be that acpi_processor_uninstall_hotplug_notify()
- * is in the module_exit (__exit) func. Allowing acpi_processor_start()
- * to not be in __cpuinit section, but being called from __cpuinit funcs
- * via __ref looks like the right thing to do here.
- */
-static __ref int acpi_processor_start(struct acpi_processor *pr)
+static __cpuinit int __acpi_processor_start(struct acpi_device *device)
 {
-       struct acpi_device *device = per_cpu(processor_device_array, pr->id);
+       struct acpi_processor *pr = acpi_driver_data(device);
+       acpi_status status;
        int result = 0;
 
+       if (!pr)
+               return -ENODEV;
+
+       if (pr->flags.need_hotplug_init)
+               return 0;
+
 #ifdef CONFIG_CPU_FREQ
        acpi_processor_ppc_has_changed(pr, 0);
        acpi_processor_load_module(pr);
@@ -506,462 +211,95 @@ static __ref int acpi_processor_start(struct acpi_processor *pr)
                goto err_remove_sysfs_thermal;
        }
 
-       return 0;
+       status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+                                            acpi_processor_notify, device);
+       if (ACPI_SUCCESS(status))
+               return 0;
 
-err_remove_sysfs_thermal:
+       sysfs_remove_link(&pr->cdev->device.kobj, "device");
+ err_remove_sysfs_thermal:
        sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
-err_thermal_unregister:
+ err_thermal_unregister:
        thermal_cooling_device_unregister(pr->cdev);
-err_power_exit:
+ err_power_exit:
        acpi_processor_power_exit(pr);
-
        return result;
 }
 
-/*
- * Do not put anything in here which needs the core to be online.
- * For example MSR access or setting up things which check for cpuinfo_x86
- * (cpu_data(cpu)) values, like CPU feature flags, family, model, etc.
- * Such things have to be put in and set up above in acpi_processor_start()
- */
-static int __cpuinit acpi_processor_add(struct acpi_device *device)
+static int __cpuinit acpi_processor_start(struct device *dev)
 {
-       struct acpi_processor *pr = NULL;
-       int result = 0;
-       struct device *dev;
-
-       pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
-       if (!pr)
-               return -ENOMEM;
-
-       if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
-               result = -ENOMEM;
-               goto err_free_pr;
-       }
-
-       pr->handle = device->handle;
-       strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
-       strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
-       device->driver_data = pr;
-
-       result = acpi_processor_get_info(device);
-       if (result) {
-               /* Processor is physically not present */
-               return 0;
-       }
+       struct acpi_device *device;
 
-#ifdef CONFIG_SMP
-       if (pr->id >= setup_max_cpus && pr->id != 0)
-               return 0;
-#endif
-
-       BUG_ON(pr->id >= nr_cpu_ids);
-
-       /*
-        * Buggy BIOS check
-        * ACPI id of processors can be reported wrongly by the BIOS.
-        * Don't trust it blindly
-        */
-       if (per_cpu(processor_device_array, pr->id) != NULL &&
-           per_cpu(processor_device_array, pr->id) != device) {
-               dev_warn(&device->dev,
-                       "BIOS reported wrong ACPI id %d for the processor\n",
-                       pr->id);
-               result = -ENODEV;
-               goto err_free_cpumask;
-       }
-       per_cpu(processor_device_array, pr->id) = device;
+       if (acpi_bus_get_device(ACPI_HANDLE(dev), &device))
+               return -ENODEV;
 
-       per_cpu(processors, pr->id) = pr;
-
-       dev = get_cpu_device(pr->id);
-       if (sysfs_create_link(&device->dev.kobj, &dev->kobj, "sysdev")) {
-               result = -EFAULT;
-               goto err_clear_processor;
-       }
-
-       /*
-        * Do not start hotplugged CPUs now, but when they
-        * are onlined the first time
-        */
-       if (pr->flags.need_hotplug_init)
-               return 0;
-
-       result = acpi_processor_start(pr);
-       if (result)
-               goto err_remove_sysfs;
-
-       return 0;
-
-err_remove_sysfs:
-       sysfs_remove_link(&device->dev.kobj, "sysdev");
-err_clear_processor:
-       /*
-        * processor_device_array is not cleared to allow checks for buggy BIOS
-        */ 
-       per_cpu(processors, pr->id) = NULL;
-err_free_cpumask:
-       free_cpumask_var(pr->throttling.shared_cpu_map);
-err_free_pr:
-       kfree(pr);
-       return result;
+       return __acpi_processor_start(device);
 }
 
-static int acpi_processor_remove(struct acpi_device *device)
+static int acpi_processor_stop(struct device *dev)
 {
-       struct acpi_processor *pr = NULL;
+       struct acpi_device *device;
+       struct acpi_processor *pr;
 
+       if (acpi_bus_get_device(ACPI_HANDLE(dev), &device))
+               return 0;
 
-       if (!device || !acpi_driver_data(device))
-               return -EINVAL;
+       acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+                                  acpi_processor_notify);
 
        pr = acpi_driver_data(device);
-
-       if (pr->id >= nr_cpu_ids)
-               goto free;
-
-       if (device->removal_type == ACPI_BUS_REMOVAL_EJECT) {
-               if (acpi_processor_handle_eject(pr))
-                       return -EINVAL;
-       }
+       if (!pr)
+               return 0;
 
        acpi_processor_power_exit(pr);
 
-       sysfs_remove_link(&device->dev.kobj, "sysdev");
-
        if (pr->cdev) {
                sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
                sysfs_remove_link(&pr->cdev->device.kobj, "device");
                thermal_cooling_device_unregister(pr->cdev);
                pr->cdev = NULL;
        }
-
-       per_cpu(processors, pr->id) = NULL;
-       per_cpu(processor_device_array, pr->id) = NULL;
-       try_offline_node(cpu_to_node(pr->id));
-
-free:
-       free_cpumask_var(pr->throttling.shared_cpu_map);
-       kfree(pr);
-
        return 0;
 }
 
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
-/****************************************************************************
- *     Acpi processor hotplug support                                      *
- ****************************************************************************/
-
-static int is_processor_present(acpi_handle handle)
-{
-       acpi_status status;
-       unsigned long long sta = 0;
-
-
-       status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-
-       if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
-               return 1;
-
-       /*
-        * _STA is mandatory for a processor that supports hot plug
-        */
-       if (status == AE_NOT_FOUND)
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                               "Processor does not support hot plug\n"));
-       else
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Processor Device is not present"));
-       return 0;
-}
-
-static void acpi_processor_hotplug_notify(acpi_handle handle,
-                                         u32 event, void *data)
-{
-       struct acpi_device *device = NULL;
-       struct acpi_eject_event *ej_event = NULL;
-       u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-       acpi_status status;
-       int result;
-
-       acpi_scan_lock_acquire();
-
-       switch (event) {
-       case ACPI_NOTIFY_BUS_CHECK:
-       case ACPI_NOTIFY_DEVICE_CHECK:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-               "Processor driver received %s event\n",
-                      (event == ACPI_NOTIFY_BUS_CHECK) ?
-                      "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"));
-
-               if (!is_processor_present(handle))
-                       break;
-
-               if (!acpi_bus_get_device(handle, &device))
-                       break;
-
-               result = acpi_bus_scan(handle);
-               if (result) {
-                       acpi_handle_err(handle, "Unable to add the device\n");
-                       break;
-               }
-               result = acpi_bus_get_device(handle, &device);
-               if (result) {
-                       acpi_handle_err(handle, "Missing device object\n");
-                       break;
-               }
-               ost_code = ACPI_OST_SC_SUCCESS;
-               break;
-
-       case ACPI_NOTIFY_EJECT_REQUEST:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "received ACPI_NOTIFY_EJECT_REQUEST\n"));
-
-               if (acpi_bus_get_device(handle, &device)) {
-                       acpi_handle_err(handle,
-                               "Device don't exist, dropping EJECT\n");
-                       break;
-               }
-               if (!acpi_driver_data(device)) {
-                       acpi_handle_err(handle,
-                               "Driver data is NULL, dropping EJECT\n");
-                       break;
-               }
-
-               ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-               if (!ej_event) {
-                       acpi_handle_err(handle, "No memory, dropping EJECT\n");
-                       break;
-               }
-
-               get_device(&device->dev);
-               ej_event->device = device;
-               ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
-               /* The eject is carried out asynchronously. */
-               status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
-                                                ej_event);
-               if (ACPI_FAILURE(status)) {
-                       put_device(&device->dev);
-                       kfree(ej_event);
-                       break;
-               }
-               goto out;
-
-       default:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Unsupported event [0x%x]\n", event));
-
-               /* non-hotplug event; possibly handled by other handler */
-               goto out;
-       }
-
-       /* Inform firmware that the hotplug operation has completed */
-       (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
-
- out:
-       acpi_scan_lock_release();
-}
-
-static acpi_status is_processor_device(acpi_handle handle)
-{
-       struct acpi_device_info *info;
-       char *hid;
-       acpi_status status;
-
-       status = acpi_get_object_info(handle, &info);
-       if (ACPI_FAILURE(status))
-               return status;
-
-       if (info->type == ACPI_TYPE_PROCESSOR) {
-               kfree(info);
-               return AE_OK;   /* found a processor object */
-       }
-
-       if (!(info->valid & ACPI_VALID_HID)) {
-               kfree(info);
-               return AE_ERROR;
-       }
-
-       hid = info->hardware_id.string;
-       if ((hid == NULL) || strcmp(hid, ACPI_PROCESSOR_DEVICE_HID)) {
-               kfree(info);
-               return AE_ERROR;
-       }
-
-       kfree(info);
-       return AE_OK;   /* found a processor device object */
-}
-
-static acpi_status
-processor_walk_namespace_cb(acpi_handle handle,
-                           u32 lvl, void *context, void **rv)
-{
-       acpi_status status;
-       int *action = context;
-
-       status = is_processor_device(handle);
-       if (ACPI_FAILURE(status))
-               return AE_OK;   /* not a processor; continue to walk */
-
-       switch (*action) {
-       case INSTALL_NOTIFY_HANDLER:
-               acpi_install_notify_handler(handle,
-                                           ACPI_SYSTEM_NOTIFY,
-                                           acpi_processor_hotplug_notify,
-                                           NULL);
-               break;
-       case UNINSTALL_NOTIFY_HANDLER:
-               acpi_remove_notify_handler(handle,
-                                          ACPI_SYSTEM_NOTIFY,
-                                          acpi_processor_hotplug_notify);
-               break;
-       default:
-               break;
-       }
-
-       /* found a processor; skip walking underneath */
-       return AE_CTRL_DEPTH;
-}
-
-static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
-{
-       acpi_handle handle = pr->handle;
-
-       if (!is_processor_present(handle)) {
-               return AE_ERROR;
-       }
-
-       if (acpi_map_lsapic(handle, &pr->id))
-               return AE_ERROR;
-
-       if (arch_register_cpu(pr->id)) {
-               acpi_unmap_lsapic(pr->id);
-               return AE_ERROR;
-       }
-
-       /* CPU got hot-plugged, but cpu_data is not initialized yet
-        * Set flag to delay cpu_idle/throttling initialization
-        * in:
-        * acpi_processor_add()
-        *   acpi_processor_get_info()
-        * and do it when the CPU gets online the first time
-        * TBD: Cleanup above functions and try to do this more elegant.
-        */
-       pr_info("CPU %d got hotplugged\n", pr->id);
-       pr->flags.need_hotplug_init = 1;
-
-       return AE_OK;
-}
-
-static int acpi_processor_handle_eject(struct acpi_processor *pr)
-{
-       if (cpu_online(pr->id))
-               cpu_down(pr->id);
-
-       get_online_cpus();
-       /*
-        * The cpu might become online again at this point. So we check whether
-        * the cpu has been onlined or not. If the cpu became online, it means
-        * that someone wants to use the cpu. So acpi_processor_handle_eject()
-        * returns -EAGAIN.
-        */
-       if (unlikely(cpu_online(pr->id))) {
-               put_online_cpus();
-               pr_warn("Failed to remove CPU %d, because other task "
-                       "brought the CPU back online\n", pr->id);
-               return -EAGAIN;
-       }
-       arch_unregister_cpu(pr->id);
-       acpi_unmap_lsapic(pr->id);
-       put_online_cpus();
-       return (0);
-}
-#else
-static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
-{
-       return AE_ERROR;
-}
-static int acpi_processor_handle_eject(struct acpi_processor *pr)
-{
-       return (-EINVAL);
-}
-#endif
-
-static
-void acpi_processor_install_hotplug_notify(void)
-{
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
-       int action = INSTALL_NOTIFY_HANDLER;
-       acpi_walk_namespace(ACPI_TYPE_ANY,
-                           ACPI_ROOT_OBJECT,
-                           ACPI_UINT32_MAX,
-                           processor_walk_namespace_cb, NULL, &action, NULL);
-#endif
-       register_hotcpu_notifier(&acpi_cpu_notifier);
-}
-
-static
-void acpi_processor_uninstall_hotplug_notify(void)
-{
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
-       int action = UNINSTALL_NOTIFY_HANDLER;
-       acpi_walk_namespace(ACPI_TYPE_ANY,
-                           ACPI_ROOT_OBJECT,
-                           ACPI_UINT32_MAX,
-                           processor_walk_namespace_cb, NULL, &action, NULL);
-#endif
-       unregister_hotcpu_notifier(&acpi_cpu_notifier);
-}
-
 /*
  * We keep the driver loaded even when ACPI is not running.
  * This is needed for the powernow-k8 driver, that works even without
  * ACPI, but needs symbols from this driver
  */
 
-static int __init acpi_processor_init(void)
+static int __init acpi_processor_driver_init(void)
 {
        int result = 0;
 
        if (acpi_disabled)
                return 0;
 
-       result = acpi_bus_register_driver(&acpi_processor_driver);
+       result = driver_register(&acpi_processor_driver);
        if (result < 0)
                return result;
 
        acpi_processor_syscore_init();
-
-       acpi_processor_install_hotplug_notify();
-
+       register_hotcpu_notifier(&acpi_cpu_notifier);
        acpi_thermal_cpufreq_init();
-
        acpi_processor_ppc_init();
-
        acpi_processor_throttling_init();
-
        return 0;
 }
 
-static void __exit acpi_processor_exit(void)
+static void __exit acpi_processor_driver_exit(void)
 {
        if (acpi_disabled)
                return;
 
        acpi_processor_ppc_exit();
-
        acpi_thermal_cpufreq_exit();
-
-       acpi_processor_uninstall_hotplug_notify();
-
+       unregister_hotcpu_notifier(&acpi_cpu_notifier);
        acpi_processor_syscore_exit();
-
-       acpi_bus_unregister_driver(&acpi_processor_driver);
-
-       return;
+       driver_unregister(&acpi_processor_driver);
 }
 
-module_init(acpi_processor_init);
-module_exit(acpi_processor_exit);
+module_init(acpi_processor_driver_init);
+module_exit(acpi_processor_driver_exit);
 
 MODULE_ALIAS("processor");
index eb133c77aadb5f38a7d60824958fa02457c4c67b..0461ccc92c54912142098a7d9b30dcb30685d21d 100644 (file)
@@ -214,13 +214,13 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
 #ifdef CONFIG_PM_SLEEP
 static u32 saved_bm_rld;
 
-int acpi_processor_suspend(void)
+static int acpi_processor_suspend(void)
 {
        acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld);
        return 0;
 }
 
-void acpi_processor_resume(void)
+static void acpi_processor_resume(void)
 {
        u32 resumed_bm_rld;
 
index e854582f29a672a5920500333e26a0b77b310e58..1e9732d809bf67ad19eee32f83617428291025b7 100644 (file)
@@ -639,7 +639,7 @@ end:
 int acpi_processor_preregister_performance(
                struct acpi_processor_performance __percpu *performance)
 {
-       int count, count_target;
+       int count_target;
        int retval = 0;
        unsigned int i, j;
        cpumask_var_t covered_cpus;
@@ -711,7 +711,6 @@ int acpi_processor_preregister_performance(
 
                /* Validate the Domain info */
                count_target = pdomain->num_processors;
-               count = 1;
                if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
                        pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
                else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
@@ -745,7 +744,6 @@ int acpi_processor_preregister_performance(
 
                        cpumask_set_cpu(j, covered_cpus);
                        cpumask_set_cpu(j, pr->performance->shared_cpu_map);
-                       count++;
                }
 
                for_each_possible_cpu(j) {
index 27da63061e11ae88c628242e0eed71fc0e1d7588..dfe76f17cfc4740e0f260c70b25023339d37c210 100644 (file)
@@ -27,6 +27,12 @@ extern struct acpi_device *acpi_root;
 
 #define ACPI_IS_ROOT_DEVICE(device)    (!(device)->parent)
 
+/*
+ * If set, devices will be hot-removed even if they cannot be put offline
+ * gracefully (from the kernel's standpoint).
+ */
+bool acpi_force_hot_remove;
+
 static const char *dummy_hid = "device";
 
 static LIST_HEAD(acpi_device_list);
@@ -120,12 +126,78 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
+static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl,
+                                              void *data, void **ret_p)
+{
+       struct acpi_device *device = NULL;
+       struct acpi_device_physical_node *pn;
+       bool second_pass = (bool)data;
+       acpi_status status = AE_OK;
+
+       if (acpi_bus_get_device(handle, &device))
+               return AE_OK;
+
+       mutex_lock(&device->physical_node_lock);
+
+       list_for_each_entry(pn, &device->physical_node_list, node) {
+               int ret;
+
+               if (second_pass) {
+                       /* Skip devices offlined by the first pass. */
+                       if (pn->put_online)
+                               continue;
+               } else {
+                       pn->put_online = false;
+               }
+               ret = device_offline(pn->dev);
+               if (acpi_force_hot_remove)
+                       continue;
+
+               if (ret >= 0) {
+                       pn->put_online = !ret;
+               } else {
+                       *ret_p = pn->dev;
+                       if (second_pass) {
+                               status = AE_ERROR;
+                               break;
+                       }
+               }
+       }
+
+       mutex_unlock(&device->physical_node_lock);
+
+       return status;
+}
+
+static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl,
+                                             void *data, void **ret_p)
+{
+       struct acpi_device *device = NULL;
+       struct acpi_device_physical_node *pn;
+
+       if (acpi_bus_get_device(handle, &device))
+               return AE_OK;
+
+       mutex_lock(&device->physical_node_lock);
+
+       list_for_each_entry(pn, &device->physical_node_list, node)
+               if (pn->put_online) {
+                       device_online(pn->dev);
+                       pn->put_online = false;
+               }
+
+       mutex_unlock(&device->physical_node_lock);
+
+       return AE_OK;
+}
+
 static int acpi_scan_hot_remove(struct acpi_device *device)
 {
        acpi_handle handle = device->handle;
        acpi_handle not_used;
        struct acpi_object_list arg_list;
        union acpi_object arg;
+       struct device *errdev;
        acpi_status status;
        unsigned long long sta;
 
@@ -136,10 +208,53 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
                return -EINVAL;
        }
 
+       lock_device_hotplug();
+
+       /*
+        * Carry out two passes here and ignore errors in the first pass,
+        * because if the devices in question are memory blocks and
+        * CONFIG_MEMCG is set, one of the blocks may hold data structures
+        * that the other blocks depend on, but it is not known in advance which
+        * block holds them.
+        *
+        * If the first pass is successful, the second one isn't needed, though.
+        */
+       errdev = NULL;
+       acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+                           NULL, acpi_bus_offline_companions,
+                           (void *)false, (void **)&errdev);
+       acpi_bus_offline_companions(handle, 0, (void *)false, (void **)&errdev);
+       if (errdev) {
+               errdev = NULL;
+               acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+                                   NULL, acpi_bus_offline_companions,
+                                   (void *)true , (void **)&errdev);
+               if (!errdev || acpi_force_hot_remove)
+                       acpi_bus_offline_companions(handle, 0, (void *)true,
+                                                   (void **)&errdev);
+
+               if (errdev && !acpi_force_hot_remove) {
+                       dev_warn(errdev, "Offline failed.\n");
+                       acpi_bus_online_companions(handle, 0, NULL, NULL);
+                       acpi_walk_namespace(ACPI_TYPE_ANY, handle,
+                                           ACPI_UINT32_MAX,
+                                           acpi_bus_online_companions, NULL,
+                                           NULL, NULL);
+
+                       unlock_device_hotplug();
+
+                       put_device(&device->dev);
+                       return -EBUSY;
+               }
+       }
+
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                "Hot-removing device %s...\n", dev_name(&device->dev)));
 
        acpi_bus_trim(device);
+
+       unlock_device_hotplug();
+
        /* Device node has been unregistered. */
        put_device(&device->dev);
        device = NULL;
@@ -236,6 +351,7 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
        int error;
 
        mutex_lock(&acpi_scan_lock);
+       lock_device_hotplug();
 
        acpi_bus_get_device(handle, &device);
        if (device) {
@@ -259,6 +375,7 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
                kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
 
  out:
+       unlock_device_hotplug();
        acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
        mutex_unlock(&acpi_scan_lock);
 }
@@ -816,32 +933,43 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device)
                                           acpi_device_notify);
 }
 
-static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
-static int acpi_device_probe(struct device * dev)
+static int acpi_device_probe(struct device *dev)
 {
        struct acpi_device *acpi_dev = to_acpi_device(dev);
        struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
        int ret;
 
-       ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
-       if (!ret) {
-               if (acpi_drv->ops.notify) {
-                       ret = acpi_device_install_notify_handler(acpi_dev);
-                       if (ret) {
-                               if (acpi_drv->ops.remove)
-                                       acpi_drv->ops.remove(acpi_dev);
-                               acpi_dev->driver = NULL;
-                               acpi_dev->driver_data = NULL;
-                               return ret;
-                       }
-               }
+       if (acpi_dev->handler)
+               return -EINVAL;
 
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                       "Found driver [%s] for device [%s]\n",
-                       acpi_drv->name, acpi_dev->pnp.bus_id));
-               get_device(dev);
+       if (!acpi_drv->ops.add)
+               return -ENOSYS;
+
+       ret = acpi_drv->ops.add(acpi_dev);
+       if (ret)
+               return ret;
+
+       acpi_dev->driver = acpi_drv;
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                         "Driver [%s] successfully bound to device [%s]\n",
+                         acpi_drv->name, acpi_dev->pnp.bus_id));
+
+       if (acpi_drv->ops.notify) {
+               ret = acpi_device_install_notify_handler(acpi_dev);
+               if (ret) {
+                       if (acpi_drv->ops.remove)
+                               acpi_drv->ops.remove(acpi_dev);
+
+                       acpi_dev->driver = NULL;
+                       acpi_dev->driver_data = NULL;
+                       return ret;
+               }
        }
-       return ret;
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n",
+                         acpi_drv->name, acpi_dev->pnp.bus_id));
+       get_device(dev);
+       return 0;
 }
 
 static int acpi_device_remove(struct device * dev)
@@ -952,7 +1080,6 @@ int acpi_device_add(struct acpi_device *device,
                printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n",
                       dev_name(&device->dev));
 
-       device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
        return 0;
 
  err:
@@ -997,41 +1124,6 @@ static void acpi_device_unregister(struct acpi_device *device)
 /* --------------------------------------------------------------------------
                                  Driver Management
    -------------------------------------------------------------------------- */
-/**
- * acpi_bus_driver_init - add a device to a driver
- * @device: the device to add and initialize
- * @driver: driver for the device
- *
- * Used to initialize a device via its device driver.  Called whenever a
- * driver is bound to a device.  Invokes the driver's add() ops.
- */
-static int
-acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
-{
-       int result = 0;
-
-       if (!device || !driver)
-               return -EINVAL;
-
-       if (!driver->ops.add)
-               return -ENOSYS;
-
-       result = driver->ops.add(device);
-       if (result)
-               return result;
-
-       device->driver = driver;
-
-       /*
-        * TBD - Configuration Management: Assign resources to device based
-        * upon possible configuration and currently allocated resources.
-        */
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "Driver successfully bound to device\n"));
-       return 0;
-}
-
 /**
  * acpi_bus_register_driver - register a driver with the ACPI bus
  * @driver: driver being registered
@@ -1939,7 +2031,6 @@ static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
        if (!acpi_bus_get_device(handle, &device)) {
                struct acpi_scan_handler *dev_handler = device->handler;
 
-               device->removal_type = ACPI_BUS_REMOVAL_EJECT;
                if (dev_handler) {
                        if (dev_handler->detach)
                                dev_handler->detach(device);
@@ -2038,8 +2129,10 @@ int __init acpi_scan_init(void)
 
        acpi_pci_root_init();
        acpi_pci_link_init();
+       acpi_processor_init();
        acpi_platform_init();
        acpi_lpss_init();
+       acpi_cmos_rtc_init();
        acpi_container_init();
        acpi_memory_hotplug_init();
        acpi_dock_init();
index 9c1a435d10e69c8228516346832a8d2d2d242890..187ab61889e6da5fab9312e987a620a4cb212280 100644 (file)
@@ -494,6 +494,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
                break;
 
        case ACPI_STATE_S3:
+               if (!acpi_suspend_lowlevel)
+                       return -ENOSYS;
                error = acpi_suspend_lowlevel();
                if (error)
                        return error;
index fcae5fa2e1b322481ec2b331c4df0430bff66d53..05306a59aedc18b45dd89f636d907def41d67d11 100644 (file)
@@ -677,10 +677,9 @@ void acpi_irq_stats_init(void)
                else
                        sprintf(buffer, "bug%02X", i);
 
-               name = kzalloc(strlen(buffer) + 1, GFP_KERNEL);
+               name = kstrdup(buffer, GFP_KERNEL);
                if (name == NULL)
                        goto fail;
-               strncpy(name, buffer, strlen(buffer) + 1);
 
                sysfs_attr_init(&counter_attrs[i].attr);
                counter_attrs[i].attr.name = name;
@@ -780,6 +779,33 @@ void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
        pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name);
 }
 
+static ssize_t force_remove_show(struct kobject *kobj,
+                                struct kobj_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", !!acpi_force_hot_remove);
+}
+
+static ssize_t force_remove_store(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 const char *buf, size_t size)
+{
+       bool val;
+       int ret;
+
+       ret = strtobool(buf, &val);
+       if (ret < 0)
+               return ret;
+
+       lock_device_hotplug();
+       acpi_force_hot_remove = val;
+       unlock_device_hotplug();
+       return size;
+}
+
+static const struct kobj_attribute force_remove_attr =
+       __ATTR(force_remove, S_IRUGO | S_IWUSR, force_remove_show,
+              force_remove_store);
+
 int __init acpi_sysfs_init(void)
 {
        int result;
@@ -789,6 +815,10 @@ int __init acpi_sysfs_init(void)
                return result;
 
        hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
+       result = sysfs_create_file(hotplug_kobj, &force_remove_attr.attr);
+       if (result)
+               return result;
+
        result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
        return result;
 }
index 440eadf2d32cdd270a75e9023f9ef31a1d9ae794..5d7075d25700b3bbd2cbe65772391155d1a10d30 100644 (file)
@@ -1722,9 +1722,6 @@ static int acpi_video_bus_add(struct acpi_device *device)
        int error;
        acpi_status status;
 
-       if (device->handler)
-               return -EINVAL;
-
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
                                device->parent->handle, 1,
                                acpi_video_bus_match, NULL,
index cdbad3a454a085a7aa17bf1ae29e4a22b73c5c37..c6707278a6bb496d200caf9f0bd4a57233b9b1a1 100644 (file)
@@ -284,7 +284,7 @@ static const struct dev_pm_ops amba_pm = {
        SET_RUNTIME_PM_OPS(
                amba_pm_runtime_suspend,
                amba_pm_runtime_resume,
-               pm_generic_runtime_idle
+               NULL
        )
 };
 
index a5a3ebcbdd2cf6295028f62d0fe1d3bb21397633..aba6e93b0502e0b966366e4565934fb80f3da9c0 100644 (file)
@@ -263,7 +263,6 @@ config SATA_PROMISE
 
 config SATA_RCAR
        tristate "Renesas R-Car SATA support"
-       depends on ARCH_SHMOBILE && ARCH_R8A7779
        help
          This option enables support for Renesas R-Car Serial ATA.
 
index 9d0cf019ce59a5034984ced1eb113f77b94206ff..fd665d919df2e59a4b44c334bd9c96d14fd946b5 100644 (file)
@@ -128,7 +128,7 @@ static struct pci_driver acard_ahci_pci_driver = {
 #ifdef CONFIG_PM
 static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        struct ahci_host_priv *hpriv = host->private_data;
        void __iomem *mmio = hpriv->mmio;
        u32 ctl;
@@ -156,7 +156,7 @@ static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg
 
 static int acard_ahci_pci_device_resume(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 2b50dfdf1cfc3ea3a6e468e3776e64958fd38e5e..5064f3ea20f1b6f362928bd7a5b3cce39894b259 100644 (file)
@@ -291,6 +291,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */
        { PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
        { PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
+       { PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -310,6 +311,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
 
        /* AMD */
        { PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
+       { PCI_VDEVICE(AMD, 0x7900), board_ahci }, /* AMD CZ */
        /* AMD is using RAID class only for ahci controllers */
        { PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
          PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
@@ -585,7 +587,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
 
        /* clear D2H reception area to properly wait for D2H FIS */
        ata_tf_init(link->device, &tf);
-       tf.command = 0x80;
+       tf.command = ATA_BUSY;
        ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 
        rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
@@ -618,7 +620,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
 #ifdef CONFIG_PM
 static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        struct ahci_host_priv *hpriv = host->private_data;
        void __iomem *mmio = hpriv->mmio;
        u32 ctl;
@@ -646,7 +648,7 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 
 static int ahci_pci_device_resume(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
@@ -1144,9 +1146,11 @@ int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
                return rc;
 
        for (i = 0; i < host->n_ports; i++) {
+               struct ahci_port_priv *pp = host->ports[i]->private_data;
+
                rc = devm_request_threaded_irq(host->dev,
                        irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
-                       dev_driver_string(host->dev), host->ports[i]);
+                       pp->irq_desc, host->ports[i]);
                if (rc)
                        goto out_free_irqs;
        }
index 10b14d45cfd2f8d2d9bb712a75e7787cdf67bdc1..11456371f29b04fdeee0aaf8247f893b3ac52a13 100644 (file)
@@ -306,6 +306,7 @@ struct ahci_port_priv {
        int                     fbs_last_dev;   /* save FBS.DEV of last FIS */
        /* enclosure management info per PM slot */
        struct ahci_em_priv     em_priv[EM_MAX_SLOTS];
+       char                    *irq_desc;      /* desc in /proc/interrupts */
 };
 
 struct ahci_host_priv {
@@ -321,6 +322,7 @@ struct ahci_host_priv {
        u32                     em_buf_sz;      /* EM buffer size in byte */
        u32                     em_msg_type;    /* EM message type */
        struct clk              *clk;           /* Only for platforms supporting clk */
+       void                    *plat_data;     /* Other platform data */
 };
 
 extern int ahci_ignore_sss;
index 7a8a2841fe64a93effec85f1ff5fc6dc4c610d06..2daaee05cab12d629502c913ef7102a793cdf27f 100644 (file)
@@ -327,6 +327,7 @@ static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
 
 static const struct of_device_id ahci_of_match[] = {
        { .compatible = "snps,spear-ahci", },
+       { .compatible = "snps,exynos5440-ahci", },
        {},
 };
 MODULE_DEVICE_TABLE(of, ahci_of_match);
index 9a8a674e8fac9df8ac2c6d08515ce88e6b213fc8..b52a10c8eeb9b775cd1c7fd438ace85571e2ca27 100644 (file)
@@ -338,6 +338,8 @@ static const struct pci_device_id piix_pci_tbl[] = {
        /* SATA Controller IDE (BayTrail) */
        { 0x8086, 0x0F20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
        { 0x8086, 0x0F21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
+       /* SATA Controller IDE (Coleto Creek) */
+       { 0x8086, 0x23a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
 
        { }     /* terminate list */
 };
@@ -993,7 +995,7 @@ static int piix_broken_suspend(void)
 
 static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        unsigned long flags;
        int rc = 0;
 
@@ -1028,7 +1030,7 @@ static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 
 static int piix_pci_device_resume(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        unsigned long flags;
        int rc;
 
@@ -1751,7 +1753,7 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 static void piix_remove_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        struct piix_host_priv *hpriv = host->private_data;
 
        pci_write_config_dword(pdev, PIIX_IOCFG, hpriv->saved_iocfg);
index a70ff154f586753d6c096b858ae5dbee0ad869c3..acfd0f711069e9da304c95179b14127e20ae1c9c 100644 (file)
@@ -173,6 +173,7 @@ struct ata_port_operations ahci_ops = {
        .em_store               = ahci_led_store,
        .sw_activity_show       = ahci_activity_show,
        .sw_activity_store      = ahci_activity_store,
+       .transmit_led_message   = ahci_transmit_led_message,
 #ifdef CONFIG_PM
        .port_suspend           = ahci_port_suspend,
        .port_resume            = ahci_port_resume,
@@ -774,7 +775,7 @@ static void ahci_start_port(struct ata_port *ap)
 
                        /* EM Transmit bit maybe busy during init */
                        for (i = 0; i < EM_MAX_RETRY; i++) {
-                               rc = ahci_transmit_led_message(ap,
+                               rc = ap->ops->transmit_led_message(ap,
                                                               emp->led_state,
                                                               4);
                                if (rc == -EBUSY)
@@ -915,7 +916,7 @@ static void ahci_sw_activity_blink(unsigned long arg)
                        led_message |= (1 << 16);
        }
        spin_unlock_irqrestore(ap->lock, flags);
-       ahci_transmit_led_message(ap, led_message, 4);
+       ap->ops->transmit_led_message(ap, led_message, 4);
 }
 
 static void ahci_init_sw_activity(struct ata_link *link)
@@ -1044,7 +1045,7 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
        if (emp->blink_policy)
                state &= ~EM_MSG_LED_VALUE_ACTIVITY;
 
-       return ahci_transmit_led_message(ap, state, size);
+       return ap->ops->transmit_led_message(ap, state, size);
 }
 
 static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
@@ -1063,7 +1064,7 @@ static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
                /* set the LED to OFF */
                port_led_state &= EM_MSG_LED_VALUE_OFF;
                port_led_state |= (ap->port_no | (link->pmp << 8));
-               ahci_transmit_led_message(ap, port_led_state, 4);
+               ap->ops->transmit_led_message(ap, port_led_state, 4);
        } else {
                link->flags |= ATA_LFLAG_SW_ACTIVITY;
                if (val == BLINK_OFF) {
@@ -1071,7 +1072,7 @@ static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
                        port_led_state &= EM_MSG_LED_VALUE_OFF;
                        port_led_state |= (ap->port_no | (link->pmp << 8));
                        port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
-                       ahci_transmit_led_message(ap, port_led_state, 4);
+                       ap->ops->transmit_led_message(ap, port_led_state, 4);
                }
        }
        emp->blink_policy = val;
@@ -1412,7 +1413,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
 
        /* clear D2H reception area to properly wait for D2H FIS */
        ata_tf_init(link->device, &tf);
-       tf.command = 0x80;
+       tf.command = ATA_BUSY;
        ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 
        rc = sata_link_hardreset(link, timing, deadline, &online,
@@ -1560,8 +1561,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
                u32 fbs = readl(port_mmio + PORT_FBS);
                int pmp = fbs >> PORT_FBS_DWE_OFFSET;
 
-               if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links) &&
-                   ata_link_online(&ap->pmp_link[pmp])) {
+               if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links)) {
                        link = &ap->pmp_link[pmp];
                        fbs_need_dec = true;
                }
@@ -2234,6 +2234,16 @@ static int ahci_port_start(struct ata_port *ap)
        if (!pp)
                return -ENOMEM;
 
+       if (ap->host->n_ports > 1) {
+               pp->irq_desc = devm_kzalloc(dev, 8, GFP_KERNEL);
+               if (!pp->irq_desc) {
+                       devm_kfree(dev, pp);
+                       return -ENOMEM;
+               }
+               snprintf(pp->irq_desc, 8,
+                        "%s%d", dev_driver_string(dev), ap->port_no);
+       }
+
        /* check FBS capability */
        if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
                void __iomem *port_mmio = ahci_port_base(ap);
index adf002a3c584b3d2bd7fb27357df040a381f3b82..c24354d44f3d72266dcf8b3994c5070e6e5e55dd 100644 (file)
@@ -2401,7 +2401,7 @@ int ata_dev_configure(struct ata_device *dev)
                        cdb_intr_string = ", CDB intr";
                }
 
-               if (atapi_dmadir || atapi_id_dmadir(dev->id)) {
+               if (atapi_dmadir || (dev->horkage & ATA_HORKAGE_ATAPI_DMADIR) || atapi_id_dmadir(dev->id)) {
                        dev->flags |= ATA_DFLAG_DMADIR;
                        dma_dir_string = ", DMADIR";
                }
@@ -5436,7 +5436,7 @@ static int ata_port_runtime_idle(struct device *dev)
                                return -EBUSY;
        }
 
-       return pm_runtime_suspend(dev);
+       return 0;
 }
 
 static int ata_port_runtime_suspend(struct device *dev)
@@ -5642,6 +5642,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
        ap->pflags |= ATA_PFLAG_INITIALIZING | ATA_PFLAG_FROZEN;
        ap->lock = &host->lock;
        ap->print_id = -1;
+       ap->local_port_no = -1;
        ap->host = host;
        ap->dev = host->dev;
 
@@ -6132,9 +6133,10 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
                kfree(host->ports[i]);
 
        /* give ports names and add SCSI hosts */
-       for (i = 0; i < host->n_ports; i++)
+       for (i = 0; i < host->n_ports; i++) {
                host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
-
+               host->ports[i]->local_port_no = i + 1;
+       }
 
        /* Create associated sysfs transport objects  */
        for (i = 0; i < host->n_ports; i++) {
@@ -6502,6 +6504,7 @@ static int __init ata_parse_force_one(char **cur,
                { "nosrst",     .lflags         = ATA_LFLAG_NO_SRST },
                { "norst",      .lflags         = ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST },
                { "rstonce",    .lflags         = ATA_LFLAG_RST_ONCE },
+               { "atapi_dmadir", .horkage_on   = ATA_HORKAGE_ATAPI_DMADIR },
        };
        char *start = *cur, *p = *cur;
        char *id, *val, *endp;
index 61c59ee45ce9275af707d68a5328d276863c57df..1c41722bb7e2d39016dd25f023dc37d6860b7584 100644 (file)
@@ -389,9 +389,13 @@ static void sata_pmp_quirks(struct ata_port *ap)
                        /* link reports offline after LPM */
                        link->flags |= ATA_LFLAG_NO_LPM;
 
-                       /* Class code report is unreliable. */
+                       /*
+                        * Class code report is unreliable and SRST times
+                        * out under certain configurations.
+                        */
                        if (link->pmp < 5)
-                               link->flags |= ATA_LFLAG_ASSUME_ATA;
+                               link->flags |= ATA_LFLAG_NO_SRST |
+                                              ATA_LFLAG_ASSUME_ATA;
 
                        /* port 5 is for SEMB device and it doesn't like SRST */
                        if (link->pmp == 5)
@@ -399,20 +403,17 @@ static void sata_pmp_quirks(struct ata_port *ap)
                                               ATA_LFLAG_ASSUME_SEMB;
                }
        } else if (vendor == 0x1095 && devid == 0x4723) {
-               /* sil4723 quirks */
-               ata_for_each_link(link, ap, EDGE) {
-                       /* link reports offline after LPM */
-                       link->flags |= ATA_LFLAG_NO_LPM;
-
-                       /* class code report is unreliable */
-                       if (link->pmp < 2)
-                               link->flags |= ATA_LFLAG_ASSUME_ATA;
-
-                       /* the config device at port 2 locks up on SRST */
-                       if (link->pmp == 2)
-                               link->flags |= ATA_LFLAG_NO_SRST |
-                                              ATA_LFLAG_ASSUME_ATA;
-               }
+               /*
+                * sil4723 quirks
+                *
+                * Link reports offline after LPM.  Class code report is
+                * unreliable.  SIMG PMPs never got SRST reliable and the
+                * config device at port 2 locks up on SRST.
+                */
+               ata_for_each_link(link, ap, EDGE)
+                       link->flags |= ATA_LFLAG_NO_LPM |
+                                      ATA_LFLAG_NO_SRST |
+                                      ATA_LFLAG_ASSUME_ATA;
        } else if (vendor == 0x1095 && devid == 0x4726) {
                /* sil4726 quirks */
                ata_for_each_link(link, ap, EDGE) {
index 0101af541436f8076b056c237fd2dc9cc8e4dce6..83c08907e0428bd44c6fad7f1f634357ea5606cd 100644 (file)
@@ -849,25 +849,24 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
                /*  Bad address mark */
                {0x01,          MEDIUM_ERROR, 0x13, 0x00},      // Address mark not found       Address mark not found for data field
                /* TRK0 */
-               {0x02,          HARDWARE_ERROR, 0x00, 0x00},    // Track 0 not found              Hardware error
-               /* Abort & !ICRC */
-               {0x04,          ABORTED_COMMAND, 0x00, 0x00},   // Aborted command              Aborted command
+               {0x02,          HARDWARE_ERROR, 0x00, 0x00},    // Track 0 not found            Hardware error
+               /* Abort: 0x04 is not translated here, see below */
                /* Media change request */
                {0x08,          NOT_READY, 0x04, 0x00},         // Media change request   FIXME: faking offline
-               /* SRV */
-               {0x10,          ABORTED_COMMAND, 0x14, 0x00},   // ID not found                 Recorded entity not found
-               /* Media change */
-               {0x08,          NOT_READY, 0x04, 0x00},         // Media change           FIXME: faking offline
+               /* SRV/IDNF */
+               {0x10,          ILLEGAL_REQUEST, 0x21, 0x00},   // ID not found                 Logical address out of range
+               /* MC */
+               {0x20,          UNIT_ATTENTION, 0x28, 0x00},    // Media Changed                Not ready to ready change, medium may have changed
                /* ECC */
                {0x40,          MEDIUM_ERROR, 0x11, 0x04},      // Uncorrectable ECC error      Unrecovered read error
                /* BBD - block marked bad */
-               {0x80,          MEDIUM_ERROR, 0x11, 0x04},      // Block marked bad               Medium error, unrecovered read error
+               {0x80,          MEDIUM_ERROR, 0x11, 0x04},      // Block marked bad             Medium error, unrecovered read error
                {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
        };
        static const unsigned char stat_table[][4] = {
                /* Must be first because BUSY means no other bits valid */
                {0x80,          ABORTED_COMMAND, 0x47, 0x00},   // Busy, fake parity for now
-               {0x20,          HARDWARE_ERROR,  0x00, 0x00},   // Device fault
+               {0x20,          HARDWARE_ERROR,  0x44, 0x00},   // Device fault, internal target failure
                {0x08,          ABORTED_COMMAND, 0x47, 0x00},   // Timed out in xfer, fake parity for now
                {0x04,          RECOVERED_ERROR, 0x11, 0x00},   // Recovered ECC error    Medium error, recovered
                {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
@@ -892,13 +891,13 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
                                goto translate_done;
                        }
                }
-               /* No immediate match */
-               if (verbose)
-                       printk(KERN_WARNING "ata%u: no sense translation for "
-                              "error 0x%02x\n", id, drv_err);
        }
 
-       /* Fall back to interpreting status bits */
+       /*
+        * Fall back to interpreting status bits.  Note that if the drv_err
+        * has only the ABRT bit set, we decode drv_stat.  ABRT by itself
+        * is not descriptive enough.
+        */
        for (i = 0; stat_table[i][0] != 0xFF; i++) {
                if (stat_table[i][0] & drv_stat) {
                        *sk = stat_table[i][1];
@@ -907,13 +906,11 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
                        goto translate_done;
                }
        }
-       /* No error?  Undecoded? */
-       if (verbose)
-               printk(KERN_WARNING "ata%u: no sense translation for "
-                      "status: 0x%02x\n", id, drv_stat);
 
-       /* We need a sensible error return here, which is tricky, and one
-          that won't cause people to do things like return a disk wrongly */
+       /*
+        * We need a sensible error return here, which is tricky, and one
+        * that won't cause people to do things like return a disk wrongly.
+        */
        *sk = ABORTED_COMMAND;
        *asc = 0x00;
        *ascq = 0x00;
index c04d393d20c119d970d80d1b73e0e0e628b0f761..077a856f5fd0b3aaa7cfdd01b141542dddb51603 100644 (file)
@@ -37,7 +37,7 @@
 #include "libata.h"
 #include "libata-transport.h"
 
-#define ATA_PORT_ATTRS         2
+#define ATA_PORT_ATTRS         3
 #define ATA_LINK_ATTRS         3
 #define ATA_DEV_ATTRS          9
 
@@ -216,6 +216,7 @@ static DEVICE_ATTR(name, S_IRUGO, show_ata_port_##name, NULL)
 
 ata_port_simple_attr(nr_pmp_links, nr_pmp_links, "%d\n", int);
 ata_port_simple_attr(stats.idle_irq, idle_irq, "%ld\n", unsigned long);
+ata_port_simple_attr(local_port_no, port_no, "%u\n", unsigned int);
 
 static DECLARE_TRANSPORT_CLASS(ata_port_class,
                               "ata_port", NULL, NULL, NULL);
@@ -709,6 +710,7 @@ struct scsi_transport_template *ata_attach_transport(void)
        count = 0;
        SETUP_PORT_ATTRIBUTE(nr_pmp_links);
        SETUP_PORT_ATTRIBUTE(idle_irq);
+       SETUP_PORT_ATTRIBUTE(port_no);
        BUG_ON(count > ATA_PORT_ATTRS);
        i->port_attrs[count] = NULL;
 
index 90b159b740b3fd1f9153f371a84fa803c17ee4d6..cd8daf47188b0a635cd697a5ed406c0c92e02ab6 100644 (file)
@@ -32,13 +32,14 @@ struct zpodd {
 
 static int eject_tray(struct ata_device *dev)
 {
-       struct ata_taskfile tf = {};
+       struct ata_taskfile tf;
        const char cdb[] = {  GPCMD_START_STOP_UNIT,
                0, 0, 0,
                0x02,     /* LoEj */
                0, 0, 0, 0, 0, 0, 0,
        };
 
+       ata_tf_init(dev, &tf);
        tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
        tf.command = ATA_CMD_PACKET;
        tf.protocol = ATAPI_PROT_NODATA;
@@ -52,8 +53,7 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
        char buf[16];
        unsigned int ret;
        struct rm_feature_desc *desc = (void *)(buf + 8);
-       struct ata_taskfile tf = {};
-
+       struct ata_taskfile tf;
        char cdb[] = {  GPCMD_GET_CONFIGURATION,
                        2,      /* only 1 feature descriptor requested */
                        0, 3,   /* 3, removable medium feature */
@@ -62,6 +62,7 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
                        0, 0, 0,
        };
 
+       ata_tf_init(dev, &tf);
        tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
        tf.command = ATA_CMD_PACKET;
        tf.protocol = ATAPI_PROT_PIO;
index 61da0694aecd68e867a486b9aa8a92efa9aaf25b..1b7b2ccabcff2e906fe603eb3c96cea136b70c9b 100644 (file)
@@ -592,7 +592,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int ali_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 82a08922afcd1d30a55dec64ed17bd6d8c414b13..d23e2b3ca0b68a6c7109eef8e53b2e3e68048281 100644 (file)
@@ -578,7 +578,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int amd_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 7638121cb5d1eb0447836f47f8ffbef9734d5ef6..848ed3254ddd6892f9f26cf3be0ab7efcb1a8f79 100644 (file)
@@ -908,7 +908,7 @@ free_clk:
 
 static int arasan_cf_remove(struct platform_device *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = platform_get_drvdata(pdev);
        struct arasan_cf_dev *acdev = host->ports[0]->private_data;
 
        ata_host_detach(host);
index 74b215c09b21cfc72c7f2c45567379b2b00f04b6..1581dee2967a80368976303fc9e7865b1e69cef2 100644 (file)
@@ -426,7 +426,7 @@ static const struct pci_device_id artop_pci_tbl[] = {
 #ifdef CONFIG_PM
 static int atp8xx_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 033f3f4c20adc9def5cca1a683bdd7e08e5a1fa7..5364f97b42c6b9d6fcac4e130d3172913aa7c80a 100644 (file)
@@ -422,7 +422,7 @@ err_put:
 
 static int pata_at91_remove(struct platform_device *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = platform_get_drvdata(pdev);
        struct at91_ide_info *info;
 
        if (!host)
index 041f50d532403e9f34f61d888b8bfd70d304aac9..2ca5026f2c150f9e83b37e48e8227e944a18253f 100644 (file)
@@ -534,7 +534,7 @@ err_out:
 #ifdef CONFIG_PM
 static int atp867x_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 8d43510c6becbb14a2e66ae54b92200c568af96a..ba0d8a29dc235ab33de62e5e9eb233afcba47a83 100644 (file)
@@ -1596,7 +1596,7 @@ static int bfin_atapi_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       dev_set_drvdata(&pdev->dev, host);
+       platform_set_drvdata(pdev, host);
 
        return 0;
 }
@@ -1610,11 +1610,9 @@ static int bfin_atapi_probe(struct platform_device *pdev)
  */
 static int bfin_atapi_remove(struct platform_device *pdev)
 {
-       struct device *dev = &pdev->dev;
-       struct ata_host *host = dev_get_drvdata(dev);
+       struct ata_host *host = platform_get_drvdata(pdev);
 
        ata_host_detach(host);
-       dev_set_drvdata(&pdev->dev, NULL);
 
        peripheral_free_list(atapi_io_port);
 
@@ -1624,7 +1622,7 @@ static int bfin_atapi_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = platform_get_drvdata(pdev);
        if (host)
                return ata_host_suspend(host, state);
        else
@@ -1633,7 +1631,7 @@ static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
 
 static int bfin_atapi_resume(struct platform_device *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = platform_get_drvdata(pdev);
        int ret;
 
        if (host) {
index 504b98b58e1950368890c00b8dd20aadd69c6c58..8fb69e5ca1b7f08be8ef7a635acdf8122765f577 100644 (file)
@@ -235,7 +235,7 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int cmd640_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 2949cfc2dd31ab9c234c55cf706c09f8e6848573..1275a8d4dedc06940cbce5660d24136d27aea0ef 100644 (file)
@@ -491,7 +491,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int cmd64x_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index bfcf377e8f77a81df2b32b5c8525be844e585b21..f10baabbf5db5ae2f266aed4f7559d258962f267 100644 (file)
@@ -241,7 +241,7 @@ static int cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 static int cs5520_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        u8 pcicfg;
        int rc;
 
@@ -269,7 +269,7 @@ static int cs5520_reinit_one(struct pci_dev *pdev)
 
 static int cs5520_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc = 0;
 
        rc = ata_host_suspend(host, mesg);
index 48389ae0b330d6cffc18774b1aa102f3db26321b..f07f2296acdcf5c986a0c33bd423736268f42c33 100644 (file)
@@ -330,7 +330,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int cs5530_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 4be884a9f5edc6537e1eac71232654315da301ba..35b521348d311fbb7b2921618e348661a57edfb6 100644 (file)
@@ -390,7 +390,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int hpt36x_reinit_one(struct pci_dev *dev)
 {
-       struct ata_host *host = dev_get_drvdata(&dev->dev);
+       struct ata_host *host = pci_get_drvdata(dev);
        int rc;
 
        rc = ata_pci_device_do_resume(dev);
index 76c9314bb82457cf950e72454765b79c23a12d14..85cf2861e0b7d217eaabd6ffa446a6446de84c72 100644 (file)
@@ -253,7 +253,7 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int hpt3x3_reinit_one(struct pci_dev *dev)
 {
-       struct ata_host *host = dev_get_drvdata(&dev->dev);
+       struct ata_host *host = pci_get_drvdata(dev);
        int rc;
 
        rc = ata_pci_device_do_resume(dev);
index aa3d166e02eb87ae698f4abe5bb69c14ea293166..4ec7c04b3f8279dff1f2e39f356106e92815e39f 100644 (file)
@@ -177,7 +177,7 @@ err:
 
 static int pata_imx_remove(struct platform_device *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = platform_get_drvdata(pdev);
        struct pata_imx_priv *priv = host->private_data;
 
        ata_host_detach(host);
index 9cc05d808ad5af450d39cb0bc9282af081eb2f0e..581e04d80367a9690c22513aaba376bf7dff643f 100644 (file)
@@ -939,7 +939,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 #ifdef CONFIG_PM
 static int it821x_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index e5725edcf5159eabae5e6751972aeb0e7d46ed1b..c28d0645e8514c1cb8785bf30529e90c6f0b81a4 100644 (file)
@@ -1311,7 +1311,7 @@ static int pata_macio_pci_attach(struct pci_dev *pdev,
 
 static void pata_macio_pci_detach(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
 
        ata_host_detach(host);
 }
@@ -1320,14 +1320,14 @@ static void pata_macio_pci_detach(struct pci_dev *pdev)
 
 static int pata_macio_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
 
        return pata_macio_do_suspend(host->private_data, mesg);
 }
 
 static int pata_macio_pci_resume(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
 
        return pata_macio_do_resume(host->private_data);
 }
index 3a8fb28b71f28df9129277167703c96706b79d96..0024ced3e2008e7a2e38b6a8715ee95fee405b2b 100644 (file)
@@ -825,7 +825,7 @@ mpc52xx_ata_remove(struct platform_device *op)
 static int
 mpc52xx_ata_suspend(struct platform_device *op, pm_message_t state)
 {
-       struct ata_host *host = dev_get_drvdata(&op->dev);
+       struct ata_host *host = platform_get_drvdata(op);
 
        return ata_host_suspend(host, state);
 }
@@ -833,7 +833,7 @@ mpc52xx_ata_suspend(struct platform_device *op, pm_message_t state)
 static int
 mpc52xx_ata_resume(struct platform_device *op)
 {
-       struct ata_host *host = dev_get_drvdata(&op->dev);
+       struct ata_host *host = platform_get_drvdata(op);
        struct mpc52xx_ata_priv *priv = host->private_data;
        int rv;
 
index 12010ed596c48c21a16045ca52c534a7c8851fb8..9513e071040da8f148dc63a6b2aca8f7d7018a83 100644 (file)
@@ -157,7 +157,7 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
 static int ninja32_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 6f6fa10605059baeb0aa5fee1b5bb4ae7991adb3..16dc3a63a23d5f763b28c92d7fcc9170d0e2320e 100644 (file)
@@ -389,7 +389,7 @@ static const struct pci_device_id ns87415_pci_tbl[] = {
 #ifdef CONFIG_PM
 static int ns87415_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index c76e65927b0eaefa369af9f1ae8abe87b7b8266c..9d874c85d64d7f5eb7f5d4c44fe785e8aa1c555a 100644 (file)
@@ -765,7 +765,7 @@ static int pdc2027x_init_one(struct pci_dev *pdev,
 #ifdef CONFIG_PM
 static int pdc2027x_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        unsigned int board_idx;
        int rc;
 
index b0ac9e0c5e01e647d205e6597f33614098d66a42..942ef94b29e6658a115935c64cc3e81bdf8c1e6b 100644 (file)
@@ -371,7 +371,7 @@ static int pxa_ata_probe(struct platform_device *pdev)
 
 static int pxa_ata_remove(struct platform_device *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = platform_get_drvdata(pdev);
        struct pata_pxa_data *data = host->ports[0]->private_data;
 
        pxa_free_dma(data->dma_channel);
index 6a8665574fee5ad0e20e2f2423c76e32d8fca6a9..79a970f05a2e2bb54d60fcfa92211596f41791ec 100644 (file)
@@ -364,7 +364,7 @@ static int rdc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 static void rdc_remove_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        struct rdc_host_priv *hpriv = host->private_data;
 
        pci_write_config_dword(pdev, 0x54, hpriv->saved_iocfg);
index 60f4de2dd47daaef17a0c40a1f50190e77a0e776..040b093617a4ada5ffa76c61c2d20615644d5b35 100644 (file)
@@ -105,7 +105,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en
 #ifdef CONFIG_PM
 static int rz1000_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index f3febbce6c462d2c7d432533630bcc17a5cd86d4..96c6a79ef6066af0171b74864134f34a05ebb611 100644 (file)
@@ -440,7 +440,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
 #ifdef CONFIG_PM
 static int serverworks_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 64c5f0d0f81279cad0fb8226b85da5dfdeafe08f..c4b0b073ba8e8c7d13512a2c6930b987ba1a4745 100644 (file)
@@ -407,7 +407,7 @@ use_ioports:
 #ifdef CONFIG_PM
 static int sil680_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int try_mmio, rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 2d5ac1361262f51d525deeda3b4e511af1554676..1e8363640bf5e7bd16a065ce0222c161b745e459 100644 (file)
@@ -873,7 +873,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 #ifdef CONFIG_PM
 static int sis_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 738e000107d61eaefdb66e46d2d9d0a55d92c069..6816911ac4229ba8e7dc46829cd2da9461015ef5 100644 (file)
@@ -341,7 +341,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
 #ifdef CONFIG_PM
 static int sl82c105_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index c8e589d91231945f718ba7b5bdd2520a927a2c44..94473da68c02d9664906f8c5c82a0f395d881d63 100644 (file)
@@ -211,7 +211,7 @@ static const struct pci_device_id triflex[] = {
 #ifdef CONFIG_PM
 static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc = 0;
 
        rc = ata_host_suspend(host, mesg);
index 8d2a9fdf6b8d9da3ad609e1eb33f068faf296c7b..c3ab9a6c3965b1c8df7045da6f6a1a10f414ca9b 100644 (file)
@@ -673,7 +673,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 static int via_reinit_one(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index d40e403e82dd259a34ab6a155a88619ba3b3542a..19720a0a4a65ff5c6198ab4e37df7e756ce85717 100644 (file)
@@ -1532,7 +1532,7 @@ static int sata_fsl_probe(struct platform_device *ofdev)
        ata_host_activate(host, irq, sata_fsl_interrupt, SATA_FSL_IRQ_FLAG,
                          &sata_fsl_sht);
 
-       dev_set_drvdata(&ofdev->dev, host);
+       platform_set_drvdata(ofdev, host);
 
        host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show;
        host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store;
@@ -1558,10 +1558,8 @@ static int sata_fsl_probe(struct platform_device *ofdev)
 
 error_exit_with_cleanup:
 
-       if (host) {
-               dev_set_drvdata(&ofdev->dev, NULL);
+       if (host)
                ata_host_detach(host);
-       }
 
        if (hcr_base)
                iounmap(hcr_base);
@@ -1572,7 +1570,7 @@ error_exit_with_cleanup:
 
 static int sata_fsl_remove(struct platform_device *ofdev)
 {
-       struct ata_host *host = dev_get_drvdata(&ofdev->dev);
+       struct ata_host *host = platform_get_drvdata(ofdev);
        struct sata_fsl_host_priv *host_priv = host->private_data;
 
        device_remove_file(&ofdev->dev, &host_priv->intr_coalescing);
@@ -1580,8 +1578,6 @@ static int sata_fsl_remove(struct platform_device *ofdev)
 
        ata_host_detach(host);
 
-       dev_set_drvdata(&ofdev->dev, NULL);
-
        irq_dispose_mapping(host_priv->irq);
        iounmap(host_priv->hcr_base);
        kfree(host_priv);
@@ -1592,13 +1588,13 @@ static int sata_fsl_remove(struct platform_device *ofdev)
 #ifdef CONFIG_PM
 static int sata_fsl_suspend(struct platform_device *op, pm_message_t state)
 {
-       struct ata_host *host = dev_get_drvdata(&op->dev);
+       struct ata_host *host = platform_get_drvdata(op);
        return ata_host_suspend(host, state);
 }
 
 static int sata_fsl_resume(struct platform_device *op)
 {
-       struct ata_host *host = dev_get_drvdata(&op->dev);
+       struct ata_host *host = platform_get_drvdata(op);
        struct sata_fsl_host_priv *host_priv = host->private_data;
        int ret;
        void __iomem *hcr_base = host_priv->hcr_base;
index b20aa96b958d2428e4cd776cedfc57eee56ba3d8..d047d92a456fbab39c56046d74feb24c9163668f 100644 (file)
@@ -33,6 +33,9 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
 #include "ahci.h"
 
 #define CPHY_MAP(dev, addr) ((((dev) & 0x1f) << 7) | (((addr) >> 9) & 0x7f))
@@ -66,6 +69,146 @@ struct phy_lane_info {
 };
 static struct phy_lane_info port_data[CPHY_PORT_COUNT];
 
+static DEFINE_SPINLOCK(sgpio_lock);
+#define SCLOCK                         0
+#define SLOAD                          1
+#define SDATA                          2
+#define SGPIO_PINS                     3
+#define SGPIO_PORTS                    8
+
+/* can be cast as an ahci_host_priv for compatibility with most functions */
+struct ecx_plat_data {
+       u32             n_ports;
+       unsigned        sgpio_gpio[SGPIO_PINS];
+       u32             sgpio_pattern;
+       u32             port_to_sgpio[SGPIO_PORTS];
+};
+
+#define SGPIO_SIGNALS                  3
+#define ECX_ACTIVITY_BITS              0x300000
+#define ECX_ACTIVITY_SHIFT             2
+#define ECX_LOCATE_BITS                        0x80000
+#define ECX_LOCATE_SHIFT               1
+#define ECX_FAULT_BITS                 0x400000
+#define ECX_FAULT_SHIFT                        0
+static inline int sgpio_bit_shift(struct ecx_plat_data *pdata, u32 port,
+                               u32 shift)
+{
+       return 1 << (3 * pdata->port_to_sgpio[port] + shift);
+}
+
+static void ecx_parse_sgpio(struct ecx_plat_data *pdata, u32 port, u32 state)
+{
+       if (state & ECX_ACTIVITY_BITS)
+               pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
+                                               ECX_ACTIVITY_SHIFT);
+       else
+               pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
+                                               ECX_ACTIVITY_SHIFT);
+       if (state & ECX_LOCATE_BITS)
+               pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
+                                               ECX_LOCATE_SHIFT);
+       else
+               pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
+                                               ECX_LOCATE_SHIFT);
+       if (state & ECX_FAULT_BITS)
+               pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
+                                               ECX_FAULT_SHIFT);
+       else
+               pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
+                                               ECX_FAULT_SHIFT);
+}
+
+/*
+ * Tell the LED controller that the signal has changed by raising the clock
+ * line for 50 uS and then lowering it for 50 uS.
+ */
+static void ecx_led_cycle_clock(struct ecx_plat_data *pdata)
+{
+       gpio_set_value(pdata->sgpio_gpio[SCLOCK], 1);
+       udelay(50);
+       gpio_set_value(pdata->sgpio_gpio[SCLOCK], 0);
+       udelay(50);
+}
+
+static ssize_t ecx_transmit_led_message(struct ata_port *ap, u32 state,
+                                       ssize_t size)
+{
+       struct ahci_host_priv *hpriv =  ap->host->private_data;
+       struct ecx_plat_data *pdata = (struct ecx_plat_data *) hpriv->plat_data;
+       struct ahci_port_priv *pp = ap->private_data;
+       unsigned long flags;
+       int pmp, i;
+       struct ahci_em_priv *emp;
+       u32 sgpio_out;
+
+       /* get the slot number from the message */
+       pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
+       if (pmp < EM_MAX_SLOTS)
+               emp = &pp->em_priv[pmp];
+       else
+               return -EINVAL;
+
+       if (!(hpriv->em_msg_type & EM_MSG_TYPE_LED))
+               return size;
+
+       spin_lock_irqsave(&sgpio_lock, flags);
+       ecx_parse_sgpio(pdata, ap->port_no, state);
+       sgpio_out = pdata->sgpio_pattern;
+       gpio_set_value(pdata->sgpio_gpio[SLOAD], 1);
+       ecx_led_cycle_clock(pdata);
+       gpio_set_value(pdata->sgpio_gpio[SLOAD], 0);
+       /*
+        * bit-bang out the SGPIO pattern, by consuming a bit and then
+        * clocking it out.
+        */
+       for (i = 0; i < (SGPIO_SIGNALS * pdata->n_ports); i++) {
+               gpio_set_value(pdata->sgpio_gpio[SDATA], sgpio_out & 1);
+               sgpio_out >>= 1;
+               ecx_led_cycle_clock(pdata);
+       }
+
+       /* save off new led state for port/slot */
+       emp->led_state = state;
+
+       spin_unlock_irqrestore(&sgpio_lock, flags);
+       return size;
+}
+
+static void highbank_set_em_messages(struct device *dev,
+                                       struct ahci_host_priv *hpriv,
+                                       struct ata_port_info *pi)
+{
+       struct device_node *np = dev->of_node;
+       struct ecx_plat_data *pdata = hpriv->plat_data;
+       int i;
+       int err;
+
+       for (i = 0; i < SGPIO_PINS; i++) {
+               err = of_get_named_gpio(np, "calxeda,sgpio-gpio", i);
+               if (IS_ERR_VALUE(err))
+                       return;
+
+               pdata->sgpio_gpio[i] = err;
+               err = gpio_request(pdata->sgpio_gpio[i], "CX SGPIO");
+               if (err) {
+                       pr_err("sata_highbank gpio_request %d failed: %d\n",
+                                       i, err);
+                       return;
+               }
+               gpio_direction_output(pdata->sgpio_gpio[i], 1);
+       }
+       of_property_read_u32_array(np, "calxeda,led-order",
+                                               pdata->port_to_sgpio,
+                                               pdata->n_ports);
+
+       /* store em_loc */
+       hpriv->em_loc = 0;
+       hpriv->em_buf_sz = 4;
+       hpriv->em_msg_type = EM_MSG_TYPE_LED;
+       pi->flags |= ATA_FLAG_EM | ATA_FLAG_SW_ACTIVITY;
+}
+
 static u32 __combo_phy_reg_read(u8 sata_port, u32 addr)
 {
        u32 data;
@@ -196,10 +339,26 @@ static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
        return 0;
 }
 
+/*
+ * The Calxeda SATA phy intermittently fails to bring up a link with Gen3
+ * Retrying the phy hard reset can work around the issue, but the drive
+ * may fail again. In less than 150 out of 15000 test runs, it took more
+ * than 10 tries for the link to be established (but never more than 35).
+ * Triple the maximum observed retry count to provide plenty of margin for
+ * rare events and to guarantee that the link is established.
+ *
+ * Also, the default 2 second time-out on a failed drive is too long in
+ * this situation. The uboot implementation of the same driver function
+ * uses a much shorter time-out period and never experiences a time out
+ * issue. Reducing the time-out to 500ms improves the responsiveness.
+ * The other timing constants were kept the same as the stock AHCI driver.
+ * This change was also tested 15000 times on 24 drives and none of them
+ * experienced a time out.
+ */
 static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
                                unsigned long deadline)
 {
-       const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+       static const unsigned long timing[] = { 5, 100, 500};
        struct ata_port *ap = link->ap;
        struct ahci_port_priv *pp = ap->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
@@ -207,7 +366,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
        bool online;
        u32 sstatus;
        int rc;
-       int retry = 10;
+       int retry = 100;
 
        ahci_stop_engine(ap);
 
@@ -241,6 +400,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
 static struct ata_port_operations ahci_highbank_ops = {
        .inherits               = &ahci_ops,
        .hardreset              = ahci_highbank_hardreset,
+       .transmit_led_message   = ecx_transmit_led_message,
 };
 
 static const struct ata_port_info ahci_highbank_port_info = {
@@ -264,12 +424,13 @@ static int ahci_highbank_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct ahci_host_priv *hpriv;
+       struct ecx_plat_data *pdata;
        struct ata_host *host;
        struct resource *mem;
        int irq;
-       int n_ports;
        int i;
        int rc;
+       u32 n_ports;
        struct ata_port_info pi = ahci_highbank_port_info;
        const struct ata_port_info *ppi[] = { &pi, NULL };
 
@@ -290,6 +451,11 @@ static int ahci_highbank_probe(struct platform_device *pdev)
                dev_err(dev, "can't alloc ahci_host_priv\n");
                return -ENOMEM;
        }
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               dev_err(dev, "can't alloc ecx_plat_data\n");
+               return -ENOMEM;
+       }
 
        hpriv->flags |= (unsigned long)pi.private_data;
 
@@ -313,8 +479,6 @@ static int ahci_highbank_probe(struct platform_device *pdev)
        if (hpriv->cap & HOST_CAP_PMP)
                pi.flags |= ATA_FLAG_PMP;
 
-       ahci_set_em_messages(hpriv, &pi);
-
        /* CAP.NP sometimes indicate the index of the last enabled
         * port, at other times, that of the last possible port, so
         * determining the maximum port number requires looking at
@@ -322,6 +486,10 @@ static int ahci_highbank_probe(struct platform_device *pdev)
         */
        n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
 
+       pdata->n_ports = n_ports;
+       hpriv->plat_data = pdata;
+       highbank_set_em_messages(dev, hpriv, &pi);
+
        host = ata_host_alloc_pinfo(dev, ppi, n_ports);
        if (!host) {
                rc = -ENOMEM;
@@ -333,9 +501,6 @@ static int ahci_highbank_probe(struct platform_device *pdev)
        if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
                host->flags |= ATA_HOST_PARALLEL_SCAN;
 
-       if (pi.flags & ATA_FLAG_EM)
-               ahci_reset_em(host);
-
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
 
index 1e6827c89429d4bd79b422745d23faf6d8407d9f..e4513174824830fa67d3e000ec97a449245fb0c8 100644 (file)
@@ -776,7 +776,7 @@ static int init_controller(void __iomem *mmio_base, u16 hctl)
 #ifdef CONFIG_PM
 static int inic_pci_device_resume(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        struct inic_host_priv *hpriv = host->private_data;
        int rc;
 
index 85ee4993ca74c8fa90d8287fcc1010d246bd57cd..d74def823d3ed865be0841d771fb7141ac1c1a07 100644 (file)
@@ -2435,7 +2435,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 #ifdef CONFIG_PM
 static int nv_pci_device_resume(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        struct nv_host_priv *hpriv = host->private_data;
        int rc;
 
index 249c8a289bfd5dbb97f25fbcbd99ff241ac40c21..8108eb0654448f8eba16da40e4aace400ff8087a 100644 (file)
 /* Descriptor table word 0 bit (when DTA32M = 1) */
 #define SATA_RCAR_DTEND                        BIT(0)
 
+#define SATA_RCAR_DMA_BOUNDARY         0x1FFFFFFEUL
+
 struct sata_rcar_priv {
        void __iomem *base;
        struct clk *clk;
@@ -128,41 +130,44 @@ struct sata_rcar_priv {
 
 static void sata_rcar_phy_initialize(struct sata_rcar_priv *priv)
 {
+       void __iomem *base = priv->base;
+
        /* idle state */
-       iowrite32(0, priv->base + SATAPHYADDR_REG);
+       iowrite32(0, base + SATAPHYADDR_REG);
        /* reset */
-       iowrite32(SATAPHYRESET_PHYRST, priv->base + SATAPHYRESET_REG);
+       iowrite32(SATAPHYRESET_PHYRST, base + SATAPHYRESET_REG);
        udelay(10);
        /* deassert reset */
-       iowrite32(0, priv->base + SATAPHYRESET_REG);
+       iowrite32(0, base + SATAPHYRESET_REG);
 }
 
 static void sata_rcar_phy_write(struct sata_rcar_priv *priv, u16 reg, u32 val,
                                int group)
 {
+       void __iomem *base = priv->base;
        int timeout;
 
        /* deassert reset */
-       iowrite32(0, priv->base + SATAPHYRESET_REG);
+       iowrite32(0, base + SATAPHYRESET_REG);
        /* lane 1 */
-       iowrite32(SATAPHYACCEN_PHYLANE, priv->base + SATAPHYACCEN_REG);
+       iowrite32(SATAPHYACCEN_PHYLANE, base + SATAPHYACCEN_REG);
        /* write phy register value */
-       iowrite32(val, priv->base + SATAPHYWDATA_REG);
+       iowrite32(val, base + SATAPHYWDATA_REG);
        /* set register group */
        if (group)
                reg |= SATAPHYADDR_PHYRATEMODE;
        /* write command */
-       iowrite32(SATAPHYADDR_PHYCMD_WRITE | reg, priv->base + SATAPHYADDR_REG);
+       iowrite32(SATAPHYADDR_PHYCMD_WRITE | reg, base + SATAPHYADDR_REG);
        /* wait for ack */
        for (timeout = 0; timeout < 100; timeout++) {
-               val = ioread32(priv->base + SATAPHYACK_REG);
+               val = ioread32(base + SATAPHYACK_REG);
                if (val & SATAPHYACK_PHYACK)
                        break;
        }
        if (timeout >= 100)
                pr_err("%s timeout\n", __func__);
        /* idle state */
-       iowrite32(0, priv->base + SATAPHYADDR_REG);
+       iowrite32(0, base + SATAPHYADDR_REG);
 }
 
 static void sata_rcar_freeze(struct ata_port *ap)
@@ -178,14 +183,15 @@ static void sata_rcar_freeze(struct ata_port *ap)
 static void sata_rcar_thaw(struct ata_port *ap)
 {
        struct sata_rcar_priv *priv = ap->host->private_data;
+       void __iomem *base = priv->base;
 
        /* ack */
-       iowrite32(~SATA_RCAR_INT_MASK, priv->base + SATAINTSTAT_REG);
+       iowrite32(~(u32)SATA_RCAR_INT_MASK, base + SATAINTSTAT_REG);
 
        ata_sff_thaw(ap);
 
        /* unmask */
-       iowrite32(0x7ff & ~SATA_RCAR_INT_MASK, priv->base + SATAINTMASK_REG);
+       iowrite32(0x7ff & ~SATA_RCAR_INT_MASK, base + SATAINTMASK_REG);
 }
 
 static void sata_rcar_ioread16_rep(void __iomem *reg, void *buffer, int count)
@@ -474,11 +480,10 @@ static void sata_rcar_bmdma_fill_sg(struct ata_queued_cmd *qc)
        struct ata_port *ap = qc->ap;
        struct ata_bmdma_prd *prd = ap->bmdma_prd;
        struct scatterlist *sg;
-       unsigned int si, pi;
+       unsigned int si;
 
-       pi = 0;
        for_each_sg(qc->sg, sg, qc->n_elem, si) {
-               u32 addr, sg_len, len;
+               u32 addr, sg_len;
 
                /*
                 * Note: h/w doesn't support 64-bit, so we unconditionally
@@ -487,24 +492,13 @@ static void sata_rcar_bmdma_fill_sg(struct ata_queued_cmd *qc)
                addr = (u32)sg_dma_address(sg);
                sg_len = sg_dma_len(sg);
 
-               /* H/w transfer count is only 29 bits long, let's be careful */
-               while (sg_len) {
-                       len = sg_len;
-                       if (len > 0x1ffffffe)
-                               len = 0x1ffffffe;
-
-                       prd[pi].addr = cpu_to_le32(addr);
-                       prd[pi].flags_len = cpu_to_le32(len);
-                       VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
-
-                       pi++;
-                       sg_len -= len;
-                       addr += len;
-               }
+               prd[si].addr = cpu_to_le32(addr);
+               prd[si].flags_len = cpu_to_le32(sg_len);
+               VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", si, addr, sg_len);
        }
 
        /* end-of-table flag */
-       prd[pi - 1].addr |= cpu_to_le32(SATA_RCAR_DTEND);
+       prd[si - 1].addr |= cpu_to_le32(SATA_RCAR_DTEND);
 }
 
 static void sata_rcar_qc_prep(struct ata_queued_cmd *qc)
@@ -519,15 +513,16 @@ static void sata_rcar_bmdma_setup(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        unsigned int rw = qc->tf.flags & ATA_TFLAG_WRITE;
-       u32 dmactl;
        struct sata_rcar_priv *priv = ap->host->private_data;
+       void __iomem *base = priv->base;
+       u32 dmactl;
 
        /* load PRD table addr. */
        mb();   /* make sure PRD table writes are visible to controller */
-       iowrite32(ap->bmdma_prd_dma, priv->base + ATAPI_DTB_ADR_REG);
+       iowrite32(ap->bmdma_prd_dma, base + ATAPI_DTB_ADR_REG);
 
        /* specify data direction, triple-check start bit is clear */
-       dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+       dmactl = ioread32(base + ATAPI_CONTROL1_REG);
        dmactl &= ~(ATAPI_CONTROL1_RW | ATAPI_CONTROL1_STOP);
        if (dmactl & ATAPI_CONTROL1_START) {
                dmactl &= ~ATAPI_CONTROL1_START;
@@ -535,7 +530,7 @@ static void sata_rcar_bmdma_setup(struct ata_queued_cmd *qc)
        }
        if (!rw)
                dmactl |= ATAPI_CONTROL1_RW;
-       iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG);
+       iowrite32(dmactl, base + ATAPI_CONTROL1_REG);
 
        /* issue r/w command */
        ap->ops->sff_exec_command(ap, &qc->tf);
@@ -544,28 +539,30 @@ static void sata_rcar_bmdma_setup(struct ata_queued_cmd *qc)
 static void sata_rcar_bmdma_start(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       u32 dmactl;
        struct sata_rcar_priv *priv = ap->host->private_data;
+       void __iomem *base = priv->base;
+       u32 dmactl;
 
        /* start host DMA transaction */
-       dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+       dmactl = ioread32(base + ATAPI_CONTROL1_REG);
        dmactl &= ~ATAPI_CONTROL1_STOP;
        dmactl |= ATAPI_CONTROL1_START;
-       iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG);
+       iowrite32(dmactl, base + ATAPI_CONTROL1_REG);
 }
 
 static void sata_rcar_bmdma_stop(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct sata_rcar_priv *priv = ap->host->private_data;
+       void __iomem *base = priv->base;
        u32 dmactl;
 
        /* force termination of DMA transfer if active */
-       dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+       dmactl = ioread32(base + ATAPI_CONTROL1_REG);
        if (dmactl & ATAPI_CONTROL1_START) {
                dmactl &= ~ATAPI_CONTROL1_START;
                dmactl |= ATAPI_CONTROL1_STOP;
-               iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG);
+               iowrite32(dmactl, base + ATAPI_CONTROL1_REG);
        }
 
        /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
@@ -575,8 +572,8 @@ static void sata_rcar_bmdma_stop(struct ata_queued_cmd *qc)
 static u8 sata_rcar_bmdma_status(struct ata_port *ap)
 {
        struct sata_rcar_priv *priv = ap->host->private_data;
-       u32 status;
        u8 host_stat = 0;
+       u32 status;
 
        status = ioread32(priv->base + ATAPI_STATUS_REG);
        if (status & ATAPI_STATUS_DEVINT)
@@ -588,7 +585,14 @@ static u8 sata_rcar_bmdma_status(struct ata_port *ap)
 }
 
 static struct scsi_host_template sata_rcar_sht = {
-       ATA_BMDMA_SHT(DRV_NAME),
+       ATA_BASE_SHT(DRV_NAME),
+       /*
+        * This controller allows transfer chunks up to 512MB which cross 64KB
+        * boundaries, therefore the DMA limits are more relaxed than standard
+        * ATA SFF.
+        */
+       .sg_tablesize           = ATA_MAX_PRD,
+       .dma_boundary           = SATA_RCAR_DMA_BOUNDARY,
 };
 
 static struct ata_port_operations sata_rcar_port_ops = {
@@ -668,19 +672,20 @@ static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance)
 {
        struct ata_host *host = dev_instance;
        struct sata_rcar_priv *priv = host->private_data;
-       struct ata_port *ap;
+       void __iomem *base = priv->base;
        unsigned int handled = 0;
+       struct ata_port *ap;
        u32 sataintstat;
        unsigned long flags;
 
        spin_lock_irqsave(&host->lock, flags);
 
-       sataintstat = ioread32(priv->base + SATAINTSTAT_REG);
+       sataintstat = ioread32(base + SATAINTSTAT_REG);
        sataintstat &= SATA_RCAR_INT_MASK;
        if (!sataintstat)
                goto done;
        /* ack */
-       iowrite32(~sataintstat & 0x7ff, priv->base + SATAINTSTAT_REG);
+       iowrite32(~sataintstat & 0x7ff, base + SATAINTSTAT_REG);
 
        ap = host->ports[0];
 
@@ -702,15 +707,16 @@ static void sata_rcar_setup_port(struct ata_host *host)
        struct ata_port *ap = host->ports[0];
        struct ata_ioports *ioaddr = &ap->ioaddr;
        struct sata_rcar_priv *priv = host->private_data;
+       void __iomem *base = priv->base;
 
        ap->ops         = &sata_rcar_port_ops;
        ap->pio_mask    = ATA_PIO4;
        ap->udma_mask   = ATA_UDMA6;
        ap->flags       |= ATA_FLAG_SATA;
 
-       ioaddr->cmd_addr = priv->base + SDATA_REG;
-       ioaddr->ctl_addr = priv->base + SSDEVCON_REG;
-       ioaddr->scr_addr = priv->base + SCRSSTS_REG;
+       ioaddr->cmd_addr = base + SDATA_REG;
+       ioaddr->ctl_addr = base + SSDEVCON_REG;
+       ioaddr->scr_addr = base + SCRSSTS_REG;
        ioaddr->altstatus_addr = ioaddr->ctl_addr;
 
        ioaddr->data_addr       = ioaddr->cmd_addr + (ATA_REG_DATA << 2);
@@ -728,6 +734,7 @@ static void sata_rcar_setup_port(struct ata_host *host)
 static void sata_rcar_init_controller(struct ata_host *host)
 {
        struct sata_rcar_priv *priv = host->private_data;
+       void __iomem *base = priv->base;
        u32 val;
 
        /* reset and setup phy */
@@ -740,27 +747,27 @@ static void sata_rcar_init_controller(struct ata_host *host)
        sata_rcar_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0);
 
        /* SATA-IP reset state */
-       val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+       val = ioread32(base + ATAPI_CONTROL1_REG);
        val |= ATAPI_CONTROL1_RESET;
-       iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+       iowrite32(val, base + ATAPI_CONTROL1_REG);
 
        /* ISM mode, PRD mode, DTEND flag at bit 0 */
-       val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+       val = ioread32(base + ATAPI_CONTROL1_REG);
        val |= ATAPI_CONTROL1_ISM;
        val |= ATAPI_CONTROL1_DESE;
        val |= ATAPI_CONTROL1_DTA32M;
-       iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+       iowrite32(val, base + ATAPI_CONTROL1_REG);
 
        /* Release the SATA-IP from the reset state */
-       val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+       val = ioread32(base + ATAPI_CONTROL1_REG);
        val &= ~ATAPI_CONTROL1_RESET;
-       iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+       iowrite32(val, base + ATAPI_CONTROL1_REG);
 
        /* ack and mask */
-       iowrite32(0, priv->base + SATAINTSTAT_REG);
-       iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+       iowrite32(0, base + SATAINTSTAT_REG);
+       iowrite32(0x7ff, base + SATAINTMASK_REG);
        /* enable interrupts */
-       iowrite32(ATAPI_INT_ENABLE_SATAINT, priv->base + ATAPI_INT_ENABLE_REG);
+       iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
 }
 
 static int sata_rcar_probe(struct platform_device *pdev)
@@ -825,16 +832,17 @@ cleanup:
 
 static int sata_rcar_remove(struct platform_device *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = platform_get_drvdata(pdev);
        struct sata_rcar_priv *priv = host->private_data;
+       void __iomem *base = priv->base;
 
        ata_host_detach(host);
 
        /* disable interrupts */
-       iowrite32(0, priv->base + ATAPI_INT_ENABLE_REG);
+       iowrite32(0, base + ATAPI_INT_ENABLE_REG);
        /* ack and mask */
-       iowrite32(0, priv->base + SATAINTSTAT_REG);
-       iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+       iowrite32(0, base + SATAINTSTAT_REG);
+       iowrite32(0x7ff, base + SATAINTMASK_REG);
 
        clk_disable(priv->clk);
 
@@ -846,14 +854,15 @@ static int sata_rcar_suspend(struct device *dev)
 {
        struct ata_host *host = dev_get_drvdata(dev);
        struct sata_rcar_priv *priv = host->private_data;
+       void __iomem *base = priv->base;
        int ret;
 
        ret = ata_host_suspend(host, PMSG_SUSPEND);
        if (!ret) {
                /* disable interrupts */
-               iowrite32(0, priv->base + ATAPI_INT_ENABLE_REG);
+               iowrite32(0, base + ATAPI_INT_ENABLE_REG);
                /* mask */
-               iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+               iowrite32(0x7ff, base + SATAINTMASK_REG);
 
                clk_disable(priv->clk);
        }
@@ -865,14 +874,15 @@ static int sata_rcar_resume(struct device *dev)
 {
        struct ata_host *host = dev_get_drvdata(dev);
        struct sata_rcar_priv *priv = host->private_data;
+       void __iomem *base = priv->base;
 
        clk_enable(priv->clk);
 
        /* ack and mask */
-       iowrite32(0, priv->base + SATAINTSTAT_REG);
-       iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+       iowrite32(0, base + SATAINTSTAT_REG);
+       iowrite32(0x7ff, base + SATAINTMASK_REG);
        /* enable interrupts */
-       iowrite32(ATAPI_INT_ENABLE_SATAINT, priv->base + ATAPI_INT_ENABLE_REG);
+       iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
 
        ata_host_resume(host);
 
index 0ae3ca4bf5c0a063077885f18e7375826a696c24..d67fc351343ca841f7ea95b68e401f52f58953c2 100644 (file)
@@ -805,7 +805,7 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 #ifdef CONFIG_PM
 static int sil_pci_device_resume(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        int rc;
 
        rc = ata_pci_device_do_resume(pdev);
index 59f0d630d634c7ff0c993f4780dbc7b55e682aff..aa1051ba6d1334885c9ac5272164e50a364dd6d8 100644 (file)
@@ -1353,7 +1353,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 #ifdef CONFIG_PM
 static int sil24_pci_device_resume(struct pci_dev *pdev)
 {
-       struct ata_host *host = dev_get_drvdata(&pdev->dev);
+       struct ata_host *host = pci_get_drvdata(pdev);
        void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
        int rc;
 
index d78b204e65c1728603384bb4f00f5e54f0601f69..ecc1929d7f6a943a086112ad5d61df8816fba8ad 100644 (file)
@@ -167,7 +167,7 @@ attribute_container_add_device(struct device *dev,
                ic->classdev.parent = get_device(dev);
                ic->classdev.class = cont->class;
                cont->class->dev_release = attribute_container_release;
-               dev_set_name(&ic->classdev, dev_name(dev));
+               dev_set_name(&ic->classdev, "%s", dev_name(dev));
                if (fn)
                        fn(cont, dev, &ic->classdev);
                else
index 6fdc53d46fa05ee244d46cd0787c55292c247b07..dc3ea237f086948ec5fe4a5ccd74bb47050fc336 100644 (file)
@@ -403,6 +403,36 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
 static struct device_attribute uevent_attr =
        __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
 
+static ssize_t show_online(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       bool val;
+
+       lock_device_hotplug();
+       val = !dev->offline;
+       unlock_device_hotplug();
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t store_online(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       bool val;
+       int ret;
+
+       ret = strtobool(buf, &val);
+       if (ret < 0)
+               return ret;
+
+       lock_device_hotplug();
+       ret = val ? device_online(dev) : device_offline(dev);
+       unlock_device_hotplug();
+       return ret < 0 ? ret : count;
+}
+
+static struct device_attribute online_attr =
+       __ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online);
+
 static int device_add_attributes(struct device *dev,
                                 struct device_attribute *attrs)
 {
@@ -516,6 +546,12 @@ static int device_add_attrs(struct device *dev)
        if (error)
                goto err_remove_type_groups;
 
+       if (device_supports_offline(dev) && !dev->offline_disabled) {
+               error = device_create_file(dev, &online_attr);
+               if (error)
+                       goto err_remove_type_groups;
+       }
+
        return 0;
 
  err_remove_type_groups:
@@ -536,6 +572,7 @@ static void device_remove_attrs(struct device *dev)
        struct class *class = dev->class;
        const struct device_type *type = dev->type;
 
+       device_remove_file(dev, &online_attr);
        device_remove_groups(dev, dev->groups);
 
        if (type)
@@ -1435,6 +1472,99 @@ EXPORT_SYMBOL_GPL(put_device);
 EXPORT_SYMBOL_GPL(device_create_file);
 EXPORT_SYMBOL_GPL(device_remove_file);
 
+static DEFINE_MUTEX(device_hotplug_lock);
+
+void lock_device_hotplug(void)
+{
+       mutex_lock(&device_hotplug_lock);
+}
+
+void unlock_device_hotplug(void)
+{
+       mutex_unlock(&device_hotplug_lock);
+}
+
+static int device_check_offline(struct device *dev, void *not_used)
+{
+       int ret;
+
+       ret = device_for_each_child(dev, NULL, device_check_offline);
+       if (ret)
+               return ret;
+
+       return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0;
+}
+
+/**
+ * device_offline - Prepare the device for hot-removal.
+ * @dev: Device to be put offline.
+ *
+ * Execute the device bus type's .offline() callback, if present, to prepare
+ * the device for a subsequent hot-removal.  If that succeeds, the device must
+ * not be used until either it is removed or its bus type's .online() callback
+ * is executed.
+ *
+ * Call under device_hotplug_lock.
+ */
+int device_offline(struct device *dev)
+{
+       int ret;
+
+       if (dev->offline_disabled)
+               return -EPERM;
+
+       ret = device_for_each_child(dev, NULL, device_check_offline);
+       if (ret)
+               return ret;
+
+       device_lock(dev);
+       if (device_supports_offline(dev)) {
+               if (dev->offline) {
+                       ret = 1;
+               } else {
+                       ret = dev->bus->offline(dev);
+                       if (!ret) {
+                               kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
+                               dev->offline = true;
+                       }
+               }
+       }
+       device_unlock(dev);
+
+       return ret;
+}
+
+/**
+ * device_online - Put the device back online after successful device_offline().
+ * @dev: Device to be put back online.
+ *
+ * If device_offline() has been successfully executed for @dev, but the device
+ * has not been removed subsequently, execute its bus type's .online() callback
+ * to indicate that the device can be used again.
+ *
+ * Call under device_hotplug_lock.
+ */
+int device_online(struct device *dev)
+{
+       int ret = 0;
+
+       device_lock(dev);
+       if (device_supports_offline(dev)) {
+               if (dev->offline) {
+                       ret = dev->bus->online(dev);
+                       if (!ret) {
+                               kobject_uevent(&dev->kobj, KOBJ_ONLINE);
+                               dev->offline = false;
+                       }
+               } else {
+                       ret = 1;
+               }
+       }
+       device_unlock(dev);
+
+       return ret;
+}
+
 struct root_device {
        struct device dev;
        struct module *owner;
index c377673320eda18e32c7eb25aa87e72e4deb12e6..a16d20e389f0f2fead522d97edee5f3c66bc9112 100644 (file)
 #include <linux/gfp.h>
 #include <linux/slab.h>
 #include <linux/percpu.h>
+#include <linux/acpi.h>
 
 #include "base.h"
 
-struct bus_type cpu_subsys = {
-       .name = "cpu",
-       .dev_name = "cpu",
-};
-EXPORT_SYMBOL_GPL(cpu_subsys);
-
 static DEFINE_PER_CPU(struct device *, cpu_sys_devices);
 
+static int cpu_subsys_match(struct device *dev, struct device_driver *drv)
+{
+       /* ACPI style match is the only one that may succeed. */
+       if (acpi_driver_match_device(dev, drv))
+               return 1;
+
+       return 0;
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 static void change_cpu_under_node(struct cpu *cpu,
                        unsigned int from_nid, unsigned int to_nid)
@@ -34,65 +38,38 @@ static void change_cpu_under_node(struct cpu *cpu,
        cpu->node_id = to_nid;
 }
 
-static ssize_t show_online(struct device *dev,
-                          struct device_attribute *attr,
-                          char *buf)
+static int __ref cpu_subsys_online(struct device *dev)
 {
        struct cpu *cpu = container_of(dev, struct cpu, dev);
+       int cpuid = dev->id;
+       int from_nid, to_nid;
+       int ret;
+
+       cpu_hotplug_driver_lock();
 
-       return sprintf(buf, "%u\n", !!cpu_online(cpu->dev.id));
+       from_nid = cpu_to_node(cpuid);
+       ret = cpu_up(cpuid);
+       /*
+        * When hot adding memory to memoryless node and enabling a cpu
+        * on the node, node number of the cpu may internally change.
+        */
+       to_nid = cpu_to_node(cpuid);
+       if (from_nid != to_nid)
+               change_cpu_under_node(cpu, from_nid, to_nid);
+
+       cpu_hotplug_driver_unlock();
+       return ret;
 }
 
-static ssize_t __ref store_online(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t count)
+static int cpu_subsys_offline(struct device *dev)
 {
-       struct cpu *cpu = container_of(dev, struct cpu, dev);
-       int cpuid = cpu->dev.id;
-       int from_nid, to_nid;
-       ssize_t ret;
+       int ret;
 
        cpu_hotplug_driver_lock();
-       switch (buf[0]) {
-       case '0':
-               ret = cpu_down(cpuid);
-               if (!ret)
-                       kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
-               break;
-       case '1':
-               from_nid = cpu_to_node(cpuid);
-               ret = cpu_up(cpuid);
-
-               /*
-                * When hot adding memory to memoryless node and enabling a cpu
-                * on the node, node number of the cpu may internally change.
-                */
-               to_nid = cpu_to_node(cpuid);
-               if (from_nid != to_nid)
-                       change_cpu_under_node(cpu, from_nid, to_nid);
-
-               if (!ret)
-                       kobject_uevent(&dev->kobj, KOBJ_ONLINE);
-               break;
-       default:
-               ret = -EINVAL;
-       }
+       ret = cpu_down(dev->id);
        cpu_hotplug_driver_unlock();
-
-       if (ret >= 0)
-               ret = count;
        return ret;
 }
-static DEVICE_ATTR(online, 0644, show_online, store_online);
-
-static struct attribute *hotplug_cpu_attrs[] = {
-       &dev_attr_online.attr,
-       NULL
-};
-
-static struct attribute_group hotplug_cpu_attr_group = {
-       .attrs = hotplug_cpu_attrs,
-};
 
 void unregister_cpu(struct cpu *cpu)
 {
@@ -127,6 +104,17 @@ static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store);
 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
 #endif /* CONFIG_HOTPLUG_CPU */
 
+struct bus_type cpu_subsys = {
+       .name = "cpu",
+       .dev_name = "cpu",
+       .match = cpu_subsys_match,
+#ifdef CONFIG_HOTPLUG_CPU
+       .online = cpu_subsys_online,
+       .offline = cpu_subsys_offline,
+#endif
+};
+EXPORT_SYMBOL_GPL(cpu_subsys);
+
 #ifdef CONFIG_KEXEC
 #include <linux/kexec.h>
 
@@ -184,9 +172,6 @@ static const struct attribute_group *common_cpu_attr_groups[] = {
 static const struct attribute_group *hotplugable_cpu_attr_groups[] = {
 #ifdef CONFIG_KEXEC
        &crash_note_cpu_attr_group,
-#endif
-#ifdef CONFIG_HOTPLUG_CPU
-       &hotplug_cpu_attr_group,
 #endif
        NULL
 };
@@ -302,6 +287,8 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
        cpu->dev.id = num;
        cpu->dev.bus = &cpu_subsys;
        cpu->dev.release = cpu_device_release;
+       cpu->dev.offline_disabled = !cpu->hotpluggable;
+       cpu->dev.offline = !cpu_online(num);
 #ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
        cpu->dev.bus->uevent = arch_cpu_uevent;
 #endif
index e315051cfeebbdb25a4420b7d3eaeb7d4d57b74f..2b7813ec6d02f31e842d181b61b01fa6be6f4b9d 100644 (file)
@@ -37,9 +37,14 @@ static inline int base_memory_block_id(int section_nr)
        return section_nr / sections_per_block;
 }
 
+static int memory_subsys_online(struct device *dev);
+static int memory_subsys_offline(struct device *dev);
+
 static struct bus_type memory_subsys = {
        .name = MEMORY_CLASS_NAME,
        .dev_name = MEMORY_CLASS_NAME,
+       .online = memory_subsys_online,
+       .offline = memory_subsys_offline,
 };
 
 static BLOCKING_NOTIFIER_HEAD(memory_chain);
@@ -262,33 +267,64 @@ static int __memory_block_change_state(struct memory_block *mem,
 {
        int ret = 0;
 
-       if (mem->state != from_state_req) {
-               ret = -EINVAL;
-               goto out;
-       }
+       if (mem->state != from_state_req)
+               return -EINVAL;
 
        if (to_state == MEM_OFFLINE)
                mem->state = MEM_GOING_OFFLINE;
 
        ret = memory_block_action(mem->start_section_nr, to_state, online_type);
+       mem->state = ret ? from_state_req : to_state;
+       return ret;
+}
 
-       if (ret) {
-               mem->state = from_state_req;
-               goto out;
-       }
+static int memory_subsys_online(struct device *dev)
+{
+       struct memory_block *mem = container_of(dev, struct memory_block, dev);
+       int ret;
 
-       mem->state = to_state;
-       switch (mem->state) {
-       case MEM_OFFLINE:
-               kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE);
-               break;
-       case MEM_ONLINE:
-               kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE);
-               break;
-       default:
-               break;
+       mutex_lock(&mem->state_mutex);
+
+       ret = mem->state == MEM_ONLINE ? 0 :
+               __memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE,
+                                           ONLINE_KEEP);
+
+       mutex_unlock(&mem->state_mutex);
+       return ret;
+}
+
+static int memory_subsys_offline(struct device *dev)
+{
+       struct memory_block *mem = container_of(dev, struct memory_block, dev);
+       int ret;
+
+       mutex_lock(&mem->state_mutex);
+
+       ret = mem->state == MEM_OFFLINE ? 0 :
+               __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1);
+
+       mutex_unlock(&mem->state_mutex);
+       return ret;
+}
+
+static int __memory_block_change_state_uevent(struct memory_block *mem,
+               unsigned long to_state, unsigned long from_state_req,
+               int online_type)
+{
+       int ret = __memory_block_change_state(mem, to_state, from_state_req,
+                                             online_type);
+       if (!ret) {
+               switch (mem->state) {
+               case MEM_OFFLINE:
+                       kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE);
+                       break;
+               case MEM_ONLINE:
+                       kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE);
+                       break;
+               default:
+                       break;
+               }
        }
-out:
        return ret;
 }
 
@@ -299,8 +335,8 @@ static int memory_block_change_state(struct memory_block *mem,
        int ret;
 
        mutex_lock(&mem->state_mutex);
-       ret = __memory_block_change_state(mem, to_state, from_state_req,
-                                         online_type);
+       ret = __memory_block_change_state_uevent(mem, to_state, from_state_req,
+                                                online_type);
        mutex_unlock(&mem->state_mutex);
 
        return ret;
@@ -310,22 +346,34 @@ store_mem_state(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
        struct memory_block *mem;
+       bool offline;
        int ret = -EINVAL;
 
        mem = container_of(dev, struct memory_block, dev);
 
-       if (!strncmp(buf, "online_kernel", min_t(int, count, 13)))
+       lock_device_hotplug();
+
+       if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) {
+               offline = false;
                ret = memory_block_change_state(mem, MEM_ONLINE,
                                                MEM_OFFLINE, ONLINE_KERNEL);
-       else if (!strncmp(buf, "online_movable", min_t(int, count, 14)))
+       } else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) {
+               offline = false;
                ret = memory_block_change_state(mem, MEM_ONLINE,
                                                MEM_OFFLINE, ONLINE_MOVABLE);
-       else if (!strncmp(buf, "online", min_t(int, count, 6)))
+       } else if (!strncmp(buf, "online", min_t(int, count, 6))) {
+               offline = false;
                ret = memory_block_change_state(mem, MEM_ONLINE,
                                                MEM_OFFLINE, ONLINE_KEEP);
-       else if(!strncmp(buf, "offline", min_t(int, count, 7)))
+       } else if(!strncmp(buf, "offline", min_t(int, count, 7))) {
+               offline = true;
                ret = memory_block_change_state(mem, MEM_OFFLINE,
                                                MEM_ONLINE, -1);
+       }
+       if (!ret)
+               dev->offline = offline;
+
+       unlock_device_hotplug();
 
        if (ret)
                return ret;
@@ -523,6 +571,7 @@ int register_memory(struct memory_block *memory)
        memory->dev.id = memory->start_section_nr / sections_per_block;
        memory->dev.release = memory_block_release;
        memory->dev.groups = memory_memblk_attr_groups;
+       memory->dev.offline = memory->state == MEM_OFFLINE;
 
        error = device_register(&memory->dev);
        return error;
@@ -646,21 +695,6 @@ int unregister_memory_section(struct mem_section *section)
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
-/*
- * offline one memory block. If the memory block has been offlined, do nothing.
- */
-int offline_memory_block(struct memory_block *mem)
-{
-       int ret = 0;
-
-       mutex_lock(&mem->state_mutex);
-       if (mem->state != MEM_OFFLINE)
-               ret = __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1);
-       mutex_unlock(&mem->state_mutex);
-
-       return ret;
-}
-
 /* return true if the memory block is offlined, otherwise, return false */
 bool is_memblock_offlined(struct memory_block *mem)
 {
index 67a274e8672703bc17bb57e96f3262b4effe184e..5fb74b43848e21369670b4503fdee13b0d4f255e 100644 (file)
@@ -48,6 +48,25 @@ int pinctrl_bind_pins(struct device *dev)
                goto cleanup_get;
        }
 
+#ifdef CONFIG_PM
+       /*
+        * If power management is enabled, we also look for the optional
+        * sleep and idle pin states, with semantics as defined in
+        * <linux/pinctrl/pinctrl-state.h>
+        */
+       dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p,
+                                       PINCTRL_STATE_SLEEP);
+       if (IS_ERR(dev->pins->sleep_state))
+               /* Not supplying this state is perfectly legal */
+               dev_dbg(dev, "no sleep pinctrl state\n");
+
+       dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p,
+                                       PINCTRL_STATE_IDLE);
+       if (IS_ERR(dev->pins->idle_state))
+               /* Not supplying this state is perfectly legal */
+               dev_dbg(dev, "no idle pinctrl state\n");
+#endif
+
        return 0;
 
        /*
index ed75cf6ef9c9f121c50cb96c3ec9ea6bf4174b48..6eaa7ab9e4bc6199c4fe9ce49b30a85068c78fe7 100644 (file)
@@ -890,7 +890,6 @@ int platform_pm_restore(struct device *dev)
 static const struct dev_pm_ops platform_dev_pm_ops = {
        .runtime_suspend = pm_generic_runtime_suspend,
        .runtime_resume = pm_generic_runtime_resume,
-       .runtime_idle = pm_generic_runtime_idle,
        USE_PLATFORM_PM_SLEEP_OPS
 };
 
index 7072404c8b6da6ddb7ba6633cab5da087e49868e..bfb8955c406c5ef02d819d4d5fa02d709f0a6ec0 100644 (file)
@@ -2143,7 +2143,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
        genpd->max_off_time_changed = true;
        genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
        genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
-       genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
        genpd->domain.ops.prepare = pm_genpd_prepare;
        genpd->domain.ops.suspend = pm_genpd_suspend;
        genpd->domain.ops.suspend_late = pm_genpd_suspend_late;
index bfd898b8988e37ca0dcc985fc28c57fdcde27fa0..5ee030a864f9266bb6c8ea18dd897e736fd2727c 100644 (file)
 #include <linux/export.h>
 
 #ifdef CONFIG_PM_RUNTIME
-/**
- * pm_generic_runtime_idle - Generic runtime idle callback for subsystems.
- * @dev: Device to handle.
- *
- * If PM operations are defined for the @dev's driver and they include
- * ->runtime_idle(), execute it and return its error code, if nonzero.
- * Otherwise, execute pm_runtime_suspend() for the device and return 0.
- */
-int pm_generic_runtime_idle(struct device *dev)
-{
-       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
-       if (pm && pm->runtime_idle) {
-               int ret = pm->runtime_idle(dev);
-               if (ret)
-                       return ret;
-       }
-
-       pm_runtime_suspend(dev);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(pm_generic_runtime_idle);
-
 /**
  * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems.
  * @dev: Device to suspend.
index f0077cb8e249e5f0fac3ef302d9a1ded177a479b..c8ec186303db29308f1091db8d5a2bcff01dc53c 100644 (file)
@@ -648,14 +648,14 @@ int opp_init_cpufreq_table(struct device *dev,
 
        list_for_each_entry(opp, &dev_opp->opp_list, node) {
                if (opp->available) {
-                       freq_table[i].index = i;
+                       freq_table[i].driver_data = i;
                        freq_table[i].frequency = opp->rate / 1000;
                        i++;
                }
        }
        mutex_unlock(&dev_opp_list_lock);
 
-       freq_table[i].index = i;
+       freq_table[i].driver_data = i;
        freq_table[i].frequency = CPUFREQ_TABLE_END;
 
        *table = &freq_table[0];
index 71671c42ef457e3486f13b770114a0c09459a708..5c1361a9e5dd58049c3835d414f42607cdb46411 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/export.h>
 #include <linux/pm_runtime.h>
 #include <linux/err.h>
+#include <trace/events/power.h>
 
 #include "power.h"
 
@@ -305,6 +306,7 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
        else if (!dev->power.qos)
                ret = dev_pm_qos_constraints_allocate(dev);
 
+       trace_dev_pm_qos_add_request(dev_name(dev), type, value);
        if (!ret) {
                req->dev = dev;
                req->type = type;
@@ -349,6 +351,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
                return -EINVAL;
        }
 
+       trace_dev_pm_qos_update_request(dev_name(req->dev), req->type,
+                                       new_value);
        if (curr_value != new_value)
                ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);
 
@@ -398,6 +402,8 @@ static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
        if (IS_ERR_OR_NULL(req->dev->power.qos))
                return -ENODEV;
 
+       trace_dev_pm_qos_remove_request(dev_name(req->dev), req->type,
+                                       PM_QOS_DEFAULT_VALUE);
        ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
        memset(req, 0, sizeof(*req));
        return ret;
index ef13ad08afb2cf845340bb28463ad3df63e5b04b..268a35097578d94f78f4baef4d9cc8b3fa1c31cd 100644 (file)
@@ -293,11 +293,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
        /* Pending requests need to be canceled. */
        dev->power.request = RPM_REQ_NONE;
 
-       if (dev->power.no_callbacks) {
-               /* Assume ->runtime_idle() callback would have suspended. */
-               retval = rpm_suspend(dev, rpmflags);
+       if (dev->power.no_callbacks)
                goto out;
-       }
 
        /* Carry out an asynchronous or a synchronous idle notification. */
        if (rpmflags & RPM_ASYNC) {
@@ -306,7 +303,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
                        dev->power.request_pending = true;
                        queue_work(pm_wq, &dev->power.work);
                }
-               goto out;
+               trace_rpm_return_int(dev, _THIS_IP_, 0);
+               return 0;
        }
 
        dev->power.idle_notification = true;
@@ -326,14 +324,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
                callback = dev->driver->pm->runtime_idle;
 
        if (callback)
-               __rpm_callback(callback, dev);
+               retval = __rpm_callback(callback, dev);
 
        dev->power.idle_notification = false;
        wake_up_all(&dev->power.wait_queue);
 
  out:
        trace_rpm_return_int(dev, _THIS_IP_, retval);
-       return retval;
+       return retval ? retval : rpm_suspend(dev, rpmflags);
 }
 
 /**
index 79715e7fa43e34c9cbf9a4521a657d7bb952f9c6..2d56f4113ae761a406fca80c8d39c892ae4b2416 100644 (file)
@@ -659,7 +659,7 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
 }
 EXPORT_SYMBOL_GPL(pm_wakeup_event);
 
-static void print_active_wakeup_sources(void)
+void pm_print_active_wakeup_sources(void)
 {
        struct wakeup_source *ws;
        int active = 0;
@@ -683,6 +683,7 @@ static void print_active_wakeup_sources(void)
                        last_activity_ws->name);
        rcu_read_unlock();
 }
+EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources);
 
 /**
  * pm_wakeup_pending - Check if power transition in progress should be aborted.
@@ -707,8 +708,10 @@ bool pm_wakeup_pending(void)
        }
        spin_unlock_irqrestore(&events_lock, flags);
 
-       if (ret)
-               print_active_wakeup_sources();
+       if (ret) {
+               pr_info("PM: Wakeup pending, aborting suspend\n");
+               pm_print_active_wakeup_sources();
+       }
 
        return ret;
 }
index c130536e0ab0626866a41dd23f35d2c260bb9980..29c83160ca29511adf7fe8c9ca9d77fe353a0781 100644 (file)
@@ -52,6 +52,7 @@ struct regmap_async {
 struct regmap {
        struct mutex mutex;
        spinlock_t spinlock;
+       unsigned long spinlock_flags;
        regmap_lock lock;
        regmap_unlock unlock;
        void *lock_arg; /* This is passed to lock/unlock functions */
@@ -148,6 +149,7 @@ struct regcache_ops {
        int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
        int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
        int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
+       int (*drop)(struct regmap *map, unsigned int min, unsigned int max);
 };
 
 bool regmap_writeable(struct regmap *map, unsigned int reg);
@@ -174,6 +176,14 @@ struct regmap_range_node {
        unsigned int window_len;
 };
 
+struct regmap_field {
+       struct regmap *regmap;
+       unsigned int mask;
+       /* lsb */
+       unsigned int shift;
+       unsigned int reg;
+};
+
 #ifdef CONFIG_DEBUG_FS
 extern void regmap_debugfs_initcall(void);
 extern void regmap_debugfs_init(struct regmap *map, const char *name);
index 02f490bad30f791f627db78584ca75b691bc6eb7..5c1435c4e210c9311e01e92e9a0039ec89df2bdb 100644 (file)
@@ -304,6 +304,48 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
        return 0;
 }
 
+static struct regcache_rbtree_node *
+regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
+{
+       struct regcache_rbtree_node *rbnode;
+       const struct regmap_range *range;
+       int i;
+
+       rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL);
+       if (!rbnode)
+               return NULL;
+
+       /* If there is a read table then use it to guess at an allocation */
+       if (map->rd_table) {
+               for (i = 0; i < map->rd_table->n_yes_ranges; i++) {
+                       if (regmap_reg_in_range(reg,
+                                               &map->rd_table->yes_ranges[i]))
+                               break;
+               }
+
+               if (i != map->rd_table->n_yes_ranges) {
+                       range = &map->rd_table->yes_ranges[i];
+                       rbnode->blklen = range->range_max - range->range_min
+                               + 1;
+                       rbnode->base_reg = range->range_min;
+               }
+       }
+
+       if (!rbnode->blklen) {
+               rbnode->blklen = sizeof(*rbnode);
+               rbnode->base_reg = reg;
+       }
+
+       rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
+                               GFP_KERNEL);
+       if (!rbnode->block) {
+               kfree(rbnode);
+               return NULL;
+       }
+
+       return rbnode;
+}
+
 static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
                                 unsigned int value)
 {
@@ -354,23 +396,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
                                return 0;
                        }
                }
-               /* we did not manage to find a place to insert it in an existing
-                * block so create a new rbnode with a single register in its block.
-                * This block will get populated further if any other adjacent
-                * registers get modified in the future.
+
+               /* We did not manage to find a place to insert it in
+                * an existing block so create a new rbnode.
                 */
-               rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
+               rbnode = regcache_rbtree_node_alloc(map, reg);
                if (!rbnode)
                        return -ENOMEM;
-               rbnode->blklen = sizeof(*rbnode);
-               rbnode->base_reg = reg;
-               rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
-                                       GFP_KERNEL);
-               if (!rbnode->block) {
-                       kfree(rbnode);
-                       return -ENOMEM;
-               }
-               regcache_rbtree_set_register(map, rbnode, 0, value);
+               regcache_rbtree_set_register(map, rbnode,
+                                            reg - rbnode->base_reg, value);
                regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
                rbtree_ctx->cached_rbnode = rbnode;
        }
index 507ee2da0f6ee9b6455ab967f2dcf76a49c57b02..e69102696533e7224b74a1237f64c478eeb2ab18 100644 (file)
@@ -250,6 +250,38 @@ int regcache_write(struct regmap *map,
        return 0;
 }
 
+static int regcache_default_sync(struct regmap *map, unsigned int min,
+                                unsigned int max)
+{
+       unsigned int reg;
+
+       for (reg = min; reg <= max; reg++) {
+               unsigned int val;
+               int ret;
+
+               if (regmap_volatile(map, reg))
+                       continue;
+
+               ret = regcache_read(map, reg, &val);
+               if (ret)
+                       return ret;
+
+               /* Is this the hardware default?  If so skip. */
+               ret = regcache_lookup_reg(map, reg);
+               if (ret >= 0 && val == map->reg_defaults[ret].def)
+                       continue;
+
+               map->cache_bypass = 1;
+               ret = _regmap_write(map, reg, val);
+               map->cache_bypass = 0;
+               if (ret)
+                       return ret;
+               dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val);
+       }
+
+       return 0;
+}
+
 /**
  * regcache_sync: Sync the register cache with the hardware.
  *
@@ -268,7 +300,7 @@ int regcache_sync(struct regmap *map)
        const char *name;
        unsigned int bypass;
 
-       BUG_ON(!map->cache_ops || !map->cache_ops->sync);
+       BUG_ON(!map->cache_ops);
 
        map->lock(map->lock_arg);
        /* Remember the initial bypass state */
@@ -297,7 +329,10 @@ int regcache_sync(struct regmap *map)
        }
        map->cache_bypass = 0;
 
-       ret = map->cache_ops->sync(map, 0, map->max_register);
+       if (map->cache_ops->sync)
+               ret = map->cache_ops->sync(map, 0, map->max_register);
+       else
+               ret = regcache_default_sync(map, 0, map->max_register);
 
        if (ret == 0)
                map->cache_dirty = false;
@@ -331,7 +366,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
        const char *name;
        unsigned int bypass;
 
-       BUG_ON(!map->cache_ops || !map->cache_ops->sync);
+       BUG_ON(!map->cache_ops);
 
        map->lock(map->lock_arg);
 
@@ -346,7 +381,10 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
        if (!map->cache_dirty)
                goto out;
 
-       ret = map->cache_ops->sync(map, min, max);
+       if (map->cache_ops->sync)
+               ret = map->cache_ops->sync(map, min, max);
+       else
+               ret = regcache_default_sync(map, min, max);
 
 out:
        trace_regcache_sync(map->dev, name, "stop region");
@@ -358,6 +396,43 @@ out:
 }
 EXPORT_SYMBOL_GPL(regcache_sync_region);
 
+/**
+ * regcache_drop_region: Discard part of the register cache
+ *
+ * @map: map to operate on
+ * @min: first register to discard
+ * @max: last register to discard
+ *
+ * Discard part of the register cache.
+ *
+ * Return a negative value on failure, 0 on success.
+ */
+int regcache_drop_region(struct regmap *map, unsigned int min,
+                        unsigned int max)
+{
+       unsigned int reg;
+       int ret = 0;
+
+       if (!map->cache_present && !(map->cache_ops && map->cache_ops->drop))
+               return -EINVAL;
+
+       map->lock(map->lock_arg);
+
+       trace_regcache_drop_region(map->dev, min, max);
+
+       if (map->cache_present)
+               for (reg = min; reg < max + 1; reg++)
+                       clear_bit(reg, map->cache_present);
+
+       if (map->cache_ops && map->cache_ops->drop)
+               ret = map->cache_ops->drop(map, min, max);
+
+       map->unlock(map->lock_arg);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regcache_drop_region);
+
 /**
  * regcache_cache_only: Put a register map into cache only mode
  *
index 975719bc345008a4d396c72b5b1e160c50b8d2a8..53495753fbdb64849f3d14fa0094b045fff39acb 100644 (file)
@@ -84,6 +84,10 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
        unsigned int fpos_offset;
        unsigned int reg_offset;
 
+       /* Suppress the cache if we're using a subrange */
+       if (from)
+               return from;
+
        /*
         * If we don't have a cache build one so we don't have to do a
         * linear scan each time.
@@ -145,7 +149,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
                        reg_offset = fpos_offset / map->debugfs_tot_len;
                        *pos = c->min + (reg_offset * map->debugfs_tot_len);
                        mutex_unlock(&map->cache_lock);
-                       return c->base_reg + reg_offset;
+                       return c->base_reg + (reg_offset * map->reg_stride);
                }
 
                *pos = c->max;
@@ -281,7 +285,7 @@ static ssize_t regmap_map_write_file(struct file *file,
                return -EINVAL;
 
        /* Userspace has been fiddling around behind the kernel's back */
-       add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE);
+       add_taint(TAINT_USER, LOCKDEP_STILL_OK);
 
        ret = regmap_write(map, reg, value);
        if (ret < 0)
index a941dcfe7590119f7f1cc1b4a69574ea3d47b9b6..95920583e31e6dfb5cd0ad18cd9a599e9e34e155 100644 (file)
@@ -65,9 +65,8 @@ bool regmap_reg_in_ranges(unsigned int reg,
 }
 EXPORT_SYMBOL_GPL(regmap_reg_in_ranges);
 
-static bool _regmap_check_range_table(struct regmap *map,
-                                     unsigned int reg,
-                                     const struct regmap_access_table *table)
+bool regmap_check_range_table(struct regmap *map, unsigned int reg,
+                             const struct regmap_access_table *table)
 {
        /* Check "no ranges" first */
        if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges))
@@ -80,6 +79,7 @@ static bool _regmap_check_range_table(struct regmap *map,
        return regmap_reg_in_ranges(reg, table->yes_ranges,
                                    table->n_yes_ranges);
 }
+EXPORT_SYMBOL_GPL(regmap_check_range_table);
 
 bool regmap_writeable(struct regmap *map, unsigned int reg)
 {
@@ -90,7 +90,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg)
                return map->writeable_reg(map->dev, reg);
 
        if (map->wr_table)
-               return _regmap_check_range_table(map, reg, map->wr_table);
+               return regmap_check_range_table(map, reg, map->wr_table);
 
        return true;
 }
@@ -107,7 +107,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
                return map->readable_reg(map->dev, reg);
 
        if (map->rd_table)
-               return _regmap_check_range_table(map, reg, map->rd_table);
+               return regmap_check_range_table(map, reg, map->rd_table);
 
        return true;
 }
@@ -121,9 +121,12 @@ bool regmap_volatile(struct regmap *map, unsigned int reg)
                return map->volatile_reg(map->dev, reg);
 
        if (map->volatile_table)
-               return _regmap_check_range_table(map, reg, map->volatile_table);
+               return regmap_check_range_table(map, reg, map->volatile_table);
 
-       return true;
+       if (map->cache_ops)
+               return false;
+       else
+               return true;
 }
 
 bool regmap_precious(struct regmap *map, unsigned int reg)
@@ -135,7 +138,7 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
                return map->precious_reg(map->dev, reg);
 
        if (map->precious_table)
-               return _regmap_check_range_table(map, reg, map->precious_table);
+               return regmap_check_range_table(map, reg, map->precious_table);
 
        return false;
 }
@@ -302,13 +305,16 @@ static void regmap_unlock_mutex(void *__map)
 static void regmap_lock_spinlock(void *__map)
 {
        struct regmap *map = __map;
-       spin_lock(&map->spinlock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&map->spinlock, flags);
+       map->spinlock_flags = flags;
 }
 
 static void regmap_unlock_spinlock(void *__map)
 {
        struct regmap *map = __map;
-       spin_unlock(&map->spinlock);
+       spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);
 }
 
 static void dev_get_regmap_release(struct device *dev, void *res)
@@ -801,6 +807,95 @@ struct regmap *devm_regmap_init(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_regmap_init);
 
+static void regmap_field_init(struct regmap_field *rm_field,
+       struct regmap *regmap, struct reg_field reg_field)
+{
+       int field_bits = reg_field.msb - reg_field.lsb + 1;
+       rm_field->regmap = regmap;
+       rm_field->reg = reg_field.reg;
+       rm_field->shift = reg_field.lsb;
+       rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb);
+}
+
+/**
+ * devm_regmap_field_alloc(): Allocate and initialise a register field
+ * in a register map.
+ *
+ * @dev: Device that will be interacted with
+ * @regmap: regmap bank in which this register field is located.
+ * @reg_field: Register field with in the bank.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap_field. The regmap_field will be automatically freed
+ * by the device management code.
+ */
+struct regmap_field *devm_regmap_field_alloc(struct device *dev,
+               struct regmap *regmap, struct reg_field reg_field)
+{
+       struct regmap_field *rm_field = devm_kzalloc(dev,
+                                       sizeof(*rm_field), GFP_KERNEL);
+       if (!rm_field)
+               return ERR_PTR(-ENOMEM);
+
+       regmap_field_init(rm_field, regmap, reg_field);
+
+       return rm_field;
+
+}
+EXPORT_SYMBOL_GPL(devm_regmap_field_alloc);
+
+/**
+ * devm_regmap_field_free(): Free register field allocated using
+ * devm_regmap_field_alloc. Usally drivers need not call this function,
+ * as the memory allocated via devm will be freed as per device-driver
+ * life-cyle.
+ *
+ * @dev: Device that will be interacted with
+ * @field: regmap field which should be freed.
+ */
+void devm_regmap_field_free(struct device *dev,
+       struct regmap_field *field)
+{
+       devm_kfree(dev, field);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_field_free);
+
+/**
+ * regmap_field_alloc(): Allocate and initialise a register field
+ * in a register map.
+ *
+ * @regmap: regmap bank in which this register field is located.
+ * @reg_field: Register field with in the bank.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap_field. The regmap_field should be freed by the
+ * user once its finished working with it using regmap_field_free().
+ */
+struct regmap_field *regmap_field_alloc(struct regmap *regmap,
+               struct reg_field reg_field)
+{
+       struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
+
+       if (!rm_field)
+               return ERR_PTR(-ENOMEM);
+
+       regmap_field_init(rm_field, regmap, reg_field);
+
+       return rm_field;
+}
+EXPORT_SYMBOL_GPL(regmap_field_alloc);
+
+/**
+ * regmap_field_free(): Free register field allocated using regmap_field_alloc
+ *
+ * @field: regmap field which should be freed.
+ */
+void regmap_field_free(struct regmap_field *field)
+{
+       kfree(field);
+}
+EXPORT_SYMBOL_GPL(regmap_field_free);
+
 /**
  * regmap_reinit_cache(): Reinitialise the current register cache
  *
@@ -1249,6 +1344,22 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
 }
 EXPORT_SYMBOL_GPL(regmap_raw_write);
 
+/**
+ * regmap_field_write(): Write a value to a single register field
+ *
+ * @field: Register field to write to
+ * @val: Value to be written
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_field_write(struct regmap_field *field, unsigned int val)
+{
+       return regmap_update_bits(field->regmap, field->reg,
+                               field->mask, val << field->shift);
+}
+EXPORT_SYMBOL_GPL(regmap_field_write);
+
 /*
  * regmap_bulk_write(): Write multiple registers to the device
  *
@@ -1531,6 +1642,31 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 }
 EXPORT_SYMBOL_GPL(regmap_raw_read);
 
+/**
+ * regmap_field_read(): Read a value to a single register field
+ *
+ * @field: Register field to read from
+ * @val: Pointer to store read value
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_field_read(struct regmap_field *field, unsigned int *val)
+{
+       int ret;
+       unsigned int reg_val;
+       ret = regmap_read(field->regmap, field->reg, &reg_val);
+       if (ret != 0)
+               return ret;
+
+       reg_val &= field->mask;
+       reg_val >>= field->shift;
+       *val = reg_val;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_field_read);
+
 /**
  * regmap_bulk_read(): Read multiple registers from the device
  *
index 175649468c9518b6b7553abc018c0de4ac5cada1..025c41d3cb335b8f6df1a683a7e3080dd0a62aa5 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (c) 2012 Coraid, Inc.  See COPYING for GPL terms. */
-#define VERSION "81"
+/* Copyright (c) 2013 Coraid, Inc.  See COPYING for GPL terms. */
+#define VERSION "83"
 #define AOE_MAJOR 152
 #define DEVICE_NAME "aoe"
 
@@ -196,9 +196,11 @@ struct ktstate {
        struct completion rendez;
        struct task_struct *task;
        wait_queue_head_t *waitq;
-       int (*fn) (void);
-       char *name;
+       int (*fn) (int);
+       char name[12];
        spinlock_t *lock;
+       int id;
+       int active;
 };
 
 int aoeblk_init(void);
@@ -222,6 +224,7 @@ int aoecmd_init(void);
 struct sk_buff *aoecmd_ata_id(struct aoedev *);
 void aoe_freetframe(struct frame *);
 void aoe_flush_iocq(void);
+void aoe_flush_iocq_by_index(int);
 void aoe_end_request(struct aoedev *, struct request *, int);
 int aoe_ktstart(struct ktstate *k);
 void aoe_ktstop(struct ktstate *k);
index fc803ecbbce4a2d9d12a27d6a822f70a42b7732d..99cb944a002dc4dfd5f2010a6f2de9d75c09ebc8 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 Coraid, Inc.  See COPYING for GPL terms. */
+/* Copyright (c) 2013 Coraid, Inc.  See COPYING for GPL terms. */
 /*
  * aoecmd.c
  * Filesystem request handling methods
@@ -35,14 +35,27 @@ module_param(aoe_maxout, int, 0644);
 MODULE_PARM_DESC(aoe_maxout,
        "Only aoe_maxout outstanding packets for every MAC on eX.Y.");
 
-static wait_queue_head_t ktiowq;
-static struct ktstate kts;
+/* The number of online cpus during module initialization gives us a
+ * convenient heuristic cap on the parallelism used for ktio threads
+ * doing I/O completion.  It is not important that the cap equal the
+ * actual number of running CPUs at any given time, but because of CPU
+ * hotplug, we take care to use ncpus instead of using
+ * num_online_cpus() after module initialization.
+ */
+static int ncpus;
+
+/* mutex lock used for synchronization while thread spawning */
+static DEFINE_MUTEX(ktio_spawn_lock);
+
+static wait_queue_head_t *ktiowq;
+static struct ktstate *kts;
 
 /* io completion queue */
-static struct {
+struct iocq_ktio {
        struct list_head head;
        spinlock_t lock;
-} iocq;
+};
+static struct iocq_ktio *iocq;
 
 static struct page *empty_page;
 
@@ -1278,23 +1291,36 @@ out:
  * Returns true iff responses needing processing remain.
  */
 static int
-ktio(void)
+ktio(int id)
 {
        struct frame *f;
        struct list_head *pos;
        int i;
+       int actual_id;
 
        for (i = 0; ; ++i) {
                if (i == MAXIOC)
                        return 1;
-               if (list_empty(&iocq.head))
+               if (list_empty(&iocq[id].head))
                        return 0;
-               pos = iocq.head.next;
+               pos = iocq[id].head.next;
                list_del(pos);
-               spin_unlock_irq(&iocq.lock);
                f = list_entry(pos, struct frame, head);
+               spin_unlock_irq(&iocq[id].lock);
                ktiocomplete(f);
-               spin_lock_irq(&iocq.lock);
+
+               /* Figure out if extra threads are required. */
+               actual_id = f->t->d->aoeminor % ncpus;
+
+               if (!kts[actual_id].active) {
+                       BUG_ON(id != 0);
+                       mutex_lock(&ktio_spawn_lock);
+                       if (!kts[actual_id].active
+                               && aoe_ktstart(&kts[actual_id]) == 0)
+                               kts[actual_id].active = 1;
+                       mutex_unlock(&ktio_spawn_lock);
+               }
+               spin_lock_irq(&iocq[id].lock);
        }
 }
 
@@ -1311,7 +1337,7 @@ kthread(void *vp)
        complete(&k->rendez);   /* tell spawner we're running */
        do {
                spin_lock_irq(k->lock);
-               more = k->fn();
+               more = k->fn(k->id);
                if (!more) {
                        add_wait_queue(k->waitq, &wait);
                        __set_current_state(TASK_INTERRUPTIBLE);
@@ -1340,7 +1366,7 @@ aoe_ktstart(struct ktstate *k)
        struct task_struct *task;
 
        init_completion(&k->rendez);
-       task = kthread_run(kthread, k, k->name);
+       task = kthread_run(kthread, k, "%s", k->name);
        if (task == NULL || IS_ERR(task))
                return -ENOMEM;
        k->task = task;
@@ -1353,13 +1379,24 @@ aoe_ktstart(struct ktstate *k)
 static void
 ktcomplete(struct frame *f, struct sk_buff *skb)
 {
+       int id;
        ulong flags;
 
        f->r_skb = skb;
-       spin_lock_irqsave(&iocq.lock, flags);
-       list_add_tail(&f->head, &iocq.head);
-       spin_unlock_irqrestore(&iocq.lock, flags);
-       wake_up(&ktiowq);
+       id = f->t->d->aoeminor % ncpus;
+       spin_lock_irqsave(&iocq[id].lock, flags);
+       if (!kts[id].active) {
+               spin_unlock_irqrestore(&iocq[id].lock, flags);
+               /* The thread with id has not been spawned yet,
+                * so delegate the work to the main thread and
+                * try spawning a new thread.
+                */
+               id = 0;
+               spin_lock_irqsave(&iocq[id].lock, flags);
+       }
+       list_add_tail(&f->head, &iocq[id].head);
+       spin_unlock_irqrestore(&iocq[id].lock, flags);
+       wake_up(&ktiowq[id]);
 }
 
 struct sk_buff *
@@ -1705,6 +1742,17 @@ aoe_failbuf(struct aoedev *d, struct buf *buf)
 
 void
 aoe_flush_iocq(void)
+{
+       int i;
+
+       for (i = 0; i < ncpus; i++) {
+               if (kts[i].active)
+                       aoe_flush_iocq_by_index(i);
+       }
+}
+
+void
+aoe_flush_iocq_by_index(int id)
 {
        struct frame *f;
        struct aoedev *d;
@@ -1713,9 +1761,9 @@ aoe_flush_iocq(void)
        struct sk_buff *skb;
        ulong flags;
 
-       spin_lock_irqsave(&iocq.lock, flags);
-       list_splice_init(&iocq.head, &flist);
-       spin_unlock_irqrestore(&iocq.lock, flags);
+       spin_lock_irqsave(&iocq[id].lock, flags);
+       list_splice_init(&iocq[id].head, &flist);
+       spin_unlock_irqrestore(&iocq[id].lock, flags);
        while (!list_empty(&flist)) {
                pos = flist.next;
                list_del(pos);
@@ -1738,6 +1786,8 @@ int __init
 aoecmd_init(void)
 {
        void *p;
+       int i;
+       int ret;
 
        /* get_zeroed_page returns page with ref count 1 */
        p = (void *) get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
@@ -1745,22 +1795,72 @@ aoecmd_init(void)
                return -ENOMEM;
        empty_page = virt_to_page(p);
 
-       INIT_LIST_HEAD(&iocq.head);
-       spin_lock_init(&iocq.lock);
-       init_waitqueue_head(&ktiowq);
-       kts.name = "aoe_ktio";
-       kts.fn = ktio;
-       kts.waitq = &ktiowq;
-       kts.lock = &iocq.lock;
-       return aoe_ktstart(&kts);
+       ncpus = num_online_cpus();
+
+       iocq = kcalloc(ncpus, sizeof(struct iocq_ktio), GFP_KERNEL);
+       if (!iocq)
+               return -ENOMEM;
+
+       kts = kcalloc(ncpus, sizeof(struct ktstate), GFP_KERNEL);
+       if (!kts) {
+               ret = -ENOMEM;
+               goto kts_fail;
+       }
+
+       ktiowq = kcalloc(ncpus, sizeof(wait_queue_head_t), GFP_KERNEL);
+       if (!ktiowq) {
+               ret = -ENOMEM;
+               goto ktiowq_fail;
+       }
+
+       mutex_init(&ktio_spawn_lock);
+
+       for (i = 0; i < ncpus; i++) {
+               INIT_LIST_HEAD(&iocq[i].head);
+               spin_lock_init(&iocq[i].lock);
+               init_waitqueue_head(&ktiowq[i]);
+               snprintf(kts[i].name, sizeof(kts[i].name), "aoe_ktio%d", i);
+               kts[i].fn = ktio;
+               kts[i].waitq = &ktiowq[i];
+               kts[i].lock = &iocq[i].lock;
+               kts[i].id = i;
+               kts[i].active = 0;
+       }
+       kts[0].active = 1;
+       if (aoe_ktstart(&kts[0])) {
+               ret = -ENOMEM;
+               goto ktstart_fail;
+       }
+       return 0;
+
+ktstart_fail:
+       kfree(ktiowq);
+ktiowq_fail:
+       kfree(kts);
+kts_fail:
+       kfree(iocq);
+
+       return ret;
 }
 
 void
 aoecmd_exit(void)
 {
-       aoe_ktstop(&kts);
+       int i;
+
+       for (i = 0; i < ncpus; i++)
+               if (kts[i].active)
+                       aoe_ktstop(&kts[i]);
+
        aoe_flush_iocq();
 
+       /* Free up the iocq and thread speicific configuration
+       * allocated during startup.
+       */
+       kfree(iocq);
+       kfree(kts);
+       kfree(ktiowq);
+
        free_page((unsigned long) page_address(empty_page));
        empty_page = NULL;
 }
index 98f2965778b9ce18a4a58aaf91544d5b35a3d134..784c92e038d1461de3b2048fc263bf55a3e758a6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 Coraid, Inc.  See COPYING for GPL terms. */
+/* Copyright (c) 2013 Coraid, Inc.  See COPYING for GPL terms. */
 /*
  * aoedev.c
  * AoE device utility functions; maintains device list.
@@ -518,7 +518,6 @@ void
 aoedev_exit(void)
 {
        flush_scheduled_work();
-       aoe_flush_iocq();
        flush(NULL, 0, EXITING);
 }
 
index 71d3ea8d30062cc85b7edba1e4f8270673f6a829..63773a90581dd36818051a114e38b5b60af0a874 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 Coraid, Inc.  See COPYING for GPL terms. */
+/* Copyright (c) 2013 Coraid, Inc.  See COPYING for GPL terms. */
 /*
  * aoenet.c
  * Ethernet portion of AoE driver
@@ -52,7 +52,7 @@ static struct sk_buff_head skbtxq;
 
 /* enters with txlock held */
 static int
-tx(void) __must_hold(&txlock)
+tx(int id) __must_hold(&txlock)
 {
        struct sk_buff *skb;
        struct net_device *ifp;
@@ -205,7 +205,8 @@ aoenet_init(void)
        kts.lock = &txlock;
        kts.fn = tx;
        kts.waitq = &txwq;
-       kts.name = "aoe_tx";
+       kts.id = 0;
+       snprintf(kts.name, sizeof(kts.name), "aoe_tx%d", kts.id);
        if (aoe_ktstart(&kts))
                return -EAGAIN;
        dev_add_pack(&aoe_pt);
index 20dd52a2f92f8ea733c4b78d444c0ea94d496dd8..952dbfe2212661cb62bd8ef49af11e90f92d391a 100644 (file)
@@ -4087,7 +4087,8 @@ skip_create_disk:
 start_service_thread:
        sprintf(thd_name, "mtip_svc_thd_%02d", index);
        dd->mtip_svc_handler = kthread_create_on_node(mtip_service_thread,
-                                               dd, dd->numa_node, thd_name);
+                                               dd, dd->numa_node, "%s",
+                                               thd_name);
 
        if (IS_ERR(dd->mtip_svc_handler)) {
                dev_err(&dd->pdev->dev, "service thread failed to start\n");
index 037288e7874d625676f5fa9e95a9920ac91551f5..2dc3b5153f0d82b42cfab720464e17bd963223f8 100644 (file)
@@ -623,8 +623,10 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                if (!nbd->sock)
                        return -EINVAL;
 
+               nbd->disconnect = 1;
+
                nbd_send_req(nbd, &sreq);
-                return 0;
+               return 0;
        }
  
        case NBD_CLEAR_SOCK: {
@@ -654,6 +656,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                                nbd->sock = SOCKET_I(inode);
                                if (max_part > 0)
                                        bdev->bd_invalidated = 1;
+                               nbd->disconnect = 0; /* we're connected now */
                                return 0;
                        } else {
                                fput(file);
@@ -714,7 +717,8 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                else
                        blk_queue_flush(nbd->disk->queue, 0);
 
-               thread = kthread_create(nbd_thread, nbd, nbd->disk->disk_name);
+               thread = kthread_create(nbd_thread, nbd, "%s",
+                                       nbd->disk->disk_name);
                if (IS_ERR(thread)) {
                        mutex_lock(&nbd->tx_lock);
                        return PTR_ERR(thread);
@@ -742,6 +746,8 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                set_capacity(nbd->disk, 0);
                if (max_part > 0)
                        ioctl_by_bdev(bdev, BLKRRPART, 0);
+               if (nbd->disconnect) /* user requested, ignore socket errors */
+                       return 0;
                return nbd->harderror;
        }
 
@@ -750,7 +756,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                 * This is for compatibility only.  The queue is always cleared
                 * by NBD_DO_IT or NBD_CLEAR_SOCK.
                 */
-               BUG_ON(!nbd->sock && !list_empty(&nbd->queue_head));
                return 0;
 
        case NBD_PRINT_DEBUG:
index 2f445b7a174e2c1dff1f9a2d1fb7438e9a242ff9..8ed6ccb748cffa996f38a4f4c5acf935f00a18c0 100644 (file)
@@ -893,7 +893,7 @@ static int swim_probe(struct platform_device *dev)
 
        swim_base = ioremap(res->start, resource_size(res));
        if (!swim_base) {
-               return -ENOMEM;
+               ret = -ENOMEM;
                goto out_release_io;
        }
 
index 64723953e1c97e54a64dee454c48f7bf672d00b4..5cdf88b7ad9e72a36bc9aa25755b03485c987418 100644 (file)
@@ -20,7 +20,7 @@ module_param(use_bio, bool, S_IRUGO);
 static int major;
 static DEFINE_IDA(vd_index_ida);
 
-struct workqueue_struct *virtblk_wq;
+static struct workqueue_struct *virtblk_wq;
 
 struct virtio_blk
 {
index 8bfd1bcf95ec0c168f565ac769479cb3be6098d3..04608a6502d7b25bec73a51da69e1e2748e960c4 100644 (file)
@@ -93,7 +93,7 @@ static void xen_update_blkif_status(struct xen_blkif *blkif)
        }
        invalidate_inode_pages2(blkif->vbd.bdev->bd_inode->i_mapping);
 
-       blkif->xenblkd = kthread_run(xen_blkif_schedule, blkif, name);
+       blkif->xenblkd = kthread_run(xen_blkif_schedule, blkif, "%s", name);
        if (IS_ERR(blkif->xenblkd)) {
                err = PTR_ERR(blkif->xenblkd);
                blkif->xenblkd = NULL;
index d620b44957454a80fcf444d10cb967e66fb9d7d5..8a3aff724d989c331f5de1596f3064cbbe72c271 100644 (file)
@@ -2882,7 +2882,7 @@ static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi,
        if (lba < 0)
                return -EINVAL;
 
-       cgc->buffer = kmalloc(blocksize, GFP_KERNEL);
+       cgc->buffer = kzalloc(blocksize, GFP_KERNEL);
        if (cgc->buffer == NULL)
                return -ENOMEM;
 
index 4afcb65cc62397466aee5f8272051e197a9c9fb1..5980cb9af857891491baee6026efe16cb84694de 100644 (file)
@@ -830,9 +830,9 @@ probe_fail_cdrom_register:
        del_gendisk(gd.disk);
 probe_fail_no_disk:
        kfree(gd.cd_info);
+probe_fail_no_mem:
        unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
        gdrom_major = 0;
-probe_fail_no_mem:
        pr_warning("Probe failed - error is 0x%X\n", err);
        return err;
 }
index dd84af4d4f7e1cfdd0c74e576269d1744e1cfdef..199b8e99f7d7886d5d5e59b4fff5bf43337e523d 100644 (file)
@@ -174,7 +174,7 @@ alpha_core_agp_setup(void)
        /*
         * Build a fake pci_dev struct
         */
-       pdev = alloc_pci_dev();
+       pdev = pci_alloc_dev(NULL);
        if (!pdev)
                return -ENOMEM;
        pdev->vendor = 0xffff;
index 94821ab01c6d6ae1803201c27217c69a30357329..bf5d2477cb77c296dac3a63b3aea2e8a2ec5ce0a 100644 (file)
@@ -333,7 +333,7 @@ parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
        struct agp_bridge_data *bridge;
        int error = 0;
 
-       fake_bridge_dev = alloc_pci_dev();
+       fake_bridge_dev = pci_alloc_dev(NULL);
        if (!fake_bridge_dev) {
                error = -ENOMEM;
                goto fail;
index 2ca6d7844ad91d102c803116cfcfd0082d6e6518..f895a8c8a244b54c02eb8b59b0eba8d42734a011 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/ptrace.h>
 #include <linux/device.h>
 #include <linux/highmem.h>
-#include <linux/crash_dump.h>
 #include <linux/backing-dev.h>
 #include <linux/bootmem.h>
 #include <linux/splice.h>
@@ -357,40 +356,6 @@ static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
 }
 #endif
 
-#ifdef CONFIG_CRASH_DUMP
-/*
- * Read memory corresponding to the old kernel.
- */
-static ssize_t read_oldmem(struct file *file, char __user *buf,
-                               size_t count, loff_t *ppos)
-{
-       unsigned long pfn, offset;
-       size_t read = 0, csize;
-       int rc = 0;
-
-       while (count) {
-               pfn = *ppos / PAGE_SIZE;
-               if (pfn > saved_max_pfn)
-                       return read;
-
-               offset = (unsigned long)(*ppos % PAGE_SIZE);
-               if (count > PAGE_SIZE - offset)
-                       csize = PAGE_SIZE - offset;
-               else
-                       csize = count;
-
-               rc = copy_oldmem_page(pfn, buf, csize, offset, 1);
-               if (rc < 0)
-                       return rc;
-               buf += csize;
-               *ppos += csize;
-               read += csize;
-               count -= csize;
-       }
-       return read;
-}
-#endif
-
 #ifdef CONFIG_DEVKMEM
 /*
  * This function reads the *virtual* memory as seen by the kernel.
@@ -772,7 +737,6 @@ static int open_port(struct inode *inode, struct file *filp)
 #define aio_write_zero aio_write_null
 #define open_mem       open_port
 #define open_kmem      open_mem
-#define open_oldmem    open_mem
 
 static const struct file_operations mem_fops = {
        .llseek         = memory_lseek,
@@ -837,14 +801,6 @@ static const struct file_operations full_fops = {
        .write          = write_full,
 };
 
-#ifdef CONFIG_CRASH_DUMP
-static const struct file_operations oldmem_fops = {
-       .read   = read_oldmem,
-       .open   = open_oldmem,
-       .llseek = default_llseek,
-};
-#endif
-
 static const struct memdev {
        const char *name;
        umode_t mode;
@@ -866,9 +822,6 @@ static const struct memdev {
 #ifdef CONFIG_PRINTK
        [11] = { "kmsg", 0644, &kmsg_fops, NULL },
 #endif
-#ifdef CONFIG_CRASH_DUMP
-       [12] = { "oldmem", 0, &oldmem_fops, NULL },
-#endif
 };
 
 static int memory_open(struct inode *inode, struct file *filp)
index 8cafa9ccd43f0e7805a86fb0edb8f6ffa526363b..0b311fa277ef097f485d9aa92da18c262a7f10dd 100644 (file)
@@ -98,32 +98,8 @@ static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
 static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
 {
        struct ps3_storage_device *dev = ps3flash_dev;
-       loff_t res;
-
-       mutex_lock(&file->f_mapping->host->i_mutex);
-       switch (origin) {
-       case 0:
-               break;
-       case 1:
-               offset += file->f_pos;
-               break;
-       case 2:
-               offset += dev->regions[dev->region_idx].size*dev->blk_size;
-               break;
-       default:
-               offset = -1;
-       }
-       if (offset < 0) {
-               res = -EINVAL;
-               goto out;
-       }
-
-       file->f_pos = offset;
-       res = file->f_pos;
-
-out:
-       mutex_unlock(&file->f_mapping->host->i_mutex);
-       return res;
+       return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
+                       dev->regions[dev->region_idx].size*dev->blk_size);
 }
 
 static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
index 2e2036e940fcafc2c52af4552da1cfd5d984d938..7faeb1cde97d3e10a128326295b9570a3bfb9912 100644 (file)
@@ -273,32 +273,10 @@ static ssize_t srom_write(struct file *filp, const char __user *buf,
 }
 
 /* Provide our own implementation so we can use srom->total_size. */
-loff_t srom_llseek(struct file *filp, loff_t offset, int origin)
+loff_t srom_llseek(struct file *file, loff_t offset, int origin)
 {
-       struct srom_dev *srom = filp->private_data;
-
-       if (mutex_lock_interruptible(&srom->lock))
-               return -ERESTARTSYS;
-
-       switch (origin) {
-       case SEEK_END:
-               offset += srom->total_size;
-               break;
-       case SEEK_CUR:
-               offset += filp->f_pos;
-               break;
-       }
-
-       if (offset < 0 || offset > srom->total_size) {
-               offset = -EINVAL;
-       } else {
-               filp->f_pos = offset;
-               filp->f_version = 0;
-       }
-
-       mutex_unlock(&srom->lock);
-
-       return offset;
+       struct srom_dev *srom = file->private_data;
+       return fixed_size_llseek(file, offset, origin, srom->total_size);
 }
 
 static ssize_t total_show(struct device *dev,
index 7c3b3dcbfbc8359e3aad78c60281ea2eecfb9a9d..e3c974a6c522028b96c2df72ab1eb053945b1f43 100644 (file)
@@ -1472,7 +1472,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
  * Once all references to platform device are down to 0,
  * release all allocated structures.
  */
-static void tpm_dev_release(struct device *dev)
+void tpm_dev_release(struct device *dev)
 {
        struct tpm_chip *chip = dev_get_drvdata(dev);
 
index 0770d1d79366d31d4832dd2186d677a6ad3a565c..a7bfc176ed4316bc8319220f1b73848bc9d74f06 100644 (file)
@@ -272,7 +272,6 @@ typedef union {
        struct  tpm_output_header out;
 } tpm_cmd_header;
 
-#define TPM_DIGEST_SIZE 20
 struct tpm_pcrread_out {
        u8      pcr_result[TPM_DIGEST_SIZE];
 } __packed;
@@ -333,6 +332,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *,
                                 const struct tpm_vendor_specific *);
 extern int tpm_open(struct inode *, struct file *);
 extern int tpm_release(struct inode *, struct file *);
+extern void tpm_dev_release(struct device *dev);
 extern void tpm_dev_vendor_release(struct tpm_chip *);
 extern ssize_t tpm_write(struct file *, const char __user *, size_t,
                         loff_t *);
index 37d5dcc10ea75882d0aec906bab00962583ca165..b8735de8ce956a3d19fd3ac5b9a5df77c57d3a22 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/wait.h>
 #include "tpm.h"
 
@@ -74,7 +73,6 @@ struct tpm_inf_dev {
 };
 
 static struct tpm_inf_dev tpm_dev;
-static struct i2c_driver tpm_tis_i2c_driver;
 
 /*
  * iic_tpm_read() - read from TPM register
@@ -744,11 +742,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
                return -ENODEV;
        }
 
-       client->driver = &tpm_tis_i2c_driver;
        tpm_dev.client = client;
        rc = tpm_tis_i2c_init(&client->dev);
        if (rc != 0) {
-               client->driver = NULL;
                tpm_dev.client = NULL;
                rc = -ENODEV;
        }
index 8a41b6be23a057bd5ff033f30d7de52ac7085a38..4519cb332987bc1ac840f9d8ac26cac4be3b964b 100644 (file)
@@ -884,12 +884,19 @@ static int __init init_tis(void)
        rc = platform_driver_register(&tis_drv);
        if (rc < 0)
                return rc;
-       if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
-               return PTR_ERR(pdev);
-       if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) {
-               platform_device_unregister(pdev);
-               platform_driver_unregister(&tis_drv);
+       pdev = platform_device_register_simple("tpm_tis", -1, NULL, 0);
+       if (IS_ERR(pdev)) {
+               rc = PTR_ERR(pdev);
+               goto err_dev;
        }
+       rc = tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0);
+       if (rc)
+               goto err_init;
+       return 0;
+err_init:
+       platform_device_unregister(pdev);
+err_dev:
+       platform_driver_unregister(&tis_drv);
        return rc;
 }
 
index 0357ac44638ba5f70ee623939697a1f1023b9440..51380d655d1aff80ab4368dddfe2d4284becc59c 100644 (file)
@@ -42,7 +42,7 @@ config COMMON_CLK_WM831X
 
 config COMMON_CLK_VERSATILE
        bool "Clock driver for ARM Reference designs"
-       depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS
+       depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS || ARM64
        ---help---
           Supports clocking on ARM Reference designs:
          - Integrator/AP and Integrator/CP
@@ -58,7 +58,6 @@ config COMMON_CLK_MAX77686
 config COMMON_CLK_SI5351
        tristate "Clock driver for SiLabs 5351A/B/C"
        depends on I2C
-       depends on OF
        select REGMAP_I2C
        select RATIONAL
        ---help---
@@ -81,6 +80,13 @@ config COMMON_CLK_AXI_CLKGEN
          Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
          FPGAs. It is commonly used in Analog Devices' reference designs.
 
+config CLK_PPC_CORENET
+       bool "Clock driver for PowerPC corenet platforms"
+       depends on PPC_E500MC && OF
+       ---help---
+         This adds the clock driver support for Freescale PowerPC corenet
+         platforms using common clock framework.
+
 endmenu
 
 source "drivers/clk/mvebu/Kconfig"
index f9cf7085ef70466755310f362db4729e0c0b8538..4038c2bdf334ddd4f6ac605b91292af5dabe2713 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_COMMON_CLK)      += clk-composite.o
 obj-$(CONFIG_ARCH_BCM2835)     += clk-bcm2835.o
 obj-$(CONFIG_ARCH_NOMADIK)     += clk-nomadik.o
 obj-$(CONFIG_ARCH_HIGHBANK)    += clk-highbank.o
+obj-$(CONFIG_ARCH_NSPIRE)      += clk-nspire.o
 obj-$(CONFIG_ARCH_MXS)         += mxs/
 obj-$(CONFIG_ARCH_SOCFPGA)     += socfpga/
 obj-$(CONFIG_PLAT_SPEAR)       += spear/
@@ -24,6 +25,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_ARCH_MMP)         += mmp/
 endif
 obj-$(CONFIG_MACH_LOONGSON1)   += clk-ls1x.o
+obj-$(CONFIG_ARCH_ROCKCHIP)    += rockchip/
 obj-$(CONFIG_ARCH_SUNXI)       += sunxi/
 obj-$(CONFIG_ARCH_U8500)       += ux500/
 obj-$(CONFIG_ARCH_VT8500)      += clk-vt8500.o
@@ -39,3 +41,4 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
 obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
 obj-$(CONFIG_CLK_TWL6040)      += clk-twl6040.o
+obj-$(CONFIG_CLK_PPC_CORENET)  += clk-ppc-corenet.o
index 6d9674160430db7456b58c1697272a801b68ba52..6d55eb2cb959baafc949cae9db15097f38c51c76 100644 (file)
@@ -150,6 +150,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
        struct clk_divider *divider = to_clk_divider(hw);
        int i, bestdiv = 0;
        unsigned long parent_rate, best = 0, now, maxdiv;
+       unsigned long parent_rate_saved = *best_parent_rate;
 
        if (!rate)
                rate = 1;
@@ -173,6 +174,15 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
        for (i = 1; i <= maxdiv; i++) {
                if (!_is_valid_div(divider, i))
                        continue;
+               if (rate * i == parent_rate_saved) {
+                       /*
+                        * It's the most ideal case if the requested rate can be
+                        * divided from parent clock without needing to change
+                        * parent rate, so return the divider immediately.
+                        */
+                       *best_parent_rate = parent_rate_saved;
+                       return i;
+               }
                parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
                                MULT_ROUND_UP(rate, i));
                now = parent_rate / i;
@@ -217,8 +227,12 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        if (divider->lock)
                spin_lock_irqsave(divider->lock, flags);
 
-       val = readl(divider->reg);
-       val &= ~(div_mask(divider) << divider->shift);
+       if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
+               val = div_mask(divider) << (divider->shift + 16);
+       } else {
+               val = readl(divider->reg);
+               val &= ~(div_mask(divider) << divider->shift);
+       }
        val |= value << divider->shift;
        writel(val, divider->reg);
 
@@ -245,6 +259,13 @@ static struct clk *_register_divider(struct device *dev, const char *name,
        struct clk *clk;
        struct clk_init_data init;
 
+       if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
+               if (width + shift > 16) {
+                       pr_warn("divider value exceeds LOWORD field\n");
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+
        /* allocate the divider */
        div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
        if (!div) {
index 15114febfd923a4093c7b90b33be6e7754be27e7..790306e921c8ad55bcad26adaeb77c2b378c8db7 100644 (file)
@@ -53,12 +53,18 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
        if (gate->lock)
                spin_lock_irqsave(gate->lock, flags);
 
-       reg = readl(gate->reg);
-
-       if (set)
-               reg |= BIT(gate->bit_idx);
-       else
-               reg &= ~BIT(gate->bit_idx);
+       if (gate->flags & CLK_GATE_HIWORD_MASK) {
+               reg = BIT(gate->bit_idx + 16);
+               if (set)
+                       reg |= BIT(gate->bit_idx);
+       } else {
+               reg = readl(gate->reg);
+
+               if (set)
+                       reg |= BIT(gate->bit_idx);
+               else
+                       reg &= ~BIT(gate->bit_idx);
+       }
 
        writel(reg, gate->reg);
 
@@ -121,6 +127,13 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
        struct clk *clk;
        struct clk_init_data init;
 
+       if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
+               if (bit_idx > 16) {
+                       pr_err("gate bit exceeds LOWORD field\n");
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+
        /* allocate the gate */
        gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
        if (!gate) {
index 25b1734560d0c99bbae8455c78d22d613ccb99c0..614444ca40cd638bbf3283c75b8ea7f80f7fdfe0 100644 (file)
@@ -86,8 +86,12 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
        if (mux->lock)
                spin_lock_irqsave(mux->lock, flags);
 
-       val = readl(mux->reg);
-       val &= ~(mux->mask << mux->shift);
+       if (mux->flags & CLK_MUX_HIWORD_MASK) {
+               val = mux->mask << (mux->shift + 16);
+       } else {
+               val = readl(mux->reg);
+               val &= ~(mux->mask << mux->shift);
+       }
        val |= index << mux->shift;
        writel(val, mux->reg);
 
@@ -111,6 +115,15 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
        struct clk_mux *mux;
        struct clk *clk;
        struct clk_init_data init;
+       u8 width = 0;
+
+       if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
+               width = fls(mask) - ffs(mask) + 1;
+               if (width + shift > 16) {
+                       pr_err("mux value exceeds LOWORD field\n");
+                       return ERR_PTR(-EINVAL);
+               }
+       }
 
        /* allocate the mux */
        mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
diff --git a/drivers/clk/clk-nspire.c b/drivers/clk/clk-nspire.c
new file mode 100644 (file)
index 0000000..a378db7
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *
+ *  Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define MHZ (1000 * 1000)
+
+#define BASE_CPU_SHIFT         1
+#define BASE_CPU_MASK          0x7F
+
+#define CPU_AHB_SHIFT          12
+#define CPU_AHB_MASK           0x07
+
+#define FIXED_BASE_SHIFT       8
+#define FIXED_BASE_MASK                0x01
+
+#define CLASSIC_BASE_SHIFT     16
+#define CLASSIC_BASE_MASK      0x1F
+
+#define CX_BASE_SHIFT          15
+#define CX_BASE_MASK           0x3F
+
+#define CX_UNKNOWN_SHIFT       21
+#define CX_UNKNOWN_MASK                0x03
+
+struct nspire_clk_info {
+       u32 base_clock;
+       u16 base_cpu_ratio;
+       u16 base_ahb_ratio;
+};
+
+
+#define EXTRACT(var, prop) (((var)>>prop##_SHIFT) & prop##_MASK)
+static void nspire_clkinfo_cx(u32 val, struct nspire_clk_info *clk)
+{
+       if (EXTRACT(val, FIXED_BASE))
+               clk->base_clock = 48 * MHZ;
+       else
+               clk->base_clock = 6 * EXTRACT(val, CX_BASE) * MHZ;
+
+       clk->base_cpu_ratio = EXTRACT(val, BASE_CPU) * EXTRACT(val, CX_UNKNOWN);
+       clk->base_ahb_ratio = clk->base_cpu_ratio * (EXTRACT(val, CPU_AHB) + 1);
+}
+
+static void nspire_clkinfo_classic(u32 val, struct nspire_clk_info *clk)
+{
+       if (EXTRACT(val, FIXED_BASE))
+               clk->base_clock = 27 * MHZ;
+       else
+               clk->base_clock = (300 - 6 * EXTRACT(val, CLASSIC_BASE)) * MHZ;
+
+       clk->base_cpu_ratio = EXTRACT(val, BASE_CPU) * 2;
+       clk->base_ahb_ratio = clk->base_cpu_ratio * (EXTRACT(val, CPU_AHB) + 1);
+}
+
+static void __init nspire_ahbdiv_setup(struct device_node *node,
+               void (*get_clkinfo)(u32, struct nspire_clk_info *))
+{
+       u32 val;
+       void __iomem *io;
+       struct clk *clk;
+       const char *clk_name = node->name;
+       const char *parent_name;
+       struct nspire_clk_info info;
+
+       io = of_iomap(node, 0);
+       if (!io)
+               return;
+       val = readl(io);
+       iounmap(io);
+
+       get_clkinfo(val, &info);
+
+       of_property_read_string(node, "clock-output-names", &clk_name);
+       parent_name = of_clk_get_parent_name(node, 0);
+
+       clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0,
+                                       1, info.base_ahb_ratio);
+       if (!IS_ERR(clk))
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+static void __init nspire_ahbdiv_setup_cx(struct device_node *node)
+{
+       nspire_ahbdiv_setup(node, nspire_clkinfo_cx);
+}
+
+static void __init nspire_ahbdiv_setup_classic(struct device_node *node)
+{
+       nspire_ahbdiv_setup(node, nspire_clkinfo_classic);
+}
+
+CLK_OF_DECLARE(nspire_ahbdiv_cx, "lsi,nspire-cx-ahb-divider",
+               nspire_ahbdiv_setup_cx);
+CLK_OF_DECLARE(nspire_ahbdiv_classic, "lsi,nspire-classic-ahb-divider",
+               nspire_ahbdiv_setup_classic);
+
+static void __init nspire_clk_setup(struct device_node *node,
+               void (*get_clkinfo)(u32, struct nspire_clk_info *))
+{
+       u32 val;
+       void __iomem *io;
+       struct clk *clk;
+       const char *clk_name = node->name;
+       struct nspire_clk_info info;
+
+       io = of_iomap(node, 0);
+       if (!io)
+               return;
+       val = readl(io);
+       iounmap(io);
+
+       get_clkinfo(val, &info);
+
+       of_property_read_string(node, "clock-output-names", &clk_name);
+
+       clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT,
+                       info.base_clock);
+       if (!IS_ERR(clk))
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       else
+               return;
+
+       pr_info("TI-NSPIRE Base: %uMHz CPU: %uMHz AHB: %uMHz\n",
+               info.base_clock / MHZ,
+               info.base_clock / info.base_cpu_ratio / MHZ,
+               info.base_clock / info.base_ahb_ratio / MHZ);
+}
+
+static void __init nspire_clk_setup_cx(struct device_node *node)
+{
+       nspire_clk_setup(node, nspire_clkinfo_cx);
+}
+
+static void __init nspire_clk_setup_classic(struct device_node *node)
+{
+       nspire_clk_setup(node, nspire_clkinfo_classic);
+}
+
+CLK_OF_DECLARE(nspire_clk_cx, "lsi,nspire-cx-clock", nspire_clk_setup_cx);
+CLK_OF_DECLARE(nspire_clk_classic, "lsi,nspire-classic-clock",
+               nspire_clk_setup_classic);
diff --git a/drivers/clk/clk-ppc-corenet.c b/drivers/clk/clk-ppc-corenet.c
new file mode 100644 (file)
index 0000000..e958707
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, 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.
+ *
+ * clock driver for Freescale PowerPC corenet SoCs.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+struct cmux_clk {
+       struct clk_hw hw;
+       void __iomem *reg;
+       u32 flags;
+};
+
+#define PLL_KILL                       BIT(31)
+#define        CLKSEL_SHIFT            27
+#define CLKSEL_ADJUST          BIT(0)
+#define to_cmux_clk(p)         container_of(p, struct cmux_clk, hw)
+
+static void __iomem *base;
+static unsigned int clocks_per_pll;
+
+static int cmux_set_parent(struct clk_hw *hw, u8 idx)
+{
+       struct cmux_clk *clk = to_cmux_clk(hw);
+       u32 clksel;
+
+       clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
+       if (clk->flags & CLKSEL_ADJUST)
+               clksel += 8;
+       clksel = (clksel & 0xf) << CLKSEL_SHIFT;
+       iowrite32be(clksel, clk->reg);
+
+       return 0;
+}
+
+static u8 cmux_get_parent(struct clk_hw *hw)
+{
+       struct cmux_clk *clk = to_cmux_clk(hw);
+       u32 clksel;
+
+       clksel = ioread32be(clk->reg);
+       clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
+       if (clk->flags & CLKSEL_ADJUST)
+               clksel -= 8;
+       clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
+
+       return clksel;
+}
+
+const struct clk_ops cmux_ops = {
+       .get_parent = cmux_get_parent,
+       .set_parent = cmux_set_parent,
+};
+
+static void __init core_mux_init(struct device_node *np)
+{
+       struct clk *clk;
+       struct clk_init_data init;
+       struct cmux_clk *cmux_clk;
+       struct device_node *node;
+       int rc, count, i;
+       u32     offset;
+       const char *clk_name;
+       const char **parent_names;
+
+       rc = of_property_read_u32(np, "reg", &offset);
+       if (rc) {
+               pr_err("%s: could not get reg property\n", np->name);
+               return;
+       }
+
+       /* get the input clock source count */
+       count = of_property_count_strings(np, "clock-names");
+       if (count < 0) {
+               pr_err("%s: get clock count error\n", np->name);
+               return;
+       }
+       parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
+       if (!parent_names) {
+               pr_err("%s: could not allocate parent_names\n", __func__);
+               return;
+       }
+
+       for (i = 0; i < count; i++)
+               parent_names[i] = of_clk_get_parent_name(np, i);
+
+       cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
+       if (!cmux_clk) {
+               pr_err("%s: could not allocate cmux_clk\n", __func__);
+               goto err_name;
+       }
+       cmux_clk->reg = base + offset;
+
+       node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
+       if (node && (offset >= 0x80))
+               cmux_clk->flags = CLKSEL_ADJUST;
+
+       rc = of_property_read_string_index(np, "clock-output-names",
+                       0, &clk_name);
+       if (rc) {
+               pr_err("%s: read clock names error\n", np->name);
+               goto err_clk;
+       }
+
+       init.name = clk_name;
+       init.ops = &cmux_ops;
+       init.parent_names = parent_names;
+       init.num_parents = count;
+       init.flags = 0;
+       cmux_clk->hw.init = &init;
+
+       clk = clk_register(NULL, &cmux_clk->hw);
+       if (IS_ERR(clk)) {
+               pr_err("%s: could not register clock\n", clk_name);
+               goto err_clk;
+       }
+
+       rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+       if (rc) {
+               pr_err("Could not register clock provider for node:%s\n",
+                        np->name);
+               goto err_clk;
+       }
+       goto err_name;
+
+err_clk:
+       kfree(cmux_clk);
+err_name:
+       /* free *_names because they are reallocated when registered */
+       kfree(parent_names);
+}
+
+static void __init core_pll_init(struct device_node *np)
+{
+       u32 offset, mult;
+       int i, rc, count;
+       const char *clk_name, *parent_name;
+       struct clk_onecell_data *onecell_data;
+       struct clk      **subclks;
+
+       rc = of_property_read_u32(np, "reg", &offset);
+       if (rc) {
+               pr_err("%s: could not get reg property\n", np->name);
+               return;
+       }
+
+       /* get the multiple of PLL */
+       mult = ioread32be(base + offset);
+
+       /* check if this PLL is disabled */
+       if (mult & PLL_KILL) {
+               pr_debug("PLL:%s is disabled\n", np->name);
+               return;
+       }
+       mult = (mult >> 1) & 0x3f;
+
+       parent_name = of_clk_get_parent_name(np, 0);
+       if (!parent_name) {
+               pr_err("PLL: %s must have a parent\n", np->name);
+               return;
+       }
+
+       count = of_property_count_strings(np, "clock-output-names");
+       if (count < 0 || count > 4) {
+               pr_err("%s: clock is not supported\n", np->name);
+               return;
+       }
+
+       /* output clock number per PLL */
+       clocks_per_pll = count;
+
+       subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
+       if (!subclks) {
+               pr_err("%s: could not allocate subclks\n", __func__);
+               return;
+       }
+
+       onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+       if (!onecell_data) {
+               pr_err("%s: could not allocate onecell_data\n", __func__);
+               goto err_clks;
+       }
+
+       for (i = 0; i < count; i++) {
+               rc = of_property_read_string_index(np, "clock-output-names",
+                               i, &clk_name);
+               if (rc) {
+                       pr_err("%s: could not get clock names\n", np->name);
+                       goto err_cell;
+               }
+
+               /*
+                * when count == 4, there are 4 output clocks:
+                * /1, /2, /3, /4 respectively
+                * when count < 4, there are at least 2 output clocks:
+                * /1, /2, (/4, if count == 3) respectively.
+                */
+               if (count == 4)
+                       subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+                                       parent_name, 0, mult, 1 + i);
+               else
+
+                       subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+                                       parent_name, 0, mult, 1 << i);
+
+               if (IS_ERR(subclks[i])) {
+                       pr_err("%s: could not register clock\n", clk_name);
+                       goto err_cell;
+               }
+       }
+
+       onecell_data->clks = subclks;
+       onecell_data->clk_num = count;
+
+       rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
+       if (rc) {
+               pr_err("Could not register clk provider for node:%s\n",
+                        np->name);
+               goto err_cell;
+       }
+
+       return;
+err_cell:
+       kfree(onecell_data);
+err_clks:
+       kfree(subclks);
+}
+
+static const struct of_device_id clk_match[] __initconst = {
+       { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+       { .compatible = "fsl,core-pll-clock", .data = core_pll_init, },
+       { .compatible = "fsl,core-mux-clock", .data = core_mux_init, },
+       {}
+};
+
+static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
+{
+       struct device_node *np;
+
+       np = pdev->dev.of_node;
+       base = of_iomap(np, 0);
+       if (!base) {
+               dev_err(&pdev->dev, "iomap error\n");
+               return -ENOMEM;
+       }
+       of_clk_init(clk_match);
+
+       return 0;
+}
+
+static const struct of_device_id ppc_clk_ids[] __initconst = {
+       { .compatible = "fsl,qoriq-clockgen-1.0", },
+       { .compatible = "fsl,qoriq-clockgen-2.0", },
+       {}
+};
+
+static struct platform_driver ppc_corenet_clk_driver = {
+       .driver = {
+               .name = "ppc_corenet_clock",
+               .owner = THIS_MODULE,
+               .of_match_table = ppc_clk_ids,
+       },
+       .probe = ppc_corenet_clk_probe,
+};
+
+static int __init ppc_corenet_clk_init(void)
+{
+       return platform_driver_register(&ppc_corenet_clk_driver);
+}
+subsys_initcall(ppc_corenet_clk_init);
index 24f553673b72d0502415cae85dcfd8a281de06ec..c50e83744b0aec3a0a8841f068bbbe05adc5ef8d 100644 (file)
@@ -851,6 +851,41 @@ static int _si5351_clkout_set_drive_strength(
        return 0;
 }
 
+static int _si5351_clkout_set_disable_state(
+       struct si5351_driver_data *drvdata, int num,
+       enum si5351_disable_state state)
+{
+       u8 reg = (num < 4) ? SI5351_CLK3_0_DISABLE_STATE :
+               SI5351_CLK7_4_DISABLE_STATE;
+       u8 shift = (num < 4) ? (2 * num) : (2 * (num-4));
+       u8 mask = SI5351_CLK_DISABLE_STATE_MASK << shift;
+       u8 val;
+
+       if (num > 8)
+               return -EINVAL;
+
+       switch (state) {
+       case SI5351_DISABLE_LOW:
+               val = SI5351_CLK_DISABLE_STATE_LOW;
+               break;
+       case SI5351_DISABLE_HIGH:
+               val = SI5351_CLK_DISABLE_STATE_HIGH;
+               break;
+       case SI5351_DISABLE_FLOATING:
+               val = SI5351_CLK_DISABLE_STATE_FLOAT;
+               break;
+       case SI5351_DISABLE_NEVER:
+               val = SI5351_CLK_DISABLE_STATE_NEVER;
+               break;
+       default:
+               return 0;
+       }
+
+       si5351_set_bits(drvdata, reg, mask, val << shift);
+
+       return 0;
+}
+
 static int si5351_clkout_prepare(struct clk_hw *hw)
 {
        struct si5351_hw_data *hwdata =
@@ -1225,6 +1260,33 @@ static int si5351_dt_parse(struct i2c_client *client)
                        }
                }
 
+               if (!of_property_read_u32(child, "silabs,disable-state",
+                                         &val)) {
+                       switch (val) {
+                       case 0:
+                               pdata->clkout[num].disable_state =
+                                       SI5351_DISABLE_LOW;
+                               break;
+                       case 1:
+                               pdata->clkout[num].disable_state =
+                                       SI5351_DISABLE_HIGH;
+                               break;
+                       case 2:
+                               pdata->clkout[num].disable_state =
+                                       SI5351_DISABLE_FLOATING;
+                               break;
+                       case 3:
+                               pdata->clkout[num].disable_state =
+                                       SI5351_DISABLE_NEVER;
+                               break;
+                       default:
+                               dev_err(&client->dev,
+                                       "invalid disable state %d for clkout %d\n",
+                                       val, num);
+                               return -EINVAL;
+                       }
+               }
+
                if (!of_property_read_u32(child, "clock-frequency", &val))
                        pdata->clkout[num].rate = val;
 
@@ -1281,9 +1343,6 @@ static int si5351_i2c_probe(struct i2c_client *client,
 
        /* Disable interrupts */
        si5351_reg_write(drvdata, SI5351_INTERRUPT_MASK, 0xf0);
-       /* Set disabled output drivers to drive low */
-       si5351_reg_write(drvdata, SI5351_CLK3_0_DISABLE_STATE, 0x00);
-       si5351_reg_write(drvdata, SI5351_CLK7_4_DISABLE_STATE, 0x00);
        /* Ensure pll select is on XTAL for Si5351A/B */
        if (drvdata->variant != SI5351_VARIANT_C)
                si5351_set_bits(drvdata, SI5351_PLL_INPUT_SOURCE,
@@ -1327,6 +1386,15 @@ static int si5351_i2c_probe(struct i2c_client *client,
                                n, pdata->clkout[n].drive);
                        return ret;
                }
+
+               ret = _si5351_clkout_set_disable_state(drvdata, n,
+                                               pdata->clkout[n].disable_state);
+               if (ret) {
+                       dev_err(&client->dev,
+                               "failed set disable state of clkout%d to %d\n",
+                               n, pdata->clkout[n].disable_state);
+                       return ret;
+               }
        }
 
        /* register xtal input clock gate */
@@ -1500,7 +1568,10 @@ static int si5351_i2c_probe(struct i2c_client *client,
 }
 
 static const struct i2c_device_id si5351_i2c_ids[] = {
-       { "silabs,si5351", 0 },
+       { "si5351a", 0 },
+       { "si5351a-msop", 0 },
+       { "si5351b", 0 },
+       { "si5351c", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids);
index af41b5080f43e27f035dd272ebaef62e6465e345..c0dbf2676872995c1ff698cefe37719f43f1236a 100644 (file)
@@ -81,6 +81,7 @@
 
 #define SI5351_CLK3_0_DISABLE_STATE            24
 #define SI5351_CLK7_4_DISABLE_STATE            25
+#define  SI5351_CLK_DISABLE_STATE_MASK         3
 #define  SI5351_CLK_DISABLE_STATE_LOW          0
 #define  SI5351_CLK_DISABLE_STATE_HIGH         1
 #define  SI5351_CLK_DISABLE_STATE_FLOAT                2
index 3af729b1b89d16f48692b3bdb7fce217cf1e92f0..1ada79a2805297aa4b3a6d921b93159bd951a402 100644 (file)
@@ -95,14 +95,14 @@ static int twl6040_clk_probe(struct platform_device *pdev)
        if (IS_ERR(clkdata->clk))
                return PTR_ERR(clkdata->clk);
 
-       dev_set_drvdata(&pdev->dev, clkdata);
+       platform_set_drvdata(pdev, clkdata);
 
        return 0;
 }
 
 static int twl6040_clk_remove(struct platform_device *pdev)
 {
-       struct twl6040_clk *clkdata = dev_get_drvdata(&pdev->dev);
+       struct twl6040_clk *clkdata = platform_get_drvdata(pdev);
 
        clk_unregister(clkdata->clk);
 
index 553ac35bcc912ea9f975927f8f91ff1e680dec6d..82306f5fb9c2497f82bcfafe403cdbc091b3dc66 100644 (file)
@@ -42,6 +42,7 @@ struct clk_device {
 #define PLL_TYPE_VT8500                0
 #define PLL_TYPE_WM8650                1
 #define PLL_TYPE_WM8750                2
+#define PLL_TYPE_WM8850                3
 
 struct clk_pll {
        struct clk_hw   hw;
@@ -156,10 +157,6 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
 
        divisor =  parent_rate / rate;
 
-       /* If prate / rate would be decimal, incr the divisor */
-       if (rate * divisor < parent_rate)
-               divisor++;
-
        if (divisor == cdev->div_mask + 1)
                divisor = 0;
 
@@ -327,6 +324,15 @@ CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init);
 #define WM8750_BITS_TO_VAL(f, m, d1, d2)                               \
                ((f << 24) | ((m - 1) << 16) | ((d1 - 1) << 8) | d2)
 
+/* Helper macros for PLL_WM8850 */
+#define WM8850_PLL_MUL(x)      ((((x >> 16) & 0x7F) + 1) * 2)
+#define WM8850_PLL_DIV(x)      ((((x >> 8) & 1) + 1) * (1 << (x & 3)))
+
+#define WM8850_BITS_TO_FREQ(r, m, d1, d2)                              \
+                               (r * ((m + 1) * 2) / ((d1+1) * (1 << d2)))
+
+#define WM8850_BITS_TO_VAL(m, d1, d2)                                  \
+               ((((m / 2) - 1) << 16) | ((d1 - 1) << 8) | d2)
 
 static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate,
                                u32 *multiplier, u32 *prediv)
@@ -466,6 +472,49 @@ static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,
        *divisor2 = best_div2;
 }
 
+static void wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate,
+                               u32 *multiplier, u32 *divisor1, u32 *divisor2)
+{
+       u32 mul, div1, div2;
+       u32 best_mul, best_div1, best_div2;
+       unsigned long tclk, rate_err, best_err;
+
+       best_err = (unsigned long)-1;
+
+       /* Find the closest match (lower or equal to requested) */
+       for (div1 = 1; div1 >= 0; div1--)
+               for (div2 = 3; div2 >= 0; div2--)
+                       for (mul = 0; mul <= 127; mul++) {
+                               tclk = parent_rate * ((mul + 1) * 2) /
+                                               ((div1 + 1) * (1 << div2));
+                               if (tclk > rate)
+                                       continue;
+                               /* error will always be +ve */
+                               rate_err = rate - tclk;
+                               if (rate_err == 0) {
+                                       *multiplier = mul;
+                                       *divisor1 = div1;
+                                       *divisor2 = div2;
+                                       return;
+                               }
+
+                               if (rate_err < best_err) {
+                                       best_err = rate_err;
+                                       best_mul = mul;
+                                       best_div1 = div1;
+                                       best_div2 = div2;
+                               }
+                       }
+
+       /* if we got here, it wasn't an exact match */
+       pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
+                                                       rate - best_err);
+
+       *multiplier = best_mul;
+       *divisor1 = best_div1;
+       *divisor2 = best_div2;
+}
+
 static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                                unsigned long parent_rate)
 {
@@ -489,6 +538,10 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2);
                pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2);
                break;
+       case PLL_TYPE_WM8850:
+               wm8850_find_pll_bits(rate, parent_rate, &mul, &div1, &div2);
+               pll_val = WM8850_BITS_TO_VAL(mul, div1, div2);
+               break;
        default:
                pr_err("%s: invalid pll type\n", __func__);
                return 0;
@@ -525,6 +578,10 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
                wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);
                round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);
                break;
+       case PLL_TYPE_WM8850:
+               wm8850_find_pll_bits(rate, *prate, &mul, &div1, &div2);
+               round_rate = WM8850_BITS_TO_FREQ(*prate, mul, div1, div2);
+               break;
        default:
                round_rate = 0;
        }
@@ -552,6 +609,10 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw,
                pll_freq = parent_rate * WM8750_PLL_MUL(pll_val);
                pll_freq /= WM8750_PLL_DIV(pll_val);
                break;
+       case PLL_TYPE_WM8850:
+               pll_freq = parent_rate * WM8850_PLL_MUL(pll_val);
+               pll_freq /= WM8850_PLL_DIV(pll_val);
+               break;
        default:
                pll_freq = 0;
        }
@@ -628,6 +689,12 @@ static void __init wm8750_pll_init(struct device_node *node)
 }
 CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init);
 
+static void __init wm8850_pll_init(struct device_node *node)
+{
+       vtwm_pll_clk_init(node, PLL_TYPE_WM8850);
+}
+CLK_OF_DECLARE(wm8850_pll, "wm,wm8850-pll-clock", wm8850_pll_init);
+
 void __init vtwm_clk_init(void __iomem *base)
 {
        if (!base)
index 16ed06808554aa5aa92651342e3b2e88c32784a6..1b3f8c9b98cc60d78d062ee8c587bfb397a668ac 100644 (file)
@@ -97,7 +97,7 @@ static int wm831x_fll_prepare(struct clk_hw *hw)
        struct wm831x *wm831x = clkdata->wm831x;
        int ret;
 
-       ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2,
+       ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1,
                              WM831X_FLL_ENA, WM831X_FLL_ENA);
        if (ret != 0)
                dev_crit(wm831x->dev, "Failed to enable FLL: %d\n", ret);
@@ -114,9 +114,9 @@ static void wm831x_fll_unprepare(struct clk_hw *hw)
        struct wm831x *wm831x = clkdata->wm831x;
        int ret;
 
-       ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2, WM831X_FLL_ENA, 0);
+       ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1, WM831X_FLL_ENA, 0);
        if (ret != 0)
-               dev_crit(wm831x->dev, "Failed to disaable FLL: %d\n", ret);
+               dev_crit(wm831x->dev, "Failed to disable FLL: %d\n", ret);
 }
 
 static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw,
@@ -299,8 +299,8 @@ static void wm831x_clkout_unprepare(struct clk_hw *hw)
 }
 
 static const char *wm831x_clkout_parents[] = {
-       "xtal",
        "fll",
+       "xtal",
 };
 
 static u8 wm831x_clkout_get_parent(struct clk_hw *hw)
@@ -318,9 +318,9 @@ static u8 wm831x_clkout_get_parent(struct clk_hw *hw)
        }
 
        if (ret & WM831X_CLKOUT_SRC)
-               return 0;
-       else
                return 1;
+       else
+               return 0;
 }
 
 static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent)
@@ -384,7 +384,7 @@ static int wm831x_clk_probe(struct platform_device *pdev)
        if (IS_ERR(clkdata->clkout))
                return PTR_ERR(clkdata->clkout);
 
-       dev_set_drvdata(&pdev->dev, clkdata);
+       platform_set_drvdata(pdev, clkdata);
 
        return 0;
 }
index 1144e8c7579dddbf5c0a0b0ad3363c7f5d79c57e..54a191c5bbf0e3f4c1b23807c12a59cdb0d74031 100644 (file)
@@ -107,7 +107,7 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
        seq_printf(s, "%*s%-*s %-11d %-12d %-10lu",
                   level * 3 + 1, "",
                   30 - level * 3, c->name,
-                  c->enable_count, c->prepare_count, c->rate);
+                  c->enable_count, c->prepare_count, clk_get_rate(c));
        seq_printf(s, "\n");
 }
 
@@ -166,7 +166,7 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
        seq_printf(s, "\"%s\": { ", c->name);
        seq_printf(s, "\"enable_count\": %d,", c->enable_count);
        seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
-       seq_printf(s, "\"rate\": %lu", c->rate);
+       seq_printf(s, "\"rate\": %lu", clk_get_rate(c));
 }
 
 static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
@@ -534,7 +534,7 @@ static int clk_disable_unused(void)
 
        return 0;
 }
-late_initcall(clk_disable_unused);
+late_initcall_sync(clk_disable_unused);
 
 /***    helper functions   ***/
 
@@ -1216,7 +1216,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        clk_prepare_lock();
 
        /* bail early if nothing to do */
-       if (rate == clk->rate)
+       if (rate == clk_get_rate(clk))
                goto out;
 
        if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count) {
@@ -1377,23 +1377,33 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
        unsigned long flags;
        int ret = 0;
        struct clk *old_parent = clk->parent;
-       bool migrated_enable = false;
 
-       /* migrate prepare */
-       if (clk->prepare_count)
+       /*
+        * Migrate prepare state between parents and prevent race with
+        * clk_enable().
+        *
+        * If the clock is not prepared, then a race with
+        * clk_enable/disable() is impossible since we already have the
+        * prepare lock (future calls to clk_enable() need to be preceded by
+        * a clk_prepare()).
+        *
+        * If the clock is prepared, migrate the prepared state to the new
+        * parent and also protect against a race with clk_enable() by
+        * forcing the clock and the new parent on.  This ensures that all
+        * future calls to clk_enable() are practically NOPs with respect to
+        * hardware and software states.
+        *
+        * See also: Comment for clk_set_parent() below.
+        */
+       if (clk->prepare_count) {
                __clk_prepare(parent);
-
-       flags = clk_enable_lock();
-
-       /* migrate enable */
-       if (clk->enable_count) {
-               __clk_enable(parent);
-               migrated_enable = true;
+               clk_enable(parent);
+               clk_enable(clk);
        }
 
        /* update the clk tree topology */
+       flags = clk_enable_lock();
        clk_reparent(clk, parent);
-
        clk_enable_unlock(flags);
 
        /* change clock input source */
@@ -1401,43 +1411,27 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
                ret = clk->ops->set_parent(clk->hw, p_index);
 
        if (ret) {
-               /*
-                * The error handling is tricky due to that we need to release
-                * the spinlock while issuing the .set_parent callback. This
-                * means the new parent might have been enabled/disabled in
-                * between, which must be considered when doing rollback.
-                */
                flags = clk_enable_lock();
-
                clk_reparent(clk, old_parent);
-
-               if (migrated_enable && clk->enable_count) {
-                       __clk_disable(parent);
-               } else if (migrated_enable && (clk->enable_count == 0)) {
-                       __clk_disable(old_parent);
-               } else if (!migrated_enable && clk->enable_count) {
-                       __clk_disable(parent);
-                       __clk_enable(old_parent);
-               }
-
                clk_enable_unlock(flags);
 
-               if (clk->prepare_count)
+               if (clk->prepare_count) {
+                       clk_disable(clk);
+                       clk_disable(parent);
                        __clk_unprepare(parent);
-
+               }
                return ret;
        }
 
-       /* clean up enable for old parent if migration was done */
-       if (migrated_enable) {
-               flags = clk_enable_lock();
-               __clk_disable(old_parent);
-               clk_enable_unlock(flags);
-       }
-
-       /* clean up prepare for old parent if migration was done */
-       if (clk->prepare_count)
+       /*
+        * Finish the migration of prepare state and undo the changes done
+        * for preventing a race with clk_enable().
+        */
+       if (clk->prepare_count) {
+               clk_disable(clk);
+               clk_disable(old_parent);
                __clk_unprepare(old_parent);
+       }
 
        /* update debugfs with new clk tree topology */
        clk_debug_reparent(clk, parent);
@@ -1449,12 +1443,17 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
  * @clk: the mux clk whose input we are switching
  * @parent: the new input to clk
  *
- * Re-parent clk to use parent as it's new input source.  If clk has the
- * CLK_SET_PARENT_GATE flag set then clk must be gated for this
- * operation to succeed.  After successfully changing clk's parent
- * clk_set_parent will update the clk topology, sysfs topology and
- * propagate rate recalculation via __clk_recalc_rates.  Returns 0 on
- * success, -EERROR otherwise.
+ * Re-parent clk to use parent as its new input source.  If clk is in
+ * prepared state, the clk will get enabled for the duration of this call. If
+ * that's not acceptable for a specific clk (Eg: the consumer can't handle
+ * that, the reparenting is glitchy in hardware, etc), use the
+ * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
+ *
+ * After successfully changing clk's parent clk_set_parent will update the
+ * clk topology, sysfs topology and propagate rate recalculation via
+ * __clk_recalc_rates.
+ *
+ * Returns 0 on success, -EERROR otherwise.
  */
 int clk_set_parent(struct clk *clk, struct clk *parent)
 {
@@ -1494,8 +1493,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
        }
 
        /* propagate PRE_RATE_CHANGE notifications */
-       if (clk->notifier_count)
-               ret = __clk_speculate_rates(clk, p_rate);
+       ret = __clk_speculate_rates(clk, p_rate);
 
        /* abort if a driver objects */
        if (ret & NOTIFY_STOP_MASK)
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
new file mode 100644 (file)
index 0000000..8d3aefa
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Rockchip Clock specific Makefile
+#
+
+obj-y  += clk-rockchip.o
diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c
new file mode 100644 (file)
index 0000000..967c141
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+static DEFINE_SPINLOCK(clk_lock);
+
+/*
+ * Gate clocks
+ */
+
+static void __init rk2928_gate_clk_init(struct device_node *node,
+                                        void *data)
+{
+       struct clk_onecell_data *clk_data;
+       const char *clk_parent;
+       const char *clk_name;
+       void __iomem *reg;
+       void __iomem *reg_idx;
+       int flags;
+       int qty;
+       int reg_bit;
+       int clkflags = CLK_SET_RATE_PARENT;
+       int i;
+
+       qty = of_property_count_strings(node, "clock-output-names");
+       if (qty < 0) {
+               pr_err("%s: error in clock-output-names %d\n", __func__, qty);
+               return;
+       }
+
+       if (qty == 0) {
+               pr_info("%s: nothing to do\n", __func__);
+               return;
+       }
+
+       reg = of_iomap(node, 0);
+
+       clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+       if (!clk_data)
+               return;
+
+       clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
+       if (!clk_data->clks) {
+               kfree(clk_data);
+               return;
+       }
+
+       flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
+
+       for (i = 0; i < qty; i++) {
+               of_property_read_string_index(node, "clock-output-names",
+                                             i, &clk_name);
+
+               /* ignore empty slots */
+               if (!strcmp("reserved", clk_name))
+                       continue;
+
+               clk_parent = of_clk_get_parent_name(node, i);
+
+               /* keep all gates untouched for now */
+               clkflags |= CLK_IGNORE_UNUSED;
+
+               reg_idx = reg + (4 * (i / 16));
+               reg_bit = (i % 16);
+
+               clk_data->clks[i] = clk_register_gate(NULL, clk_name,
+                                                     clk_parent, clkflags,
+                                                     reg_idx, reg_bit,
+                                                     flags,
+                                                     &clk_lock);
+               WARN_ON(IS_ERR(clk_data->clks[i]));
+       }
+
+       clk_data->clk_num = qty;
+
+       of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+}
+CLK_OF_DECLARE(rk2928_gate, "rockchip,rk2928-gate-clk", rk2928_gate_clk_init);
index addc738a06fbdc5e9ae3f9e2635ecc9590d28530..1bdb882c845bd48a96597bb8f65c2cbe2a3c03c2 100644 (file)
@@ -356,8 +356,8 @@ struct samsung_fixed_rate_clock exynos4210_fixed_rate_clks[] __initdata = {
 
 /* list of mux clocks supported in all exynos4 soc's */
 struct samsung_mux_clock exynos4_mux_clks[] __initdata = {
-       MUX_F(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
-                       CLK_SET_RATE_PARENT, 0),
+       MUX_FA(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
+                       CLK_SET_RATE_PARENT, 0, "mout_apll"),
        MUX(none, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1),
        MUX(none, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1),
        MUX(none, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1),
@@ -385,9 +385,9 @@ struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
        MUX(none, "mout_g2d", mout_g2d_p, E4210_SRC_IMAGE, 8, 1),
        MUX(none, "mout_fimd1", group1_p4210, E4210_SRC_LCD1, 0, 4),
        MUX(none, "mout_mipi1", group1_p4210, E4210_SRC_LCD1, 12, 4),
-       MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "sclk_mpll"),
+       MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "mout_mpll"),
        MUX_A(mout_core, "mout_core", mout_core_p4210,
-                       SRC_CPU, 16, 1, "mout_core"),
+                       SRC_CPU, 16, 1, "moutcore"),
        MUX_A(sclk_vpll, "sclk_vpll", sclk_vpll_p4210,
                        SRC_TOP0, 8, 1, "sclk_vpll"),
        MUX(mout_fimc0, "mout_fimc0", group1_p4210, SRC_CAM, 0, 4),
@@ -424,8 +424,8 @@ struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
 
 /* list of mux clocks supported in exynos4x12 soc */
 struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
-       MUX(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12,
-                       SRC_CPU, 24, 1),
+       MUX_A(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12,
+                       SRC_CPU, 24, 1, "mout_mpll"),
        MUX(none, "mout_aclk266_gps", aclk_p4412, SRC_TOP1, 4, 1),
        MUX(none, "mout_aclk400_mcuisp", aclk_p4412, SRC_TOP1, 8, 1),
        MUX(mout_mpll_user_t, "mout_mpll_user_t", mout_mpll_user_p4x12,
@@ -449,7 +449,8 @@ struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
                        SRC_DMC, 12, 1, "sclk_mpll"),
        MUX_A(sclk_vpll, "sclk_vpll", mout_vpll_p,
                        SRC_TOP0, 8, 1, "sclk_vpll"),
-       MUX(mout_core, "mout_core", mout_core_p4x12, SRC_CPU, 16, 1),
+       MUX_A(mout_core, "mout_core", mout_core_p4x12,
+                       SRC_CPU, 16, 1, "moutcore"),
        MUX(mout_fimc0, "mout_fimc0", group1_p4x12, SRC_CAM, 0, 4),
        MUX(mout_fimc1, "mout_fimc1", group1_p4x12, SRC_CAM, 4, 4),
        MUX(mout_fimc2, "mout_fimc2", group1_p4x12, SRC_CAM, 8, 4),
@@ -537,7 +538,7 @@ struct samsung_div_clock exynos4_div_clks[] __initdata = {
        DIV(none, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8),
        DIV(none, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4),
        DIV(none, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4),
-       DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "arm_clk"),
+       DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "armclk"),
        DIV_A(sclk_apll, "sclk_apll", "mout_apll",
                        DIV_CPU0, 24, 3, "sclk_apll"),
        DIV_F(none, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
@@ -1070,9 +1071,9 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so
        pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
                "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n",
                exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
-               _get_rate("sclk_apll"), _get_rate("sclk_mpll"),
+               _get_rate("sclk_apll"), _get_rate("mout_mpll"),
                _get_rate("sclk_epll"), _get_rate("sclk_vpll"),
-               _get_rate("arm_clk"));
+               _get_rate("armclk"));
 }
 
 
index e4ad6ea9aa764b1eda9371452d3b95dc412920ff..2f7dba20ced8b9145f261b817be65387f3048662 100644 (file)
@@ -144,6 +144,9 @@ struct samsung_mux_clock {
 #define MUX_F(_id, cname, pnames, o, s, w, f, mf)              \
        __MUX(_id, NULL, cname, pnames, o, s, w, f, mf, NULL)
 
+#define MUX_FA(_id, cname, pnames, o, s, w, f, mf, a)          \
+       __MUX(_id, NULL, cname, pnames, o, s, w, f, mf, a)
+
 /**
  * @id: platform specific id of the clock.
  * struct samsung_div_clock: information about div clock
index 8492ad1d53601d19c0c0481e8c12bd696dd00683..412912bbba53c6806f58cb7dc1d4a8daa45d084e 100644 (file)
@@ -239,7 +239,7 @@ struct mux_data {
        u8 shift;
 };
 
-static const __initconst struct mux_data cpu_data = {
+static const __initconst struct mux_data cpu_mux_data = {
        .shift = 16,
 };
 
@@ -333,22 +333,34 @@ struct gates_data {
        DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
 };
 
-static const __initconst struct gates_data axi_gates_data = {
+static const __initconst struct gates_data sun4i_axi_gates_data = {
        .mask = {1},
 };
 
-static const __initconst struct gates_data ahb_gates_data = {
+static const __initconst struct gates_data sun4i_ahb_gates_data = {
        .mask = {0x7F77FFF, 0x14FB3F},
 };
 
-static const __initconst struct gates_data apb0_gates_data = {
+static const __initconst struct gates_data sun5i_a13_ahb_gates_data = {
+       .mask = {0x107067e7, 0x185111},
+};
+
+static const __initconst struct gates_data sun4i_apb0_gates_data = {
        .mask = {0x4EF},
 };
 
-static const __initconst struct gates_data apb1_gates_data = {
+static const __initconst struct gates_data sun5i_a13_apb0_gates_data = {
+       .mask = {0x61},
+};
+
+static const __initconst struct gates_data sun4i_apb1_gates_data = {
        .mask = {0xFF00F7},
 };
 
+static const __initconst struct gates_data sun5i_a13_apb1_gates_data = {
+       .mask = {0xa0007},
+};
+
 static void __init sunxi_gates_clk_setup(struct device_node *node,
                                         struct gates_data *data)
 {
@@ -421,17 +433,20 @@ static const __initconst struct of_device_id clk_div_match[] = {
 
 /* Matches for mux clocks */
 static const __initconst struct of_device_id clk_mux_match[] = {
-       {.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_data,},
+       {.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_mux_data,},
        {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &apb1_mux_data,},
        {}
 };
 
 /* Matches for gate clocks */
 static const __initconst struct of_device_id clk_gates_match[] = {
-       {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &axi_gates_data,},
-       {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &ahb_gates_data,},
-       {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &apb0_gates_data,},
-       {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &apb1_gates_data,},
+       {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,},
+       {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
+       {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
+       {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
+       {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
+       {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
+       {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
        {}
 };
 
index 17c2cc086eb4e997034d6f2348956cf6f856582b..197074a5775421371d8c17526a6799ea4212b202 100644 (file)
 #define PLLCX_MISC2_DEFAULT 0x30211200
 #define PLLCX_MISC3_DEFAULT 0x200
 
-#define PMC_PLLM_WB0_OVERRIDE  0x1dc
-#define PMC_PLLM_WB0_OVERRIDE_2        0x2b0
-#define PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK BIT(27)
-
 #define PMC_SATA_PWRGT 0x1ac
 #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5)
 #define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4)
 #define pll_readl(offset, p) readl_relaxed(p->clk_base + offset)
 #define pll_readl_base(p) pll_readl(p->params->base_reg, p)
 #define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
+#define pll_override_readl(offset, p) readl_relaxed(p->pmc + offset)
 
 #define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)
 #define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)
 #define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
+#define pll_override_writel(val, offset, p) writel(val, p->pmc + offset)
 
 #define mask(w) ((1 << (w)) - 1)
-#define divm_mask(p) mask(p->divm_width)
-#define divn_mask(p) mask(p->divn_width)
+#define divm_mask(p) mask(p->params->div_nmp->divm_width)
+#define divn_mask(p) mask(p->params->div_nmp->divn_width)
 #define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :    \
-                     mask(p->divp_width))
+                     mask(p->params->div_nmp->divp_width))
 
 #define divm_max(p) (divm_mask(p))
 #define divn_max(p) (divn_mask(p))
 #define divp_max(p) (1 << (divp_mask(p)))
 
-
-#ifdef CONFIG_ARCH_TEGRA_114_SOC
-/* PLLXC has 4-bit PDIV, but entry 15 is not allowed in h/w */
-#define PLLXC_PDIV_MAX                 14
-
-/* non-monotonic mapping below is not a typo */
-static u8 pllxc_p[PLLXC_PDIV_MAX + 1] = {
-       /* PDIV: 0, 1, 2, 3, 4, 5, 6,  7,  8,  9, 10, 11, 12, 13, 14 */
-       /* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32
-};
-
-#define PLLCX_PDIV_MAX 7
-static u8 pllcx_p[PLLCX_PDIV_MAX + 1] = {
-       /* PDIV: 0, 1, 2, 3, 4, 5,  6,  7 */
-       /* p: */ 1, 2, 3, 4, 6, 8, 12, 16
+static struct div_nmp default_nmp = {
+       .divn_shift = PLL_BASE_DIVN_SHIFT,
+       .divn_width = PLL_BASE_DIVN_WIDTH,
+       .divm_shift = PLL_BASE_DIVM_SHIFT,
+       .divm_width = PLL_BASE_DIVM_WIDTH,
+       .divp_shift = PLL_BASE_DIVP_SHIFT,
+       .divp_width = PLL_BASE_DIVP_WIDTH,
 };
-#endif
 
 static void clk_pll_enable_lock(struct tegra_clk_pll *pll)
 {
@@ -297,6 +286,39 @@ static void clk_pll_disable(struct clk_hw *hw)
                spin_unlock_irqrestore(pll->lock, flags);
 }
 
+static int _p_div_to_hw(struct clk_hw *hw, u8 p_div)
+{
+       struct tegra_clk_pll *pll = to_clk_pll(hw);
+       struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
+
+       if (p_tohw) {
+               while (p_tohw->pdiv) {
+                       if (p_div <= p_tohw->pdiv)
+                               return p_tohw->hw_val;
+                       p_tohw++;
+               }
+               return -EINVAL;
+       }
+       return -EINVAL;
+}
+
+static int _hw_to_p_div(struct clk_hw *hw, u8 p_div_hw)
+{
+       struct tegra_clk_pll *pll = to_clk_pll(hw);
+       struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
+
+       if (p_tohw) {
+               while (p_tohw->pdiv) {
+                       if (p_div_hw == p_tohw->hw_val)
+                               return p_tohw->pdiv;
+                       p_tohw++;
+               }
+               return -EINVAL;
+       }
+
+       return 1 << p_div_hw;
+}
+
 static int _get_table_rate(struct clk_hw *hw,
                           struct tegra_clk_pll_freq_table *cfg,
                           unsigned long rate, unsigned long parent_rate)
@@ -326,9 +348,9 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
                      unsigned long rate, unsigned long parent_rate)
 {
        struct tegra_clk_pll *pll = to_clk_pll(hw);
-       struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
        unsigned long cfreq;
        u32 p_div = 0;
+       int ret;
 
        switch (parent_rate) {
        case 12000000:
@@ -369,20 +391,16 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
            || cfg->output_rate > pll->params->vco_max) {
                pr_err("%s: Failed to set %s rate %lu\n",
                       __func__, __clk_get_name(hw->clk), rate);
+               WARN_ON(1);
                return -EINVAL;
        }
 
-       if (p_tohw) {
-               p_div = 1 << p_div;
-               while (p_tohw->pdiv) {
-                       if (p_div <= p_tohw->pdiv) {
-                               cfg->p = p_tohw->hw_val;
-                               break;
-                       }
-                       p_tohw++;
-               }
-               if (!p_tohw->pdiv)
-                       return -EINVAL;
+       if (pll->params->pdiv_tohw) {
+               ret = _p_div_to_hw(hw, 1 << p_div);
+               if (ret < 0)
+                       return ret;
+               else
+                       cfg->p = ret;
        } else
                cfg->p = p_div;
 
@@ -393,29 +411,61 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,
                            struct tegra_clk_pll_freq_table *cfg)
 {
        u32 val;
+       struct tegra_clk_pll_params *params = pll->params;
+       struct div_nmp *div_nmp = params->div_nmp;
+
+       if ((pll->flags & TEGRA_PLLM) &&
+               (pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
+                       PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
+               val = pll_override_readl(params->pmc_divp_reg, pll);
+               val &= ~(divp_mask(pll) << div_nmp->override_divp_shift);
+               val |= cfg->p << div_nmp->override_divp_shift;
+               pll_override_writel(val, params->pmc_divp_reg, pll);
+
+               val = pll_override_readl(params->pmc_divnm_reg, pll);
+               val &= ~(divm_mask(pll) << div_nmp->override_divm_shift) |
+                       ~(divn_mask(pll) << div_nmp->override_divn_shift);
+               val |= (cfg->m << div_nmp->override_divm_shift) |
+                       (cfg->n << div_nmp->override_divn_shift);
+               pll_override_writel(val, params->pmc_divnm_reg, pll);
+       } else {
+               val = pll_readl_base(pll);
 
-       val = pll_readl_base(pll);
+               val &= ~((divm_mask(pll) << div_nmp->divm_shift) |
+                (divn_mask(pll) << div_nmp->divn_shift) |
+                (divp_mask(pll) << div_nmp->divp_shift));
 
-       val &= ~((divm_mask(pll) << pll->divm_shift) |
-                (divn_mask(pll) << pll->divn_shift) |
-                (divp_mask(pll) << pll->divp_shift));
-       val |= ((cfg->m << pll->divm_shift) |
-               (cfg->n << pll->divn_shift) |
-               (cfg->p << pll->divp_shift));
+               val |= ((cfg->m << div_nmp->divm_shift) |
+                       (cfg->n << div_nmp->divn_shift) |
+                       (cfg->p << div_nmp->divp_shift));
 
-       pll_writel_base(val, pll);
+               pll_writel_base(val, pll);
+       }
 }
 
 static void _get_pll_mnp(struct tegra_clk_pll *pll,
                         struct tegra_clk_pll_freq_table *cfg)
 {
        u32 val;
+       struct tegra_clk_pll_params *params = pll->params;
+       struct div_nmp *div_nmp = params->div_nmp;
+
+       if ((pll->flags & TEGRA_PLLM) &&
+               (pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
+                       PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
+               val = pll_override_readl(params->pmc_divp_reg, pll);
+               cfg->p = (val >> div_nmp->override_divp_shift) & divp_mask(pll);
+
+               val = pll_override_readl(params->pmc_divnm_reg, pll);
+               cfg->m = (val >> div_nmp->override_divm_shift) & divm_mask(pll);
+               cfg->n = (val >> div_nmp->override_divn_shift) & divn_mask(pll);
+       }  else {
+               val = pll_readl_base(pll);
 
-       val = pll_readl_base(pll);
-
-       cfg->m = (val >> pll->divm_shift) & (divm_mask(pll));
-       cfg->n = (val >> pll->divn_shift) & (divn_mask(pll));
-       cfg->p = (val >> pll->divp_shift) & (divp_mask(pll));
+               cfg->m = (val >> div_nmp->divm_shift) & divm_mask(pll);
+               cfg->n = (val >> div_nmp->divn_shift) & divn_mask(pll);
+               cfg->p = (val >> div_nmp->divp_shift) & divp_mask(pll);
+       }
 }
 
 static void _update_pll_cpcon(struct tegra_clk_pll *pll,
@@ -485,9 +535,10 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
        }
 
        if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
-           _calc_rate(hw, &cfg, rate, parent_rate))
+           _calc_rate(hw, &cfg, rate, parent_rate)) {
+               WARN_ON(1);
                return -EINVAL;
-
+       }
        if (pll->lock)
                spin_lock_irqsave(pll->lock, flags);
 
@@ -507,7 +558,6 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct tegra_clk_pll *pll = to_clk_pll(hw);
        struct tegra_clk_pll_freq_table cfg;
-       u64 output_rate = *prate;
 
        if (pll->flags & TEGRA_PLL_FIXED)
                return pll->fixed_rate;
@@ -517,13 +567,12 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
                return __clk_get_rate(hw->clk);
 
        if (_get_table_rate(hw, &cfg, rate, *prate) &&
-           _calc_rate(hw, &cfg, rate, *prate))
+           _calc_rate(hw, &cfg, rate, *prate)) {
+               WARN_ON(1);
                return -EINVAL;
+       }
 
-       output_rate *= cfg.n;
-       do_div(output_rate, cfg.m * (1 << cfg.p));
-
-       return output_rate;
+       return cfg.output_rate;
 }
 
 static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
@@ -531,7 +580,6 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
 {
        struct tegra_clk_pll *pll = to_clk_pll(hw);
        struct tegra_clk_pll_freq_table cfg;
-       struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
        u32 val;
        u64 rate = parent_rate;
        int pdiv;
@@ -553,21 +601,11 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
 
        _get_pll_mnp(pll, &cfg);
 
-       if (p_tohw) {
-               while (p_tohw->pdiv) {
-                       if (cfg.p == p_tohw->hw_val) {
-                               pdiv = p_tohw->pdiv;
-                               break;
-                       }
-                       p_tohw++;
-               }
-
-               if (!p_tohw->pdiv) {
-                       WARN_ON(1);
-                       pdiv = 1;
-               }
-       } else
-               pdiv = 1 << cfg.p;
+       pdiv = _hw_to_p_div(hw, cfg.p);
+       if (pdiv < 0) {
+               WARN_ON(1);
+               pdiv = 1;
+       }
 
        cfg.m *= pdiv;
 
@@ -647,9 +685,9 @@ static int clk_plle_enable(struct clk_hw *hw)
                val = pll_readl_base(pll);
                val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));
                val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
-               val |= sel.m << pll->divm_shift;
-               val |= sel.n << pll->divn_shift;
-               val |= sel.p << pll->divp_shift;
+               val |= sel.m << pll->params->div_nmp->divm_shift;
+               val |= sel.n << pll->params->div_nmp->divn_shift;
+               val |= sel.p << pll->params->div_nmp->divp_shift;
                val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
                pll_writel_base(val, pll);
        }
@@ -680,9 +718,9 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
        u32 divn = 0, divm = 0, divp = 0;
        u64 rate = parent_rate;
 
-       divp = (val >> pll->divp_shift) & (divp_mask(pll));
-       divn = (val >> pll->divn_shift) & (divn_mask(pll));
-       divm = (val >> pll->divm_shift) & (divm_mask(pll));
+       divp = (val >> pll->params->div_nmp->divp_shift) & (divp_mask(pll));
+       divn = (val >> pll->params->div_nmp->divn_shift) & (divn_mask(pll));
+       divm = (val >> pll->params->div_nmp->divm_shift) & (divm_mask(pll));
        divm *= divp;
 
        rate *= divn;
@@ -769,16 +807,22 @@ static int _calc_dynamic_ramp_rate(struct clk_hw *hw,
 {
        struct tegra_clk_pll *pll = to_clk_pll(hw);
        unsigned int p;
+       int p_div;
 
        if (!rate)
                return -EINVAL;
 
        p = DIV_ROUND_UP(pll->params->vco_min, rate);
        cfg->m = _pll_fixed_mdiv(pll->params, parent_rate);
-       cfg->p = p;
-       cfg->output_rate = rate * cfg->p;
+       cfg->output_rate = rate * p;
        cfg->n = cfg->output_rate * cfg->m / parent_rate;
 
+       p_div = _p_div_to_hw(hw, p);
+       if (p_div < 0)
+               return p_div;
+       else
+               cfg->p = p_div;
+
        if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max)
                return -EINVAL;
 
@@ -790,18 +834,25 @@ static int _pll_ramp_calc_pll(struct clk_hw *hw,
                              unsigned long rate, unsigned long parent_rate)
 {
        struct tegra_clk_pll *pll = to_clk_pll(hw);
-       int err = 0;
+       int err = 0, p_div;
 
        err = _get_table_rate(hw, cfg, rate, parent_rate);
        if (err < 0)
                err = _calc_dynamic_ramp_rate(hw, cfg, rate, parent_rate);
-       else if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) {
+       else {
+               if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) {
                        WARN_ON(1);
                        err = -EINVAL;
                        goto out;
+               }
+               p_div = _p_div_to_hw(hw, cfg->p);
+               if (p_div < 0)
+                       return p_div;
+               else
+                       cfg->p = p_div;
        }
 
-       if (!cfg->p || (cfg->p >  pll->params->max_p))
+       if (cfg->p >  pll->params->max_p)
                err = -EINVAL;
 
 out:
@@ -815,7 +866,6 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
        struct tegra_clk_pll_freq_table cfg, old_cfg;
        unsigned long flags = 0;
        int ret = 0;
-       u8 old_p;
 
        ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate);
        if (ret < 0)
@@ -826,11 +876,8 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
 
        _get_pll_mnp(pll, &old_cfg);
 
-       old_p = pllxc_p[old_cfg.p];
-       if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_p != cfg.p) {
-               cfg.p -= 1;
+       if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)
                ret = _program_pll(hw, &cfg, rate);
-       }
 
        if (pll->lock)
                spin_unlock_irqrestore(pll->lock, flags);
@@ -842,15 +889,19 @@ static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate,
                                unsigned long *prate)
 {
        struct tegra_clk_pll_freq_table cfg;
-       int ret = 0;
+       int ret = 0, p_div;
        u64 output_rate = *prate;
 
        ret = _pll_ramp_calc_pll(hw, &cfg, rate, *prate);
        if (ret < 0)
                return ret;
 
+       p_div = _hw_to_p_div(hw, cfg.p);
+       if (p_div < 0)
+               return p_div;
+
        output_rate *= cfg.n;
-       do_div(output_rate, cfg.m * cfg.p);
+       do_div(output_rate, cfg.m * p_div);
 
        return output_rate;
 }
@@ -862,7 +913,6 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
        struct tegra_clk_pll *pll = to_clk_pll(hw);
        unsigned long flags = 0;
        int state, ret = 0;
-       u32 val;
 
        if (pll->lock)
                spin_lock_irqsave(pll->lock, flags);
@@ -881,22 +931,7 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
        if (ret < 0)
                goto out;
 
-       cfg.p -= 1;
-
-       val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
-       if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) {
-               val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE_2);
-               val = cfg.p ? (val | PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK) :
-                       (val & ~PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK);
-               writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE_2);
-
-               val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
-               val &= ~(divn_mask(pll) | divm_mask(pll));
-               val |= (cfg.m << pll->divm_shift) | (cfg.n << pll->divn_shift);
-               writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE);
-       } else
-               _update_pll_mnp(pll, &cfg);
-
+       _update_pll_mnp(pll, &cfg);
 
 out:
        if (pll->lock)
@@ -1010,13 +1045,10 @@ static int _pllcx_update_dynamic_coef(struct tegra_clk_pll *pll,
 static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate,
                                unsigned long parent_rate)
 {
-       struct tegra_clk_pll_freq_table cfg;
+       struct tegra_clk_pll_freq_table cfg, old_cfg;
        struct tegra_clk_pll *pll = to_clk_pll(hw);
        unsigned long flags = 0;
        int state, ret = 0;
-       u32 val;
-       u16 old_m, old_n;
-       u8 old_p;
 
        if (pll->lock)
                spin_lock_irqsave(pll->lock, flags);
@@ -1025,21 +1057,16 @@ static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate,
        if (ret < 0)
                goto out;
 
-       val = pll_readl_base(pll);
-       old_m = (val >> pll->divm_shift) & (divm_mask(pll));
-       old_n = (val >> pll->divn_shift) & (divn_mask(pll));
-       old_p = pllcx_p[(val >> pll->divp_shift) & (divp_mask(pll))];
+       _get_pll_mnp(pll, &old_cfg);
 
-       if (cfg.m != old_m) {
+       if (cfg.m != old_cfg.m) {
                WARN_ON(1);
                goto out;
        }
 
-       if (old_n == cfg.n && old_p == cfg.p)
+       if (old_cfg.n == cfg.n && old_cfg.p == cfg.p)
                goto out;
 
-       cfg.p -= 1;
-
        state = clk_pll_is_enabled(hw);
        if (state)
                _clk_pllc_disable(hw);
@@ -1178,8 +1205,8 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
        val = pll_readl_base(pll);
        val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));
        val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
-       val |= sel.m << pll->divm_shift;
-       val |= sel.n << pll->divn_shift;
+       val |= sel.m << pll->params->div_nmp->divm_shift;
+       val |= sel.n << pll->params->div_nmp->divn_shift;
        val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
        pll_writel_base(val, pll);
        udelay(1);
@@ -1240,12 +1267,8 @@ static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
        pll->flags = pll_flags;
        pll->lock = lock;
 
-       pll->divp_shift = PLL_BASE_DIVP_SHIFT;
-       pll->divp_width = PLL_BASE_DIVP_WIDTH;
-       pll->divn_shift = PLL_BASE_DIVN_SHIFT;
-       pll->divn_width = PLL_BASE_DIVN_WIDTH;
-       pll->divm_shift = PLL_BASE_DIVM_SHIFT;
-       pll->divm_width = PLL_BASE_DIVM_WIDTH;
+       if (!pll_params->div_nmp)
+               pll_params->div_nmp = &default_nmp;
 
        return pll;
 }
@@ -1401,7 +1424,7 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
        struct tegra_clk_pll *pll;
        struct clk *clk;
 
-       pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+       pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC;
        pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
                              freq_table, lock);
        if (IS_ERR(pll))
@@ -1428,7 +1451,6 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
        val &= ~BIT(29);
        pll_writel_misc(val, pll);
 
-       pll_flags |= TEGRA_PLL_LOCK_MISC;
        clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
                                      &tegra_clk_pllre_ops);
        if (IS_ERR(clk))
@@ -1453,6 +1475,7 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
 
        pll_flags |= TEGRA_PLL_BYPASS;
        pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+       pll_flags |= TEGRA_PLLM;
        pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
                              freq_table, lock);
        if (IS_ERR(pll))
index 40d939d091bfc69608ea2a959cacef2cd87531a3..b6015cb4fc01af4f7f92f898b4373748ad73b008 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/delay.h>
+#include <linux/export.h>
 #include <linux/clk/tegra.h>
 
 #include "clk.h"
@@ -28,6 +29,7 @@
 #define RST_DEVICES_L                  0x004
 #define RST_DEVICES_H                  0x008
 #define RST_DEVICES_U                  0x00C
+#define RST_DFLL_DVCO                  0x2F4
 #define RST_DEVICES_V                  0x358
 #define RST_DEVICES_W                  0x35C
 #define RST_DEVICES_X                  0x28C
 #define RST_DEVICES_CLR_V              0x434
 #define RST_DEVICES_SET_W              0x438
 #define RST_DEVICES_CLR_W              0x43c
+#define CPU_FINETRIM_SELECT            0x4d4   /* override default prop dlys */
+#define CPU_FINETRIM_DR                        0x4d8   /* rise->rise prop dly A */
+#define CPU_FINETRIM_R                 0x4e4   /* rise->rise prop dly inc A */
 #define RST_DEVICES_NUM                        5
 
+/* RST_DFLL_DVCO bitfields */
+#define DVFS_DFLL_RESET_SHIFT          0
+
+/* CPU_FINETRIM_SELECT and CPU_FINETRIM_DR bitfields */
+#define CPU_FINETRIM_1_FCPU_1          BIT(0)  /* fcpu0 */
+#define CPU_FINETRIM_1_FCPU_2          BIT(1)  /* fcpu1 */
+#define CPU_FINETRIM_1_FCPU_3          BIT(2)  /* fcpu2 */
+#define CPU_FINETRIM_1_FCPU_4          BIT(3)  /* fcpu3 */
+#define CPU_FINETRIM_1_FCPU_5          BIT(4)  /* fl2 */
+#define CPU_FINETRIM_1_FCPU_6          BIT(5)  /* ftop */
+
+/* CPU_FINETRIM_R bitfields */
+#define CPU_FINETRIM_R_FCPU_1_SHIFT    0               /* fcpu0 */
+#define CPU_FINETRIM_R_FCPU_1_MASK     (0x3 << CPU_FINETRIM_R_FCPU_1_SHIFT)
+#define CPU_FINETRIM_R_FCPU_2_SHIFT    2               /* fcpu1 */
+#define CPU_FINETRIM_R_FCPU_2_MASK     (0x3 << CPU_FINETRIM_R_FCPU_2_SHIFT)
+#define CPU_FINETRIM_R_FCPU_3_SHIFT    4               /* fcpu2 */
+#define CPU_FINETRIM_R_FCPU_3_MASK     (0x3 << CPU_FINETRIM_R_FCPU_3_SHIFT)
+#define CPU_FINETRIM_R_FCPU_4_SHIFT    6               /* fcpu3 */
+#define CPU_FINETRIM_R_FCPU_4_MASK     (0x3 << CPU_FINETRIM_R_FCPU_4_SHIFT)
+#define CPU_FINETRIM_R_FCPU_5_SHIFT    8               /* fl2 */
+#define CPU_FINETRIM_R_FCPU_5_MASK     (0x3 << CPU_FINETRIM_R_FCPU_5_SHIFT)
+#define CPU_FINETRIM_R_FCPU_6_SHIFT    10              /* ftop */
+#define CPU_FINETRIM_R_FCPU_6_MASK     (0x3 << CPU_FINETRIM_R_FCPU_6_SHIFT)
+
 #define CLK_OUT_ENB_L                  0x010
 #define CLK_OUT_ENB_H                  0x014
 #define CLK_OUT_ENB_U                  0x018
 #define PMC_DPD_PADS_ORIDE_BLINK_ENB 20
 #define PMC_CTRL 0
 #define PMC_CTRL_BLINK_ENB 7
+#define PMC_BLINK_TIMER 0x40
 
 #define OSC_CTRL                       0x50
 #define OSC_CTRL_OSC_FREQ_SHIFT                28
 #define CLK_SOURCE_I2CSLOW 0x3fc
 #define CLK_SOURCE_SE 0x42c
 #define CLK_SOURCE_MSELECT 0x3b4
+#define CLK_SOURCE_DFLL_REF 0x62c
+#define CLK_SOURCE_DFLL_SOC 0x630
 #define CLK_SOURCE_SOC_THERM 0x644
 #define CLK_SOURCE_XUSB_HOST_SRC 0x600
 #define CLK_SOURCE_XUSB_FALCON_SRC 0x604
 #define CLK_SOURCE_XUSB_DEV_SRC 0x60c
 #define CLK_SOURCE_EMC 0x19c
 
+/* PLLM override registers */
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
+
 /* Tegra CPU clock and reset control regs */
 #define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS    0x470
 
@@ -267,6 +304,15 @@ static DEFINE_SPINLOCK(clk_doubler_lock);
 static DEFINE_SPINLOCK(clk_out_lock);
 static DEFINE_SPINLOCK(sysrate_lock);
 
+static struct div_nmp pllxc_nmp = {
+       .divm_shift = 0,
+       .divm_width = 8,
+       .divn_shift = 8,
+       .divn_width = 8,
+       .divp_shift = 20,
+       .divp_width = 4,
+};
+
 static struct pdiv_map pllxc_p[] = {
        { .pdiv = 1, .hw_val = 0 },
        { .pdiv = 2, .hw_val = 1 },
@@ -315,6 +361,16 @@ static struct tegra_clk_pll_params pll_c_params = {
        .stepa_shift = 17,
        .stepb_shift = 9,
        .pdiv_tohw = pllxc_p,
+       .div_nmp = &pllxc_nmp,
+};
+
+static struct div_nmp pllcx_nmp = {
+       .divm_shift = 0,
+       .divm_width = 2,
+       .divn_shift = 8,
+       .divn_width = 8,
+       .divp_shift = 20,
+       .divp_width = 3,
 };
 
 static struct pdiv_map pllc_p[] = {
@@ -348,6 +404,8 @@ static struct tegra_clk_pll_params pll_c2_params = {
        .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
        .lock_delay = 300,
        .pdiv_tohw = pllc_p,
+       .div_nmp = &pllcx_nmp,
+       .max_p = 7,
        .ext_misc_reg[0] = 0x4f0,
        .ext_misc_reg[1] = 0x4f4,
        .ext_misc_reg[2] = 0x4f8,
@@ -366,11 +424,25 @@ static struct tegra_clk_pll_params pll_c3_params = {
        .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
        .lock_delay = 300,
        .pdiv_tohw = pllc_p,
+       .div_nmp = &pllcx_nmp,
+       .max_p = 7,
        .ext_misc_reg[0] = 0x504,
        .ext_misc_reg[1] = 0x508,
        .ext_misc_reg[2] = 0x50c,
 };
 
+static struct div_nmp pllm_nmp = {
+       .divm_shift = 0,
+       .divm_width = 8,
+       .override_divm_shift = 0,
+       .divn_shift = 8,
+       .divn_width = 8,
+       .override_divn_shift = 8,
+       .divp_shift = 20,
+       .divp_width = 1,
+       .override_divp_shift = 27,
+};
+
 static struct pdiv_map pllm_p[] = {
        { .pdiv = 1, .hw_val = 0 },
        { .pdiv = 2, .hw_val = 1 },
@@ -400,6 +472,18 @@ static struct tegra_clk_pll_params pll_m_params = {
        .lock_delay = 300,
        .max_p = 2,
        .pdiv_tohw = pllm_p,
+       .div_nmp = &pllm_nmp,
+       .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
+       .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
+};
+
+static struct div_nmp pllp_nmp = {
+       .divm_shift = 0,
+       .divm_width = 5,
+       .divn_shift = 8,
+       .divn_width = 10,
+       .divp_shift = 20,
+       .divp_width = 3,
 };
 
 static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
@@ -423,6 +507,7 @@ static struct tegra_clk_pll_params pll_p_params = {
        .lock_mask = PLL_BASE_LOCK,
        .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
        .lock_delay = 300,
+       .div_nmp = &pllp_nmp,
 };
 
 static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
@@ -449,6 +534,7 @@ static struct tegra_clk_pll_params pll_a_params = {
        .lock_mask = PLL_BASE_LOCK,
        .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
        .lock_delay = 300,
+       .div_nmp = &pllp_nmp,
 };
 
 static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
@@ -484,6 +570,7 @@ static struct tegra_clk_pll_params pll_d_params = {
        .lock_mask = PLL_BASE_LOCK,
        .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
        .lock_delay = 1000,
+       .div_nmp = &pllp_nmp,
 };
 
 static struct tegra_clk_pll_params pll_d2_params = {
@@ -498,6 +585,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
        .lock_mask = PLL_BASE_LOCK,
        .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
        .lock_delay = 1000,
+       .div_nmp = &pllp_nmp,
 };
 
 static struct pdiv_map pllu_p[] = {
@@ -506,6 +594,15 @@ static struct pdiv_map pllu_p[] = {
        { .pdiv = 0, .hw_val = 0 },
 };
 
+static struct div_nmp pllu_nmp = {
+       .divm_shift = 0,
+       .divm_width = 5,
+       .divn_shift = 8,
+       .divn_width = 10,
+       .divp_shift = 20,
+       .divp_width = 1,
+};
+
 static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
        {12000000, 480000000, 960, 12, 0, 12},
        {13000000, 480000000, 960, 13, 0, 12},
@@ -528,6 +625,7 @@ static struct tegra_clk_pll_params pll_u_params = {
        .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
        .lock_delay = 1000,
        .pdiv_tohw = pllu_p,
+       .div_nmp = &pllu_nmp,
 };
 
 static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
@@ -560,6 +658,7 @@ static struct tegra_clk_pll_params pll_x_params = {
        .stepa_shift = 16,
        .stepb_shift = 24,
        .pdiv_tohw = pllxc_p,
+       .div_nmp = &pllxc_nmp,
 };
 
 static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
@@ -569,6 +668,15 @@ static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
        {0, 0, 0, 0, 0, 0},
 };
 
+static struct div_nmp plle_nmp = {
+       .divm_shift = 0,
+       .divm_width = 8,
+       .divn_shift = 8,
+       .divn_width = 8,
+       .divp_shift = 24,
+       .divp_width = 4,
+};
+
 static struct tegra_clk_pll_params pll_e_params = {
        .input_min = 12000000,
        .input_max = 1000000000,
@@ -582,6 +690,16 @@ static struct tegra_clk_pll_params pll_e_params = {
        .lock_mask = PLLE_MISC_LOCK,
        .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
        .lock_delay = 300,
+       .div_nmp = &plle_nmp,
+};
+
+static struct div_nmp pllre_nmp = {
+       .divm_shift = 0,
+       .divm_width = 8,
+       .divn_shift = 8,
+       .divn_width = 8,
+       .divp_shift = 16,
+       .divp_width = 4,
 };
 
 static struct tegra_clk_pll_params pll_re_vco_params = {
@@ -598,6 +716,7 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
        .lock_delay = 300,
        .iddq_reg = PLLRE_MISC,
        .iddq_bit_idx = PLLRE_IDDQ_BIT,
+       .div_nmp = &pllre_nmp,
 };
 
 /* Peripheral clock registers */
@@ -765,6 +884,7 @@ enum tegra114_clk {
        audio1, audio2, audio3, audio4, spdif, clk_out_1, clk_out_2, clk_out_3,
        blink, xusb_host_src = 252, xusb_falcon_src, xusb_fs_src, xusb_ss_src,
        xusb_dev_src, xusb_dev, xusb_hs_src, sclk, hclk, pclk, cclk_g, cclk_lp,
+       dfll_ref = 264, dfll_soc,
 
        /* Mux clocks */
 
@@ -1202,8 +1322,8 @@ static void __init tegra114_pll_init(void __iomem *clk_base,
        /* PLLP_OUT2 */
        clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p",
                                clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED |
-                               TEGRA_DIVIDER_ROUND_UP, 24, 8, 1,
-                               &pll_div_lock);
+                               TEGRA_DIVIDER_ROUND_UP | TEGRA_DIVIDER_INT, 24,
+                               8, 1, &pll_div_lock);
        clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div",
                                clk_base + PLLP_OUTA, 17, 16,
                                CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
@@ -1605,7 +1725,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
 
        /* clk_out_2 */
        clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
-                              ARRAY_SIZE(clk_out1_parents), 0,
+                              ARRAY_SIZE(clk_out2_parents), 0,
                               pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
                               &clk_out_lock);
        clks[clk_out_2_mux] = clk;
@@ -1617,7 +1737,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
 
        /* clk_out_3 */
        clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
-                              ARRAY_SIZE(clk_out1_parents), 0,
+                              ARRAY_SIZE(clk_out3_parents), 0,
                               pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
                               &clk_out_lock);
        clks[clk_out_3_mux] = clk;
@@ -1628,6 +1748,8 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
        clks[clk_out_3] = clk;
 
        /* blink */
+       /* clear the blink timer register to directly output clk_32k */
+       writel_relaxed(0, pmc_base + PMC_BLINK_TIMER);
        clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,
                                pmc_base + PMC_DPD_PADS_ORIDE,
                                PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL);
@@ -1640,7 +1762,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
 }
 
 static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
-                              "pll_p_out3", "pll_p_out2", "unused",
+                              "pll_p", "pll_p_out2", "unused",
                               "clk_32k", "pll_m_out1" };
 
 static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
@@ -1750,7 +1872,7 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {
        TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor),
        TEGRA_INIT_DATA_INT8("vi", "vi", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi),
        TEGRA_INIT_DATA_INT8("epp", NULL, "epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp),
-       TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_h_regs, TEGRA_PERIPH_WAR_1005168, msenc),
+       TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_u_regs, TEGRA_PERIPH_WAR_1005168, msenc),
        TEGRA_INIT_DATA_INT8("tsec", NULL, "tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, &periph_u_regs, 0, tsec),
        TEGRA_INIT_DATA_INT8("host1x", NULL, "host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x),
        TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi),
@@ -1767,6 +1889,8 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {
        TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow),
        TEGRA_INIT_DATA_INT8("se", NULL, "se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, TEGRA_PERIPH_ON_APB, se),
        TEGRA_INIT_DATA_INT_FLAGS("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect, CLK_IGNORE_UNUSED),
+       TEGRA_INIT_DATA_MUX("dfll_ref", "ref", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_REF, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_ref),
+       TEGRA_INIT_DATA_MUX("dfll_soc", "soc", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_SOC, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_soc),
        TEGRA_INIT_DATA_MUX8("soc_therm", NULL, "soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, &periph_u_regs, TEGRA_PERIPH_ON_APB, soc_therm),
        TEGRA_INIT_DATA_XUSB("xusb_host_src", "host_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, &periph_w_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_host_src),
        TEGRA_INIT_DATA_XUSB("xusb_falcon_src", "falcon_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_falcon_src),
@@ -2028,6 +2152,10 @@ static const struct of_device_id pmc_match[] __initconst = {
        {},
 };
 
+/*
+ * dfll_soc/dfll_ref apparently must be kept enabled, otherwise I2C5
+ * breaks
+ */
 static __initdata struct tegra_clk_init_table init_table[] = {
        {uarta, pll_p, 408000000, 0},
        {uartb, pll_p, 408000000, 0},
@@ -2043,6 +2171,8 @@ static __initdata struct tegra_clk_init_table init_table[] = {
        {i2s2, pll_a_out0, 11289600, 0},
        {i2s3, pll_a_out0, 11289600, 0},
        {i2s4, pll_a_out0, 11289600, 0},
+       {dfll_soc, pll_p, 51000000, 1},
+       {dfll_ref, pll_p, 51000000, 1},
        {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */
 };
 
@@ -2051,7 +2181,132 @@ static void __init tegra114_clock_apply_init_table(void)
        tegra_init_from_table(init_table, clks, clk_max);
 }
 
-void __init tegra114_clock_init(struct device_node *np)
+
+/**
+ * tegra114_car_barrier - wait for pending writes to the CAR to complete
+ *
+ * Wait for any outstanding writes to the CAR MMIO space from this CPU
+ * to complete before continuing execution.  No return value.
+ */
+static void tegra114_car_barrier(void)
+{
+       wmb();          /* probably unnecessary */
+       readl_relaxed(clk_base + CPU_FINETRIM_SELECT);
+}
+
+/**
+ * tegra114_clock_tune_cpu_trimmers_high - use high-voltage propagation delays
+ *
+ * When the CPU rail voltage is in the high-voltage range, use the
+ * built-in hardwired clock propagation delays in the CPU clock
+ * shaper.  No return value.
+ */
+void tegra114_clock_tune_cpu_trimmers_high(void)
+{
+       u32 select = 0;
+
+       /* Use hardwired rise->rise & fall->fall clock propagation delays */
+       select |= ~(CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 |
+                   CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 |
+                   CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6);
+       writel_relaxed(select, clk_base + CPU_FINETRIM_SELECT);
+
+       tegra114_car_barrier();
+}
+EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_high);
+
+/**
+ * tegra114_clock_tune_cpu_trimmers_low - use low-voltage propagation delays
+ *
+ * When the CPU rail voltage is in the low-voltage range, use the
+ * extended clock propagation delays set by
+ * tegra114_clock_tune_cpu_trimmers_init().  The intention is to
+ * maintain the input clock duty cycle that the FCPU subsystem
+ * expects.  No return value.
+ */
+void tegra114_clock_tune_cpu_trimmers_low(void)
+{
+       u32 select = 0;
+
+       /*
+        * Use software-specified rise->rise & fall->fall clock
+        * propagation delays (from
+        * tegra114_clock_tune_cpu_trimmers_init()
+        */
+       select |= (CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 |
+                  CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 |
+                  CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6);
+       writel_relaxed(select, clk_base + CPU_FINETRIM_SELECT);
+
+       tegra114_car_barrier();
+}
+EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_low);
+
+/**
+ * tegra114_clock_tune_cpu_trimmers_init - set up and enable clk prop delays
+ *
+ * Program extended clock propagation delays into the FCPU clock
+ * shaper and enable them.  XXX Define the purpose - peak current
+ * reduction?  No return value.
+ */
+/* XXX Initial voltage rail state assumption issues? */
+void tegra114_clock_tune_cpu_trimmers_init(void)
+{
+       u32 dr = 0, r = 0;
+
+       /* Increment the rise->rise clock delay by four steps */
+       r |= (CPU_FINETRIM_R_FCPU_1_MASK | CPU_FINETRIM_R_FCPU_2_MASK |
+             CPU_FINETRIM_R_FCPU_3_MASK | CPU_FINETRIM_R_FCPU_4_MASK |
+             CPU_FINETRIM_R_FCPU_5_MASK | CPU_FINETRIM_R_FCPU_6_MASK);
+       writel_relaxed(r, clk_base + CPU_FINETRIM_R);
+
+       /*
+        * Use the rise->rise clock propagation delay specified in the
+        * r field
+        */
+       dr |= (CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 |
+              CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 |
+              CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6);
+       writel_relaxed(dr, clk_base + CPU_FINETRIM_DR);
+
+       tegra114_clock_tune_cpu_trimmers_low();
+}
+EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_init);
+
+/**
+ * tegra114_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset
+ *
+ * Assert the reset line of the DFLL's DVCO.  No return value.
+ */
+void tegra114_clock_assert_dfll_dvco_reset(void)
+{
+       u32 v;
+
+       v = readl_relaxed(clk_base + RST_DFLL_DVCO);
+       v |= (1 << DVFS_DFLL_RESET_SHIFT);
+       writel_relaxed(v, clk_base + RST_DFLL_DVCO);
+       tegra114_car_barrier();
+}
+EXPORT_SYMBOL(tegra114_clock_assert_dfll_dvco_reset);
+
+/**
+ * tegra114_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset
+ *
+ * Deassert the reset line of the DFLL's DVCO, allowing the DVCO to
+ * operate.  No return value.
+ */
+void tegra114_clock_deassert_dfll_dvco_reset(void)
+{
+       u32 v;
+
+       v = readl_relaxed(clk_base + RST_DFLL_DVCO);
+       v &= ~(1 << DVFS_DFLL_RESET_SHIFT);
+       writel_relaxed(v, clk_base + RST_DFLL_DVCO);
+       tegra114_car_barrier();
+}
+EXPORT_SYMBOL(tegra114_clock_deassert_dfll_dvco_reset);
+
+static void __init tegra114_clock_init(struct device_node *np)
 {
        struct device_node *node;
        int i;
@@ -2104,3 +2359,4 @@ void __init tegra114_clock_init(struct device_node *np)
 
        tegra_cpu_car_ops = &tegra114_cpu_car_ops;
 }
+CLK_OF_DECLARE(tegra114, "nvidia,tegra114-car", tegra114_clock_init);
index 075db0c99edb9b8569556d853fbaee0e88c2cb2c..759ca47be7533c608e3b20f12b324851d180fde0 100644 (file)
@@ -1287,7 +1287,7 @@ static const struct of_device_id pmc_match[] __initconst = {
        {},
 };
 
-void __init tegra20_clock_init(struct device_node *np)
+static void __init tegra20_clock_init(struct device_node *np)
 {
        int i;
        struct device_node *node;
@@ -1339,3 +1339,4 @@ void __init tegra20_clock_init(struct device_node *np)
 
        tegra_cpu_car_ops = &tegra20_cpu_car_ops;
 }
+CLK_OF_DECLARE(tegra20, "nvidia,tegra20-car", tegra20_clock_init);
index ba99e3844106ec961c03c33cd637ad59b217e2b3..e2c6ca0431d662c141742c46eb7dc91bc040dda3 100644 (file)
 #define CLK_RESET_CCLK_RUN_POLICY              2
 #define CLK_RESET_CCLK_BURST_POLICY_PLLX       8
 
+/* PLLM override registers */
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+
 #ifdef CONFIG_PM_SLEEP
 static struct cpu_clk_suspend_context {
        u32 pllx_misc;
@@ -563,6 +566,18 @@ static struct tegra_clk_pll_params pll_c_params = {
        .lock_delay = 300,
 };
 
+static struct div_nmp pllm_nmp = {
+       .divn_shift = 8,
+       .divn_width = 10,
+       .override_divn_shift = 5,
+       .divm_shift = 0,
+       .divm_width = 5,
+       .override_divm_shift = 0,
+       .divp_shift = 20,
+       .divp_width = 3,
+       .override_divp_shift = 15,
+};
+
 static struct tegra_clk_pll_params pll_m_params = {
        .input_min = 2000000,
        .input_max = 31000000,
@@ -575,6 +590,9 @@ static struct tegra_clk_pll_params pll_m_params = {
        .lock_mask = PLL_BASE_LOCK,
        .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
        .lock_delay = 300,
+       .div_nmp = &pllm_nmp,
+       .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
+       .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE,
 };
 
 static struct tegra_clk_pll_params pll_p_params = {
@@ -1223,7 +1241,7 @@ static void __init tegra30_pmc_clk_init(void)
 
        /* clk_out_2 */
        clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
-                              ARRAY_SIZE(clk_out1_parents), 0,
+                              ARRAY_SIZE(clk_out2_parents), 0,
                               pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
                               &clk_out_lock);
        clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0,
@@ -1234,7 +1252,7 @@ static void __init tegra30_pmc_clk_init(void)
 
        /* clk_out_3 */
        clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
-                              ARRAY_SIZE(clk_out1_parents), 0,
+                              ARRAY_SIZE(clk_out3_parents), 0,
                               pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
                               &clk_out_lock);
        clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0,
@@ -1954,7 +1972,7 @@ static const struct of_device_id pmc_match[] __initconst = {
        {},
 };
 
-void __init tegra30_clock_init(struct device_node *np)
+static void __init tegra30_clock_init(struct device_node *np)
 {
        struct device_node *node;
        int i;
@@ -2005,3 +2023,4 @@ void __init tegra30_clock_init(struct device_node *np)
 
        tegra_cpu_car_ops = &tegra30_cpu_car_ops;
 }
+CLK_OF_DECLARE(tegra30, "nvidia,tegra30-car", tegra30_clock_init);
index 923ca7ee46944c4d516f01938c2ce046e6fa6d6a..86581ac1fd6985ffcae150aa0737521c3edbd5a5 100644 (file)
@@ -74,18 +74,6 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
        }
 }
 
-static const struct of_device_id tegra_dt_clk_match[] = {
-       { .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init },
-       { .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init },
-       { .compatible = "nvidia,tegra114-car", .data = tegra114_clock_init },
-       { }
-};
-
-void __init tegra_clocks_init(void)
-{
-       of_clk_init(tegra_dt_clk_match);
-}
-
 tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
 
 void __init tegra_clocks_apply_init_table(void)
index e0565620d68ea508f53aed0973a388f8aa6005e5..07cfacd91686b949f75bedeb6cc0bcb4c0ff0c54 100644 (file)
@@ -127,6 +127,31 @@ struct pdiv_map {
        u8 hw_val;
 };
 
+/**
+ * struct div_nmp - offset and width of m,n and p fields
+ *
+ * @divn_shift:        shift to the feedback divider bit field
+ * @divn_width:        width of the feedback divider bit field
+ * @divm_shift:        shift to the input divider bit field
+ * @divm_width:        width of the input divider bit field
+ * @divp_shift:        shift to the post divider bit field
+ * @divp_width:        width of the post divider bit field
+ * @override_divn_shift: shift to the feedback divider bitfield in override reg
+ * @override_divm_shift: shift to the input divider bitfield in override reg
+ * @override_divp_shift: shift to the post divider bitfield in override reg
+ */
+struct div_nmp {
+       u8              divn_shift;
+       u8              divn_width;
+       u8              divm_shift;
+       u8              divm_width;
+       u8              divp_shift;
+       u8              divp_width;
+       u8              override_divn_shift;
+       u8              override_divm_shift;
+       u8              override_divp_shift;
+};
+
 /**
  * struct clk_pll_params - PLL parameters
  *
@@ -161,11 +186,14 @@ struct tegra_clk_pll_params {
        u32             aux_reg;
        u32             dyn_ramp_reg;
        u32             ext_misc_reg[3];
+       u32             pmc_divnm_reg;
+       u32             pmc_divp_reg;
        int             stepa_shift;
        int             stepb_shift;
        int             lock_delay;
        int             max_p;
        struct pdiv_map *pdiv_tohw;
+       struct div_nmp  *div_nmp;
 };
 
 /**
@@ -179,12 +207,6 @@ struct tegra_clk_pll_params {
  * @flags:     PLL flags
  * @fixed_rate:        PLL rate if it is fixed
  * @lock:      register lock
- * @divn_shift:        shift to the feedback divider bit field
- * @divn_width:        width of the feedback divider bit field
- * @divm_shift:        shift to the input divider bit field
- * @divm_width:        width of the input divider bit field
- * @divp_shift:        shift to the post divider bit field
- * @divp_width:        width of the post divider bit field
  *
  * Flags:
  * TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
@@ -214,12 +236,6 @@ struct tegra_clk_pll {
        u32             flags;
        unsigned long   fixed_rate;
        spinlock_t      *lock;
-       u8              divn_shift;
-       u8              divn_width;
-       u8              divm_shift;
-       u8              divm_width;
-       u8              divp_shift;
-       u8              divp_width;
        struct tegra_clk_pll_freq_table *freq_table;
        struct tegra_clk_pll_params     *params;
 };
@@ -571,23 +587,11 @@ void tegra_init_from_table(struct tegra_clk_init_table *tbl,
 void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
                struct clk *clks[], int clk_max);
 
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-void tegra20_clock_init(struct device_node *np);
-#else
-static inline void tegra20_clock_init(struct device_node *np) {}
-#endif /* CONFIG_ARCH_TEGRA_2x_SOC */
-
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
-void tegra30_clock_init(struct device_node *np);
-#else
-static inline void tegra30_clock_init(struct device_node *np) {}
-#endif /* CONFIG_ARCH_TEGRA_3x_SOC */
-
-#ifdef CONFIG_ARCH_TEGRA_114_SOC
-void tegra114_clock_init(struct device_node *np);
-#else
-static inline void tegra114_clock_init(struct device_node *np) {}
-#endif /* CONFIG_ARCH_TEGRA114_SOC */
+void tegra114_clock_tune_cpu_trimmers_high(void);
+void tegra114_clock_tune_cpu_trimmers_low(void);
+void tegra114_clock_tune_cpu_trimmers_init(void);
+void tegra114_clock_assert_dfll_dvco_reset(void);
+void tegra114_clock_deassert_dfll_dvco_reset(void);
 
 typedef void (*tegra_clk_apply_init_table_func)(void);
 extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
index a0fca004abc17b865743a75c5d2d9f2b53af6fd2..e7bd62cf60b350897cfd9f593afd803e8136cf68 100644 (file)
@@ -45,7 +45,7 @@ static int ab8500_reg_clks(struct device *dev)
                                CLK_IS_ROOT);
        clk_register_clkdev(clk, "sysclk", "ab8500-usb.0");
        clk_register_clkdev(clk, "sysclk", "ab-iddet.0");
-       clk_register_clkdev(clk, "sysclk", "ab85xx-codec.0");
+       clk_register_clkdev(clk, "sysclk", "snd-soc-mop500.0");
        clk_register_clkdev(clk, "sysclk", "shrm_bus");
 
        /* ab8500_sysclk2 */
@@ -70,19 +70,19 @@ static int ab8500_reg_clks(struct device *dev)
                AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
                AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
                38400000, 9000, CLK_IS_ROOT);
-       clk_register_clkdev(clk, "ulpclk", "ab85xx-codec.0");
+       clk_register_clkdev(clk, "ulpclk", "snd-soc-mop500.0");
 
        /* ab8500_intclk */
        clk = clk_reg_sysctrl_set_parent(dev , "intclk", intclk_parents, 2,
                intclk_reg_sel, intclk_reg_mask, intclk_reg_bits, 0);
-       clk_register_clkdev(clk, "intclk", "ab85xx-codec.0");
+       clk_register_clkdev(clk, "intclk", "snd-soc-mop500.0");
        clk_register_clkdev(clk, NULL, "ab8500-pwm.1");
 
        /* ab8500_audioclk */
        clk = clk_reg_sysctrl_gate(dev , "audioclk", "intclk",
                AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA,
                AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 0, 0);
-       clk_register_clkdev(clk, "audioclk", "ab85xx-codec.0");
+       clk_register_clkdev(clk, "audioclk", "ab8500-codec.0");
 
        return 0;
 }
index 10adfd2ead2109e477cba99016fa900d82073fa0..f26258869deb22d4f2fd760b2139395ae25c9b0f 100644 (file)
 #include <linux/clk-provider.h>
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/platform_data/clk-ux500.h>
-
 #include "clk.h"
 
-void u8540_clk_init(void)
+void u8540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
+                   u32 clkrst5_base, u32 clkrst6_base)
 {
-       /* register clocks here */
+       struct clk *clk;
+
+       /* Clock sources. */
+       /* Fixed ClockGen */
+       clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0,
+                               CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+       clk_register_clkdev(clk, "soc0_pll", NULL);
+
+       clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1,
+                               CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+       clk_register_clkdev(clk, "soc1_pll", NULL);
+
+       clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR,
+                               CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+       clk_register_clkdev(clk, "ddr_pll", NULL);
+
+       clk = clk_register_fixed_rate(NULL, "rtc32k", NULL,
+                               CLK_IS_ROOT|CLK_IGNORE_UNUSED,
+                               32768);
+       clk_register_clkdev(clk, "clk32k", NULL);
+       clk_register_clkdev(clk, "apb_pclk", "rtc-pl031");
+
+       clk = clk_register_fixed_rate(NULL, "ulp38m4", NULL,
+                               CLK_IS_ROOT|CLK_IGNORE_UNUSED,
+                               38400000);
+
+       clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "UART");
+
+       /* msp02clk needs a abx500 clk as parent. Handle by abx500 clk driver */
+       clk = clk_reg_prcmu_gate("msp02clk", "ab9540_sysclk12_b1",
+                       PRCMU_MSP02CLK, 0);
+       clk_register_clkdev(clk, NULL, "MSP02");
+
+       clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "MSP1");
+
+       clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "I2C");
+
+       clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "slim");
+
+       clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH1");
+
+       clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH2");
+
+       clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH3");
+
+       clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH5");
+
+       clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH6");
+
+       clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "PERIPH7");
+
+       clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "lcd");
+       clk_register_clkdev(clk, "lcd", "mcde");
+
+       clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BML8580CLK,
+                               CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "bml");
+
+       clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+
+       clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+
+       clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "hdmi");
+       clk_register_clkdev(clk, "hdmi", "mcde");
+
+       clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "apeat");
+
+       clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK,
+                               CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "apetrace");
+
+       clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "mcde");
+       clk_register_clkdev(clk, "mcde", "mcde");
+       clk_register_clkdev(clk, NULL, "dsilink.0");
+       clk_register_clkdev(clk, NULL, "dsilink.1");
+       clk_register_clkdev(clk, NULL, "dsilink.2");
+
+       clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK,
+                               CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "ipi2");
+
+       clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK,
+                               CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "dsialt");
+
+       clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "dma40.0");
+
+       clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "b2r2");
+       clk_register_clkdev(clk, NULL, "b2r2_core");
+       clk_register_clkdev(clk, NULL, "U8500-B2R2.0");
+       clk_register_clkdev(clk, NULL, "b2r2_1_core");
+
+       clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "tv");
+       clk_register_clkdev(clk, "tv", "mcde");
+
+       clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "SSP");
+
+       clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "rngclk");
+
+       clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "uicc");
+
+       clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "mtu0");
+       clk_register_clkdev(clk, NULL, "mtu1");
+
+       clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL,
+                                       PRCMU_SDMMCCLK, 100000000,
+                                       CLK_IS_ROOT|CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdmmc");
+
+       clk = clk_reg_prcmu_opp_volt_scalable("sdmmchclk", NULL,
+                                       PRCMU_SDMMCHCLK, 400000000,
+                                       CLK_IS_ROOT|CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdmmchclk");
+
+       clk = clk_reg_prcmu_gate("hvaclk", NULL, PRCMU_HVACLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "hva");
+
+       clk = clk_reg_prcmu_gate("g1clk", NULL, PRCMU_G1CLK, CLK_IS_ROOT);
+       clk_register_clkdev(clk, NULL, "g1");
+
+       clk = clk_reg_prcmu_scalable("spare1clk", NULL, PRCMU_SPARE1CLK, 0,
+                               CLK_IS_ROOT|CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsilcd", "mcde");
+
+       clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
+                               PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsihs2", "mcde");
+       clk_register_clkdev(clk, "hs_clk", "dsilink.2");
+
+       clk = clk_reg_prcmu_scalable("dsilcd_pll", "spare1clk",
+                               PRCMU_PLLDSI_LCD, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsilcd_pll", "mcde");
+
+       clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll",
+                               PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsihs0", "mcde");
+
+       clk = clk_reg_prcmu_scalable("dsi0lcdclk", "dsilcd_pll",
+                               PRCMU_DSI0CLK_LCD, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsihs0", "mcde");
+       clk_register_clkdev(clk, "hs_clk", "dsilink.0");
+
+       clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll",
+                               PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsihs1", "mcde");
+
+       clk = clk_reg_prcmu_scalable("dsi1lcdclk", "dsilcd_pll",
+                               PRCMU_DSI1CLK_LCD, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "dsihs1", "mcde");
+       clk_register_clkdev(clk, "hs_clk", "dsilink.1");
+
+       clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk",
+                               PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "lp_clk", "dsilink.0");
+       clk_register_clkdev(clk, "dsilp0", "mcde");
+
+       clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk",
+                               PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "lp_clk", "dsilink.1");
+       clk_register_clkdev(clk, "dsilp1", "mcde");
+
+       clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk",
+                               PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, "lp_clk", "dsilink.2");
+       clk_register_clkdev(clk, "dsilp2", "mcde");
+
+       clk = clk_reg_prcmu_scalable_rate("armss", NULL,
+                               PRCMU_ARMSS, 0, CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+       clk_register_clkdev(clk, "armss", NULL);
+
+       clk = clk_register_fixed_factor(NULL, "smp_twd", "armss",
+                               CLK_IGNORE_UNUSED, 1, 2);
+       clk_register_clkdev(clk, NULL, "smp_twd");
+
+       /* PRCC P-clocks */
+       /* Peripheral 1 : PRCC P-clocks */
+       clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", clkrst1_base,
+                               BIT(0), 0);
+       clk_register_clkdev(clk, "apb_pclk", "uart0");
+
+       clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", clkrst1_base,
+                               BIT(1), 0);
+       clk_register_clkdev(clk, "apb_pclk", "uart1");
+
+       clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", clkrst1_base,
+                               BIT(2), 0);
+       clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.1");
+
+       clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", clkrst1_base,
+                               BIT(3), 0);
+       clk_register_clkdev(clk, "apb_pclk", "msp0");
+       clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.0");
+
+       clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", clkrst1_base,
+                               BIT(4), 0);
+       clk_register_clkdev(clk, "apb_pclk", "msp1");
+       clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.1");
+
+       clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", clkrst1_base,
+                               BIT(5), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi0");
+
+       clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", clkrst1_base,
+                               BIT(6), 0);
+       clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.2");
+
+       clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", clkrst1_base,
+                               BIT(7), 0);
+       clk_register_clkdev(clk, NULL, "spi3");
+
+       clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", clkrst1_base,
+                               BIT(8), 0);
+       clk_register_clkdev(clk, "apb_pclk", "slimbus0");
+
+       clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", clkrst1_base,
+                               BIT(9), 0);
+       clk_register_clkdev(clk, NULL, "gpio.0");
+       clk_register_clkdev(clk, NULL, "gpio.1");
+       clk_register_clkdev(clk, NULL, "gpioblock0");
+       clk_register_clkdev(clk, "apb_pclk", "ab85xx-codec.0");
+
+       clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", clkrst1_base,
+                               BIT(10), 0);
+       clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.4");
+
+       clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", clkrst1_base,
+                               BIT(11), 0);
+       clk_register_clkdev(clk, "apb_pclk", "msp3");
+       clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.3");
+
+       /* Peripheral 2 : PRCC P-clocks */
+       clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", clkrst2_base,
+                               BIT(0), 0);
+       clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.3");
+
+       clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", clkrst2_base,
+                               BIT(1), 0);
+       clk_register_clkdev(clk, NULL, "spi2");
+
+       clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", clkrst2_base,
+                               BIT(2), 0);
+       clk_register_clkdev(clk, NULL, "spi1");
+
+       clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", clkrst2_base,
+                               BIT(3), 0);
+       clk_register_clkdev(clk, NULL, "pwl");
+
+       clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", clkrst2_base,
+                               BIT(4), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi4");
+
+       clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", clkrst2_base,
+                               BIT(5), 0);
+       clk_register_clkdev(clk, "apb_pclk", "msp2");
+       clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.2");
+
+       clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", clkrst2_base,
+                               BIT(6), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi1");
+
+       clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", clkrst2_base,
+                               BIT(7), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi3");
+
+       clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", clkrst2_base,
+                               BIT(8), 0);
+       clk_register_clkdev(clk, NULL, "spi0");
+
+       clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", clkrst2_base,
+                               BIT(9), 0);
+       clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0");
+
+       clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", clkrst2_base,
+                               BIT(10), 0);
+       clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0");
+
+       clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", clkrst2_base,
+                               BIT(11), 0);
+       clk_register_clkdev(clk, NULL, "gpio.6");
+       clk_register_clkdev(clk, NULL, "gpio.7");
+       clk_register_clkdev(clk, NULL, "gpioblock1");
+
+       clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", clkrst2_base,
+                               BIT(12), 0);
+       clk_register_clkdev(clk, "msp4-pclk", "ab85xx-codec.0");
+
+       /* Peripheral 3 : PRCC P-clocks */
+       clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", clkrst3_base,
+                               BIT(0), 0);
+       clk_register_clkdev(clk, NULL, "fsmc");
+
+       clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", clkrst3_base,
+                               BIT(1), 0);
+       clk_register_clkdev(clk, "apb_pclk", "ssp0");
+
+       clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", clkrst3_base,
+                               BIT(2), 0);
+       clk_register_clkdev(clk, "apb_pclk", "ssp1");
+
+       clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", clkrst3_base,
+                               BIT(3), 0);
+       clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.0");
+
+       clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", clkrst3_base,
+                               BIT(4), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi2");
+
+       clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", clkrst3_base,
+                               BIT(5), 0);
+       clk_register_clkdev(clk, "apb_pclk", "ske");
+       clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad");
+
+       clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", clkrst3_base,
+                               BIT(6), 0);
+       clk_register_clkdev(clk, "apb_pclk", "uart2");
+
+       clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", clkrst3_base,
+                               BIT(7), 0);
+       clk_register_clkdev(clk, "apb_pclk", "sdi5");
+
+       clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", clkrst3_base,
+                               BIT(8), 0);
+       clk_register_clkdev(clk, NULL, "gpio.2");
+       clk_register_clkdev(clk, NULL, "gpio.3");
+       clk_register_clkdev(clk, NULL, "gpio.4");
+       clk_register_clkdev(clk, NULL, "gpio.5");
+       clk_register_clkdev(clk, NULL, "gpioblock2");
+
+       clk = clk_reg_prcc_pclk("p3_pclk9", "per3clk", clkrst3_base,
+                               BIT(9), 0);
+       clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.5");
+
+       clk = clk_reg_prcc_pclk("p3_pclk10", "per3clk", clkrst3_base,
+                               BIT(10), 0);
+       clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.6");
+
+       clk = clk_reg_prcc_pclk("p3_pclk11", "per3clk", clkrst3_base,
+                               BIT(11), 0);
+       clk_register_clkdev(clk, "apb_pclk", "uart3");
+
+       clk = clk_reg_prcc_pclk("p3_pclk12", "per3clk", clkrst3_base,
+                               BIT(12), 0);
+       clk_register_clkdev(clk, "apb_pclk", "uart4");
+
+       /* Peripheral 5 : PRCC P-clocks */
+       clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", clkrst5_base,
+                               BIT(0), 0);
+       clk_register_clkdev(clk, "usb", "musb-ux500.0");
+       clk_register_clkdev(clk, "usbclk", "ab-iddet.0");
+
+       clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", clkrst5_base,
+                               BIT(1), 0);
+       clk_register_clkdev(clk, NULL, "gpio.8");
+       clk_register_clkdev(clk, NULL, "gpioblock3");
+
+       /* Peripheral 6 : PRCC P-clocks */
+       clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", clkrst6_base,
+                               BIT(0), 0);
+       clk_register_clkdev(clk, "apb_pclk", "rng");
+
+       clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", clkrst6_base,
+                               BIT(1), 0);
+       clk_register_clkdev(clk, NULL, "cryp0");
+       clk_register_clkdev(clk, NULL, "cryp1");
+
+       clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", clkrst6_base,
+                               BIT(2), 0);
+       clk_register_clkdev(clk, NULL, "hash0");
+
+       clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", clkrst6_base,
+                               BIT(3), 0);
+       clk_register_clkdev(clk, NULL, "pka");
+
+       clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", clkrst6_base,
+                               BIT(4), 0);
+       clk_register_clkdev(clk, NULL, "db8540-hash1");
+
+       clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", clkrst6_base,
+                               BIT(5), 0);
+       clk_register_clkdev(clk, NULL, "cfgreg");
+
+       clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", clkrst6_base,
+                               BIT(6), 0);
+       clk_register_clkdev(clk, "apb_pclk", "mtu0");
+
+       clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", clkrst6_base,
+                               BIT(7), 0);
+       clk_register_clkdev(clk, "apb_pclk", "mtu1");
+
+       /*
+        * PRCC K-clocks  ==> see table PRCC_PCKEN/PRCC_KCKEN
+        * This differs from the internal implementation:
+        * We don't use the PERPIH[n| clock as parent, since those _should_
+        * only be used as parents for the P-clocks.
+        * TODO: "parentjoin" with corresponding P-clocks for all K-clocks.
+        */
+
+       /* Peripheral 1 : PRCC K-clocks */
+       clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk",
+                       clkrst1_base, BIT(0), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "uart0");
+
+       clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk",
+                       clkrst1_base, BIT(1), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "uart1");
+
+       clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk",
+                       clkrst1_base, BIT(2), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "nmk-i2c.1");
+
+       clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk",
+                       clkrst1_base, BIT(3), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "msp0");
+       clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.0");
+
+       clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk",
+                       clkrst1_base, BIT(4), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "msp1");
+       clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.1");
+
+       clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmchclk",
+                       clkrst1_base, BIT(5), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi0");
+
+       clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk",
+                       clkrst1_base, BIT(6), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "nmk-i2c.2");
+
+       clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk",
+                       clkrst1_base, BIT(8), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "slimbus0");
+
+       clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk",
+                       clkrst1_base, BIT(9), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "nmk-i2c.4");
+
+       clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk",
+                       clkrst1_base, BIT(10), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "msp3");
+       clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.3");
+
+       /* Peripheral 2 : PRCC K-clocks */
+       clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk",
+                       clkrst2_base, BIT(0), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "nmk-i2c.3");
+
+       clk = clk_reg_prcc_kclk("p2_pwl_kclk", "rtc32k",
+                       clkrst2_base, BIT(1), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "pwl");
+
+       clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmchclk",
+                       clkrst2_base, BIT(2), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi4");
+
+       clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk",
+                       clkrst2_base, BIT(3), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "msp2");
+       clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.2");
+
+       clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmchclk",
+                       clkrst2_base, BIT(4), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi1");
+
+       clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk",
+                       clkrst2_base, BIT(5), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi3");
+
+       clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk",
+                       clkrst2_base, BIT(6),
+                       CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
+       clk_register_clkdev(clk, "hsir_hsirxclk", "ste_hsi.0");
+
+       clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk",
+                       clkrst2_base, BIT(7),
+                       CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
+       clk_register_clkdev(clk, "hsit_hsitxclk", "ste_hsi.0");
+
+       /* Should only be 9540, but might be added for 85xx as well */
+       clk = clk_reg_prcc_kclk("p2_msp4_kclk", "msp02clk",
+                       clkrst2_base, BIT(9), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "msp4");
+       clk_register_clkdev(clk, "msp4", "ab85xx-codec.0");
+
+       /* Peripheral 3 : PRCC K-clocks */
+       clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk",
+                       clkrst3_base, BIT(1), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "ssp0");
+
+       clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk",
+                       clkrst3_base, BIT(2), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "ssp1");
+
+       clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk",
+                       clkrst3_base, BIT(3), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "nmk-i2c.0");
+
+       clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmchclk",
+                       clkrst3_base, BIT(4), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi2");
+
+       clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
+                       clkrst3_base, BIT(5), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "ske");
+       clk_register_clkdev(clk, NULL, "nmk-ske-keypad");
+
+       clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
+                       clkrst3_base, BIT(6), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "uart2");
+
+       clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk",
+                       clkrst3_base, BIT(7), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "sdi5");
+
+       clk = clk_reg_prcc_kclk("p3_i2c5_kclk", "i2cclk",
+                       clkrst3_base, BIT(8), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "nmk-i2c.5");
+
+       clk = clk_reg_prcc_kclk("p3_i2c6_kclk", "i2cclk",
+                       clkrst3_base, BIT(9), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "nmk-i2c.6");
+
+       clk = clk_reg_prcc_kclk("p3_uart3_kclk", "uartclk",
+                       clkrst3_base, BIT(10), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "uart3");
+
+       clk = clk_reg_prcc_kclk("p3_uart4_kclk", "uartclk",
+                       clkrst3_base, BIT(11), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "uart4");
+
+       /* Peripheral 6 : PRCC K-clocks */
+       clk = clk_reg_prcc_kclk("p6_rng_kclk", "rngclk",
+                       clkrst6_base, BIT(0), CLK_SET_RATE_GATE);
+       clk_register_clkdev(clk, NULL, "rng");
 }
index dbc0191e16c8e8aad0863bee6f56525ce93a6a0d..44794782e7e01681414ad123809bf1b8ce35be0b 100644 (file)
 #include <linux/clk-provider.h>
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/platform_data/clk-ux500.h>
-
 #include "clk.h"
 
-void u9540_clk_init(void)
+void u9540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
+                   u32 clkrst5_base, u32 clkrst6_base)
 {
        /* register clocks here */
 }
index 256c8be74df8483073ac84fe2f9984724a837ac9..2dc8b41a339dba3dc359e7ee34b10de98e8eb3fe 100644 (file)
@@ -107,7 +107,7 @@ void __init vexpress_osc_of_setup(struct device_node *node)
        osc->func = vexpress_config_func_get_by_node(node);
        if (!osc->func) {
                pr_err("Failed to obtain config func for node '%s'!\n",
-                               node->name);
+                               node->full_name);
                goto error;
        }
 
@@ -119,7 +119,7 @@ void __init vexpress_osc_of_setup(struct device_node *node)
 
        of_property_read_string(node, "clock-output-names", &init.name);
        if (!init.name)
-               init.name = node->name;
+               init.name = node->full_name;
 
        init.ops = &vexpress_osc_ops;
        init.flags = CLK_IS_ROOT;
index 4f45eee9e33b2746f95c42867c2339f67707fb30..812f83f8b0c646758c9ac6144ccc6c76e0ed03f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Intel Lynxpoint LPSS clocks.
+ * Intel Low Power Subsystem clocks.
  *
  * Copyright (C) 2013, Intel Corporation
  * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
@@ -18,8 +18,6 @@
 #include <linux/platform_data/clk-lpss.h>
 #include <linux/platform_device.h>
 
-#define PRV_CLOCK_PARAMS 0x800
-
 static int lpt_clk_probe(struct platform_device *pdev)
 {
        struct lpss_clk_data *drvdata;
index a2b25418978244d1ae129cf74f031020951f35d4..053d846ab5b108931ccbeacb67ebc7c85696d0f6 100644 (file)
@@ -186,27 +186,19 @@ u32 arch_timer_get_rate(void)
        return arch_timer_rate;
 }
 
-/*
- * Some external users of arch_timer_read_counter (e.g. sched_clock) may try to
- * call it before it has been initialised. Rather than incur a performance
- * penalty checking for initialisation, provide a default implementation that
- * won't lead to time appearing to jump backwards.
- */
-static u64 arch_timer_read_zero(void)
+u64 arch_timer_read_counter(void)
 {
-       return 0;
+       return arch_counter_get_cntvct();
 }
 
-u64 (*arch_timer_read_counter)(void) = arch_timer_read_zero;
-
 static cycle_t arch_counter_read(struct clocksource *cs)
 {
-       return arch_timer_read_counter();
+       return arch_counter_get_cntvct();
 }
 
 static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
 {
-       return arch_timer_read_counter();
+       return arch_counter_get_cntvct();
 }
 
 static struct clocksource clocksource_counter = {
@@ -287,7 +279,7 @@ static int __init arch_timer_register(void)
        cyclecounter.mult = clocksource_counter.mult;
        cyclecounter.shift = clocksource_counter.shift;
        timecounter_init(&timecounter, &cyclecounter,
-                        arch_counter_get_cntpct());
+                        arch_counter_get_cntvct());
 
        if (arch_timer_use_virtual) {
                ppi = arch_timer_ppi[VIRT_PPI];
@@ -376,11 +368,6 @@ static void __init arch_timer_init(struct device_node *np)
                }
        }
 
-       if (arch_timer_use_virtual)
-               arch_timer_read_counter = arch_counter_get_cntvct;
-       else
-               arch_timer_read_counter = arch_counter_get_cntpct;
-
        arch_timer_register();
        arch_timer_arch_init();
 }
index a924408968682961cac83f70f8fef85f8d8ee893..de4d5d93c3fdc826ae013c6f7e0652b13e550f2d 100644 (file)
@@ -5,6 +5,7 @@
 config ARM_BIG_LITTLE_CPUFREQ
        tristate "Generic ARM big LITTLE CPUfreq driver"
        depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK
+       select CPU_FREQ_TABLE
        help
          This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
 
@@ -18,6 +19,7 @@ config ARM_DT_BL_CPUFREQ
 config ARM_EXYNOS_CPUFREQ
        bool "SAMSUNG EXYNOS SoCs"
        depends on ARCH_EXYNOS
+       select CPU_FREQ_TABLE
        default y
        help
          This adds the CPUFreq driver common part for Samsung
@@ -46,6 +48,7 @@ config ARM_EXYNOS5250_CPUFREQ
 config ARM_EXYNOS5440_CPUFREQ
        def_bool SOC_EXYNOS5440
        depends on HAVE_CLK && PM_OPP && OF
+       select CPU_FREQ_TABLE
        help
          This adds the CPUFreq driver for Samsung EXYNOS5440
          SoC. The nature of exynos5440 clock controller is
@@ -55,7 +58,6 @@ config ARM_EXYNOS5440_CPUFREQ
 config ARM_HIGHBANK_CPUFREQ
        tristate "Calxeda Highbank-based"
        depends on ARCH_HIGHBANK
-       select CPU_FREQ_TABLE
        select GENERIC_CPUFREQ_CPU0
        select PM_OPP
        select REGULATOR
@@ -71,6 +73,7 @@ config ARM_IMX6Q_CPUFREQ
        tristate "Freescale i.MX6Q cpufreq support"
        depends on SOC_IMX6Q
        depends on REGULATOR_ANATOP
+       select CPU_FREQ_TABLE
        help
          This adds cpufreq driver support for Freescale i.MX6Q SOC.
 
@@ -86,6 +89,7 @@ config ARM_INTEGRATOR
 
 config ARM_KIRKWOOD_CPUFREQ
        def_bool ARCH_KIRKWOOD && OF
+       select CPU_FREQ_TABLE
        help
          This adds the CPUFreq driver for Marvell Kirkwood
          SoCs.
@@ -149,6 +153,7 @@ config ARM_S3C2412_CPUFREQ
 config ARM_S3C2416_CPUFREQ
        bool "S3C2416 CPU Frequency scaling support"
        depends on CPU_S3C2416
+       select CPU_FREQ_TABLE
        help
          This adds the CPUFreq driver for the Samsung S3C2416 and
          S3C2450 SoC. The S3C2416 supports changing the rate of the
@@ -179,6 +184,7 @@ config ARM_S3C2440_CPUFREQ
 config ARM_S3C64XX_CPUFREQ
        bool "Samsung S3C64XX"
        depends on CPU_S3C6410
+       select CPU_FREQ_TABLE
        default y
        help
          This adds the CPUFreq driver for Samsung S3C6410 SoC.
@@ -205,6 +211,15 @@ config ARM_SA1110_CPUFREQ
 config ARM_SPEAR_CPUFREQ
        bool "SPEAr CPUFreq support"
        depends on PLAT_SPEAR
+       select CPU_FREQ_TABLE
        default y
        help
          This adds the CPUFreq driver support for SPEAr SOCs.
+
+config ARM_TEGRA_CPUFREQ
+       bool "TEGRA CPUFreq support"
+       depends on ARCH_TEGRA
+       select CPU_FREQ_TABLE
+       default y
+       help
+         This adds the CPUFreq driver support for TEGRA SOCs.
index 9c926ca0d718020b048b1efc09b0b55c7b1efe2f..25ca9db62e090d6b49e20d6744c3cd4027a16bfb 100644 (file)
@@ -1,6 +1,7 @@
 config CPU_FREQ_CBE
        tristate "CBE frequency scaling"
        depends on CBE_RAS && PPC_CELL
+       select CPU_FREQ_TABLE
        default m
        help
          This adds the cpufreq driver for Cell BE processors.
@@ -23,3 +24,39 @@ config CPU_FREQ_MAPLE
        help
          This adds support for frequency switching on Maple 970FX
          Evaluation Board and compatible boards (IBM JS2x blades).
+
+config PPC_CORENET_CPUFREQ
+       tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
+       depends on PPC_E500MC && OF && COMMON_CLK
+       select CPU_FREQ_TABLE
+       select CLK_PPC_CORENET
+       help
+         This adds the CPUFreq driver support for Freescale e500mc,
+         e5500 and e6500 series SoCs which are capable of changing
+         the CPU's frequency dynamically.
+
+config CPU_FREQ_PMAC
+       bool "Support for Apple PowerBooks"
+       depends on ADB_PMU && PPC32
+       select CPU_FREQ_TABLE
+       help
+         This adds support for frequency switching on Apple PowerBooks,
+         this currently includes some models of iBook & Titanium
+         PowerBook.
+
+config CPU_FREQ_PMAC64
+       bool "Support for some Apple G5s"
+       depends on PPC_PMAC && PPC64
+       select CPU_FREQ_TABLE
+       help
+         This adds support for frequency switching on Apple iMac G5,
+         and some of the more recent desktop G5 machines as well.
+
+config PPC_PASEMI_CPUFREQ
+       bool "Support for PA Semi PWRficient"
+       depends on PPC_PASEMI
+       select CPU_FREQ_TABLE
+       default y
+       help
+         This adds the support for frequency switching on PA Semi
+         PWRficient processors.
index 6bd63d63d356ba0f2fc731e65824409cee9bf158..e2b6eabef2218d4e1e392ed523b3451553e196cb 100644 (file)
@@ -132,6 +132,7 @@ config X86_POWERNOW_K8
 config X86_AMD_FREQ_SENSITIVITY
        tristate "AMD frequency sensitivity feedback powersave bias"
        depends on CPU_FREQ_GOV_ONDEMAND && X86_ACPI_CPUFREQ && CPU_SUP_AMD
+       select CPU_FREQ_TABLE
        help
          This adds AMD-specific powersave bias function to the ondemand
          governor, which allows it to make more power-conscious frequency
index 6ad0b913ca176c54bb2ef2669d16de355d560541..d345b5a7aa719e52fd660013afdf96b4d3da6335 100644 (file)
@@ -76,7 +76,7 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ)     += s5pv210-cpufreq.o
 obj-$(CONFIG_ARM_SA1100_CPUFREQ)       += sa1100-cpufreq.o
 obj-$(CONFIG_ARM_SA1110_CPUFREQ)       += sa1110-cpufreq.o
 obj-$(CONFIG_ARM_SPEAR_CPUFREQ)                += spear-cpufreq.o
-obj-$(CONFIG_ARCH_TEGRA)               += tegra-cpufreq.o
+obj-$(CONFIG_ARM_TEGRA_CPUFREQ)                += tegra-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
@@ -84,11 +84,15 @@ obj-$(CONFIG_CPU_FREQ_CBE)          += ppc-cbe-cpufreq.o
 ppc-cbe-cpufreq-y                      += ppc_cbe_cpufreq_pervasive.o ppc_cbe_cpufreq.o
 obj-$(CONFIG_CPU_FREQ_CBE_PMI)         += ppc_cbe_cpufreq_pmi.o
 obj-$(CONFIG_CPU_FREQ_MAPLE)           += maple-cpufreq.o
+obj-$(CONFIG_PPC_CORENET_CPUFREQ)   += ppc-corenet-cpufreq.o
+obj-$(CONFIG_CPU_FREQ_PMAC)            += pmac32-cpufreq.o
+obj-$(CONFIG_CPU_FREQ_PMAC64)          += pmac64-cpufreq.o
+obj-$(CONFIG_PPC_PASEMI_CPUFREQ)       += pasemi-cpufreq.o
 
 ##################################################################################
 # Other platform drivers
 obj-$(CONFIG_AVR32_AT32AP_CPUFREQ)     += at32ap-cpufreq.o
-obj-$(CONFIG_BLACKFIN)                 += blackfin-cpufreq.o
+obj-$(CONFIG_BFIN_CPU_FREQ)            += blackfin-cpufreq.o
 obj-$(CONFIG_CRIS_MACH_ARTPEC3)                += cris-artpec3-cpufreq.o
 obj-$(CONFIG_ETRAXFS)                  += cris-etraxfs-cpufreq.o
 obj-$(CONFIG_IA64_ACPI_CPUFREQ)                += ia64-acpi-cpufreq.o
index edc089e9d0c42028aa93a208dde52dea9224df53..39264020b88a1b2e7d461a8d0a3f2f909a31dbb4 100644 (file)
@@ -70,6 +70,7 @@ struct acpi_cpufreq_data {
        struct cpufreq_frequency_table *freq_table;
        unsigned int resume;
        unsigned int cpu_feature;
+       cpumask_var_t freqdomain_cpus;
 };
 
 static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data);
@@ -176,6 +177,15 @@ static struct global_attr global_boost = __ATTR(boost, 0644,
                                                show_global_boost,
                                                store_global_boost);
 
+static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
+{
+       struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+
+       return cpufreq_show_cpus(data->freqdomain_cpus, buf);
+}
+
+cpufreq_freq_attr_ro(freqdomain_cpus);
+
 #ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
 static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
                         size_t count)
@@ -232,7 +242,7 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
        perf = data->acpi_data;
 
        for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
-               if (msr == perf->states[data->freq_table[i].index].status)
+               if (msr == perf->states[data->freq_table[i].driver_data].status)
                        return data->freq_table[i].frequency;
        }
        return data->freq_table[0].frequency;
@@ -442,7 +452,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
                goto out;
        }
 
-       next_perf_state = data->freq_table[next_state].index;
+       next_perf_state = data->freq_table[next_state].driver_data;
        if (perf->state == next_perf_state) {
                if (unlikely(data->resume)) {
                        pr_debug("Called after resume, resetting to P%d\n",
@@ -494,12 +504,14 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
                        pr_debug("acpi_cpufreq_target failed (%d)\n",
                                policy->cpu);
                        result = -EAGAIN;
-                       goto out;
+                       freqs.new = freqs.old;
                }
        }
 
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
-       perf->state = next_perf_state;
+
+       if (!result)
+               perf->state = next_perf_state;
 
 out:
        return result;
@@ -702,6 +714,11 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
        if (!data)
                return -ENOMEM;
 
+       if (!zalloc_cpumask_var(&data->freqdomain_cpus, GFP_KERNEL)) {
+               result = -ENOMEM;
+               goto err_free;
+       }
+
        data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu);
        per_cpu(acfreq_data, cpu) = data;
 
@@ -710,7 +727,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        result = acpi_processor_register_performance(data->acpi_data, cpu);
        if (result)
-               goto err_free;
+               goto err_free_mask;
 
        perf = data->acpi_data;
        policy->shared_type = perf->shared_type;
@@ -723,6 +740,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
            policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
                cpumask_copy(policy->cpus, perf->shared_cpu_map);
        }
+       cpumask_copy(data->freqdomain_cpus, perf->shared_cpu_map);
 
 #ifdef CONFIG_SMP
        dmi_check_system(sw_any_bug_dmi_table);
@@ -734,6 +752,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
        if (check_amd_hwpstate_cpu(cpu) && !acpi_pstate_strict) {
                cpumask_clear(policy->cpus);
                cpumask_set_cpu(cpu, policy->cpus);
+               cpumask_copy(data->freqdomain_cpus, cpu_sibling_mask(cpu));
                policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
                pr_info_once(PFX "overriding BIOS provided _PSD data\n");
        }
@@ -811,7 +830,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
                    data->freq_table[valid_states-1].frequency / 1000)
                        continue;
 
-               data->freq_table[valid_states].index = i;
+               data->freq_table[valid_states].driver_data = i;
                data->freq_table[valid_states].frequency =
                    perf->states[i].core_frequency * 1000;
                valid_states++;
@@ -868,6 +887,8 @@ err_freqfree:
        kfree(data->freq_table);
 err_unreg:
        acpi_processor_unregister_performance(perf, cpu);
+err_free_mask:
+       free_cpumask_var(data->freqdomain_cpus);
 err_free:
        kfree(data);
        per_cpu(acfreq_data, cpu) = NULL;
@@ -886,6 +907,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
                per_cpu(acfreq_data, policy->cpu) = NULL;
                acpi_processor_unregister_performance(data->acpi_data,
                                                      policy->cpu);
+               free_cpumask_var(data->freqdomain_cpus);
                kfree(data->freq_table);
                kfree(data);
        }
@@ -906,6 +928,7 @@ static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
 
 static struct freq_attr *acpi_cpufreq_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
+       &freqdomain_cpus,
        NULL,   /* this is a placeholder for cpb, do not remove */
        NULL,
 };
@@ -947,7 +970,7 @@ static void __init acpi_cpufreq_boost_init(void)
        /* We create the boost file in any case, though for systems without
         * hardware support it will be read-only and hardwired to return 0.
         */
-       if (sysfs_create_file(cpufreq_global_kobject, &(global_boost.attr)))
+       if (cpufreq_sysfs_create_file(&(global_boost.attr)))
                pr_warn(PFX "could not register global boost sysfs file\n");
        else
                pr_debug("registered global boost sysfs file\n");
@@ -955,7 +978,7 @@ static void __init acpi_cpufreq_boost_init(void)
 
 static void __exit acpi_cpufreq_boost_exit(void)
 {
-       sysfs_remove_file(cpufreq_global_kobject, &(global_boost.attr));
+       cpufreq_sysfs_remove_file(&(global_boost.attr));
 
        if (msrs) {
                unregister_cpu_notifier(&boost_nb);
@@ -1034,4 +1057,11 @@ static const struct x86_cpu_id acpi_cpufreq_ids[] = {
 };
 MODULE_DEVICE_TABLE(x86cpu, acpi_cpufreq_ids);
 
+static const struct acpi_device_id processor_device_ids[] = {
+       {ACPI_PROCESSOR_OBJECT_HID, },
+       {ACPI_PROCESSOR_DEVICE_HID, },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, processor_device_ids);
+
 MODULE_ALIAS("acpi");
index 5d7f53fcd6f5eac052d4a0bfed4d48f531921d8c..3549f0784af176d07ee17dd60d02ec85859d6bd1 100644 (file)
@@ -84,11 +84,9 @@ static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
        ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);
        if (ret) {
                pr_err("clk_set_rate failed: %d\n", ret);
-               return ret;
+               freqs.new = freqs.old;
        }
 
-       policy->cur = freqs.new;
-
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
 
        return ret;
index 995511e80bef6d012b5fe0c4a7319db324dbd9c6..9cdbbd278a800da1587eae1fdb6314d23d0a9b9d 100644 (file)
 
 
 /* this is the table of CCLK frequencies, in Hz */
-/* .index is the entry in the auxiliary dpm_state_table[] */
+/* .driver_data is the entry in the auxiliary dpm_state_table[] */
 static struct cpufreq_frequency_table bfin_freq_table[] = {
        {
                .frequency = CPUFREQ_TABLE_END,
-               .index = 0,
+               .driver_data = 0,
        },
        {
                .frequency = CPUFREQ_TABLE_END,
-               .index = 1,
+               .driver_data = 1,
        },
        {
                .frequency = CPUFREQ_TABLE_END,
-               .index = 2,
+               .driver_data = 2,
        },
        {
                .frequency = CPUFREQ_TABLE_END,
-               .index = 0,
+               .driver_data = 0,
        },
 };
 
index 2d53f47d1747360b8968c7c308c0f975777ef9ab..6a015ada5285720389d1191a210d541f41b429fe 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2001 Russell King
  *            (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
+ *            (C) 2013 Viresh Kumar <viresh.kumar@linaro.org>
  *
  *  Oct 2005 - Ashok Raj <ashok.raj@intel.com>
  *     Added handling for CPU hotplug
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <asm/cputime.h>
 #include <linux/kernel.h>
+#include <linux/kernel_stat.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/notifier.h>
@@ -25,6 +27,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <linux/tick.h>
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/cpu.h>
  */
 static struct cpufreq_driver *cpufreq_driver;
 static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
+static DEFINE_RWLOCK(cpufreq_driver_lock);
+static DEFINE_MUTEX(cpufreq_governor_lock);
+
 #ifdef CONFIG_HOTPLUG_CPU
 /* This one keeps track of the previously set governor of a removed CPU */
 static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
 #endif
-static DEFINE_RWLOCK(cpufreq_driver_lock);
 
 /*
  * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
@@ -132,6 +137,51 @@ bool have_governor_per_policy(void)
 {
        return cpufreq_driver->have_governor_per_policy;
 }
+EXPORT_SYMBOL_GPL(have_governor_per_policy);
+
+struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
+{
+       if (have_governor_per_policy())
+               return &policy->kobj;
+       else
+               return cpufreq_global_kobject;
+}
+EXPORT_SYMBOL_GPL(get_governor_parent_kobj);
+
+static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
+{
+       u64 idle_time;
+       u64 cur_wall_time;
+       u64 busy_time;
+
+       cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
+
+       busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
+
+       idle_time = cur_wall_time - busy_time;
+       if (wall)
+               *wall = cputime_to_usecs(cur_wall_time);
+
+       return cputime_to_usecs(idle_time);
+}
+
+u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
+{
+       u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL);
+
+       if (idle_time == -1ULL)
+               return get_cpu_idle_time_jiffy(cpu, wall);
+       else if (!io_busy)
+               idle_time += get_cpu_iowait_time_us(cpu, wall);
+
+       return idle_time;
+}
+EXPORT_SYMBOL_GPL(get_cpu_idle_time);
 
 static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
 {
@@ -150,7 +200,6 @@ static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
        if (!try_module_get(cpufreq_driver->owner))
                goto err_out_unlock;
 
-
        /* get the CPU */
        data = per_cpu(cpufreq_cpu_data, cpu);
 
@@ -220,7 +269,7 @@ static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data)
  */
 #ifndef CONFIG_SMP
 static unsigned long l_p_j_ref;
-static unsigned int  l_p_j_ref_freq;
+static unsigned int l_p_j_ref_freq;
 
 static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
 {
@@ -233,7 +282,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
                pr_debug("saving %lu as reference value for loops_per_jiffy; "
                        "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
        }
-       if ((val == CPUFREQ_POSTCHANGE  && ci->old != ci->new) ||
+       if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) ||
            (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
                loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
                                                                ci->new);
@@ -248,8 +297,7 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
 }
 #endif
 
-
-void __cpufreq_notify_transition(struct cpufreq_policy *policy,
+static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
                struct cpufreq_freqs *freqs, unsigned int state)
 {
        BUG_ON(irqs_disabled());
@@ -264,6 +312,12 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
        switch (state) {
 
        case CPUFREQ_PRECHANGE:
+               if (WARN(policy->transition_ongoing,
+                               "In middle of another frequency transition\n"))
+                       return;
+
+               policy->transition_ongoing = true;
+
                /* detect if the driver reported a value as "old frequency"
                 * which is not equal to what the cpufreq core thinks is
                 * "old frequency".
@@ -283,6 +337,12 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
                break;
 
        case CPUFREQ_POSTCHANGE:
+               if (WARN(!policy->transition_ongoing,
+                               "No frequency transition in progress\n"))
+                       return;
+
+               policy->transition_ongoing = false;
+
                adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
                pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
                        (unsigned long)freqs->cpu);
@@ -294,6 +354,7 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
                break;
        }
 }
+
 /**
  * cpufreq_notify_transition - call notifier chain and adjust_jiffies
  * on frequency transition.
@@ -311,7 +372,6 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy,
 EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
 
 
-
 /*********************************************************************
  *                          SYSFS INTERFACE                          *
  *********************************************************************/
@@ -376,7 +436,6 @@ out:
        return err;
 }
 
-
 /**
  * cpufreq_per_cpu_attr_read() / show_##file_name() -
  * print out cpufreq information
@@ -441,7 +500,6 @@ static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
        return sprintf(buf, "%u\n", cur_freq);
 }
 
-
 /**
  * show_scaling_governor - show the current policy for the specified CPU
  */
@@ -457,7 +515,6 @@ static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
        return -EINVAL;
 }
 
-
 /**
  * store_scaling_governor - store policy for the specified CPU
  */
@@ -480,8 +537,10 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
                                                &new_policy.governor))
                return -EINVAL;
 
-       /* Do not use cpufreq_set_policy here or the user_policy.max
-          will be wrongly overridden */
+       /*
+        * Do not use cpufreq_set_policy here or the user_policy.max
+        * will be wrongly overridden
+        */
        ret = __cpufreq_set_policy(policy, &new_policy);
 
        policy->user_policy.policy = policy->policy;
@@ -526,7 +585,7 @@ out:
        return i;
 }
 
-static ssize_t show_cpus(const struct cpumask *mask, char *buf)
+ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf)
 {
        ssize_t i = 0;
        unsigned int cpu;
@@ -541,6 +600,7 @@ static ssize_t show_cpus(const struct cpumask *mask, char *buf)
        i += sprintf(&buf[i], "\n");
        return i;
 }
+EXPORT_SYMBOL_GPL(cpufreq_show_cpus);
 
 /**
  * show_related_cpus - show the CPUs affected by each transition even if
@@ -548,7 +608,7 @@ static ssize_t show_cpus(const struct cpumask *mask, char *buf)
  */
 static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)
 {
-       return show_cpus(policy->related_cpus, buf);
+       return cpufreq_show_cpus(policy->related_cpus, buf);
 }
 
 /**
@@ -556,7 +616,7 @@ static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)
  */
 static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
 {
-       return show_cpus(policy->cpus, buf);
+       return cpufreq_show_cpus(policy->cpus, buf);
 }
 
 static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
@@ -630,9 +690,6 @@ static struct attribute *default_attrs[] = {
        NULL
 };
 
-struct kobject *cpufreq_global_kobject;
-EXPORT_SYMBOL(cpufreq_global_kobject);
-
 #define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
 #define to_attr(a) container_of(a, struct freq_attr, attr)
 
@@ -703,6 +760,49 @@ static struct kobj_type ktype_cpufreq = {
        .release        = cpufreq_sysfs_release,
 };
 
+struct kobject *cpufreq_global_kobject;
+EXPORT_SYMBOL(cpufreq_global_kobject);
+
+static int cpufreq_global_kobject_usage;
+
+int cpufreq_get_global_kobject(void)
+{
+       if (!cpufreq_global_kobject_usage++)
+               return kobject_add(cpufreq_global_kobject,
+                               &cpu_subsys.dev_root->kobj, "%s", "cpufreq");
+
+       return 0;
+}
+EXPORT_SYMBOL(cpufreq_get_global_kobject);
+
+void cpufreq_put_global_kobject(void)
+{
+       if (!--cpufreq_global_kobject_usage)
+               kobject_del(cpufreq_global_kobject);
+}
+EXPORT_SYMBOL(cpufreq_put_global_kobject);
+
+int cpufreq_sysfs_create_file(const struct attribute *attr)
+{
+       int ret = cpufreq_get_global_kobject();
+
+       if (!ret) {
+               ret = sysfs_create_file(cpufreq_global_kobject, attr);
+               if (ret)
+                       cpufreq_put_global_kobject();
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(cpufreq_sysfs_create_file);
+
+void cpufreq_sysfs_remove_file(const struct attribute *attr)
+{
+       sysfs_remove_file(cpufreq_global_kobject, attr);
+       cpufreq_put_global_kobject();
+}
+EXPORT_SYMBOL(cpufreq_sysfs_remove_file);
+
 /* symlink affected CPUs */
 static int cpufreq_add_dev_symlink(unsigned int cpu,
                                   struct cpufreq_policy *policy)
@@ -1005,7 +1105,8 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
  * Caller should already have policy_rwsem in write mode for this CPU.
  * This routine frees the rwsem before returning.
  */
-static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
+static int __cpufreq_remove_dev(struct device *dev,
+               struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id, ret, cpus;
        unsigned long flags;
@@ -1112,7 +1213,6 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
        return 0;
 }
 
-
 static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id;
@@ -1125,7 +1225,6 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
        return retval;
 }
 
-
 static void handle_update(struct work_struct *work)
 {
        struct cpufreq_policy *policy =
@@ -1136,7 +1235,8 @@ static void handle_update(struct work_struct *work)
 }
 
 /**
- *     cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble.
+ *     cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're
+ *     in deep trouble.
  *     @cpu: cpu number
  *     @old_freq: CPU frequency the kernel thinks the CPU runs at
  *     @new_freq: CPU frequency the CPU actually runs at
@@ -1151,7 +1251,6 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
        struct cpufreq_freqs freqs;
        unsigned long flags;
 
-
        pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
               "core thinks of %u, is %u kHz.\n", old_freq, new_freq);
 
@@ -1166,7 +1265,6 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
 }
 
-
 /**
  * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
  * @cpu: CPU number
@@ -1212,7 +1310,6 @@ unsigned int cpufreq_quick_get_max(unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_quick_get_max);
 
-
 static unsigned int __cpufreq_get(unsigned int cpu)
 {
        struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
@@ -1271,7 +1368,6 @@ static struct subsys_interface cpufreq_interface = {
        .remove_dev     = cpufreq_remove_dev,
 };
 
-
 /**
  * cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
  *
@@ -1408,11 +1504,10 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
 }
 EXPORT_SYMBOL(cpufreq_register_notifier);
 
-
 /**
  *     cpufreq_unregister_notifier - unregister a driver with cpufreq
  *     @nb: notifier block to be unregistered
- *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
+ *     @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
  *
  *     Remove a driver from the CPU frequency notifier list.
  *
@@ -1448,7 +1543,6 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
  *                              GOVERNORS                            *
  *********************************************************************/
 
-
 int __cpufreq_driver_target(struct cpufreq_policy *policy,
                            unsigned int target_freq,
                            unsigned int relation)
@@ -1458,6 +1552,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
 
        if (cpufreq_disabled())
                return -ENODEV;
+       if (policy->transition_ongoing)
+               return -EBUSY;
 
        /* Make sure that target_freq is within supported range */
        if (target_freq > policy->max)
@@ -1484,10 +1580,6 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
 {
        int ret = -EINVAL;
 
-       policy = cpufreq_cpu_get(policy->cpu);
-       if (!policy)
-               goto no_policy;
-
        if (unlikely(lock_policy_rwsem_write(policy->cpu)))
                goto fail;
 
@@ -1496,30 +1588,19 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
        unlock_policy_rwsem_write(policy->cpu);
 
 fail:
-       cpufreq_cpu_put(policy);
-no_policy:
        return ret;
 }
 EXPORT_SYMBOL_GPL(cpufreq_driver_target);
 
 int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
 {
-       int ret = 0;
-
        if (cpufreq_disabled())
-               return ret;
+               return 0;
 
        if (!cpufreq_driver->getavg)
                return 0;
 
-       policy = cpufreq_cpu_get(policy->cpu);
-       if (!policy)
-               return -EINVAL;
-
-       ret = cpufreq_driver->getavg(policy, cpu);
-
-       cpufreq_cpu_put(policy);
-       return ret;
+       return cpufreq_driver->getavg(policy, cpu);
 }
 EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg);
 
@@ -1562,6 +1643,21 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
 
        pr_debug("__cpufreq_governor for CPU %u, event %u\n",
                                                policy->cpu, event);
+
+       mutex_lock(&cpufreq_governor_lock);
+       if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) ||
+           (policy->governor_enabled && (event == CPUFREQ_GOV_START))) {
+               mutex_unlock(&cpufreq_governor_lock);
+               return -EBUSY;
+       }
+
+       if (event == CPUFREQ_GOV_STOP)
+               policy->governor_enabled = false;
+       else if (event == CPUFREQ_GOV_START)
+               policy->governor_enabled = true;
+
+       mutex_unlock(&cpufreq_governor_lock);
+
        ret = policy->governor->governor(policy, event);
 
        if (!ret) {
@@ -1569,6 +1665,14 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
                        policy->governor->initialized++;
                else if (event == CPUFREQ_GOV_POLICY_EXIT)
                        policy->governor->initialized--;
+       } else {
+               /* Restore original values */
+               mutex_lock(&cpufreq_governor_lock);
+               if (event == CPUFREQ_GOV_STOP)
+                       policy->governor_enabled = true;
+               else if (event == CPUFREQ_GOV_START)
+                       policy->governor_enabled = false;
+               mutex_unlock(&cpufreq_governor_lock);
        }
 
        /* we keep one module reference alive for
@@ -1581,7 +1685,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
        return ret;
 }
 
-
 int cpufreq_register_governor(struct cpufreq_governor *governor)
 {
        int err;
@@ -1606,7 +1709,6 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
 }
 EXPORT_SYMBOL_GPL(cpufreq_register_governor);
 
-
 void cpufreq_unregister_governor(struct cpufreq_governor *governor)
 {
 #ifdef CONFIG_HOTPLUG_CPU
@@ -1636,7 +1738,6 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
 EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
 
 
-
 /*********************************************************************
  *                          POLICY INTERFACE                         *
  *********************************************************************/
@@ -1665,7 +1766,6 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_get_policy);
 
-
 /*
  * data   : current policy.
  * policy : policy to be set.
@@ -1699,8 +1799,10 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
                        CPUFREQ_INCOMPATIBLE, policy);
 
-       /* verify the cpu speed can be set within this limit,
-          which might be different to the first one */
+       /*
+        * verify the cpu speed can be set within this limit, which might be
+        * different to the first one
+        */
        ret = cpufreq_driver->verify(policy);
        if (ret)
                goto error_out;
@@ -1802,8 +1904,10 @@ int cpufreq_update_policy(unsigned int cpu)
        policy.policy = data->user_policy.policy;
        policy.governor = data->user_policy.governor;
 
-       /* BIOS might change freq behind our back
-         -> ask driver for current freq and notify governors about a change */
+       /*
+        * BIOS might change freq behind our back
+        * -> ask driver for current freq and notify governors about a change
+        */
        if (cpufreq_driver->get) {
                policy.cur = cpufreq_driver->get(cpu);
                if (!data->cur) {
@@ -1852,7 +1956,7 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
 }
 
 static struct notifier_block __refdata cpufreq_cpu_notifier = {
-    .notifier_call = cpufreq_cpu_callback,
+       .notifier_call = cpufreq_cpu_callback,
 };
 
 /*********************************************************************
@@ -1864,7 +1968,7 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
  * @driver_data: A struct cpufreq_driver containing the values#
  * submitted by the CPU Frequency driver.
  *
- *   Registers a CPU Frequency driver to this core code. This code
+ * Registers a CPU Frequency driver to this core code. This code
  * returns zero on success, -EBUSY when another driver got here first
  * (and isn't unregistered in the meantime).
  *
@@ -1931,11 +2035,10 @@ err_null_driver:
 }
 EXPORT_SYMBOL_GPL(cpufreq_register_driver);
 
-
 /**
  * cpufreq_unregister_driver - unregister the current CPUFreq driver
  *
- *    Unregister the current CPUFreq driver. Only call this if you have
+ * Unregister the current CPUFreq driver. Only call this if you have
  * the right to do so, i.e. if you have succeeded in initialising before!
  * Returns zero if successful, and -EINVAL if the cpufreq_driver is
  * currently not initialised.
@@ -1972,7 +2075,7 @@ static int __init cpufreq_core_init(void)
                init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
        }
 
-       cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
+       cpufreq_global_kobject = kobject_create();
        BUG_ON(!cpufreq_global_kobject);
        register_syscore_ops(&cpufreq_syscore_ops);
 
index dc9b72e25c1ab66c429fb65e9cb1d410ef4ee908..464587697561d177bf5d9675b58a2eae0c89e507 100644 (file)
 #include <linux/kernel_stat.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/tick.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
 #include <linux/cpu.h>
 
 #include "cpufreq_governor.h"
 
-static struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
-{
-       if (have_governor_per_policy())
-               return &policy->kobj;
-       else
-               return cpufreq_global_kobject;
-}
-
 static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data)
 {
        if (have_governor_per_policy())
@@ -46,41 +37,6 @@ static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data)
                return dbs_data->cdata->attr_group_gov_sys;
 }
 
-static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
-{
-       u64 idle_time;
-       u64 cur_wall_time;
-       u64 busy_time;
-
-       cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
-
-       busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER];
-       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM];
-       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ];
-       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ];
-       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
-       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
-
-       idle_time = cur_wall_time - busy_time;
-       if (wall)
-               *wall = cputime_to_usecs(cur_wall_time);
-
-       return cputime_to_usecs(idle_time);
-}
-
-u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
-{
-       u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL);
-
-       if (idle_time == -1ULL)
-               return get_cpu_idle_time_jiffy(cpu, wall);
-       else if (!io_busy)
-               idle_time += get_cpu_iowait_time_us(cpu, wall);
-
-       return idle_time;
-}
-EXPORT_SYMBOL_GPL(get_cpu_idle_time);
-
 void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
 {
        struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
@@ -278,6 +234,9 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        return rc;
                }
 
+               if (!have_governor_per_policy())
+                       WARN_ON(cpufreq_get_global_kobject());
+
                rc = sysfs_create_group(get_governor_parent_kobj(policy),
                                get_sysfs_attr(dbs_data));
                if (rc) {
@@ -316,6 +275,9 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        sysfs_remove_group(get_governor_parent_kobj(policy),
                                        get_sysfs_attr(dbs_data));
 
+                       if (!have_governor_per_policy())
+                               cpufreq_put_global_kobject();
+
                        if ((dbs_data->cdata->governor == GOV_CONSERVATIVE) &&
                                (policy->governor->initialized == 1)) {
                                struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
@@ -404,6 +366,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
 
                mutex_lock(&dbs_data->mutex);
                mutex_destroy(&cpu_cdbs->timer_mutex);
+               cpu_cdbs->cur_policy = NULL;
 
                mutex_unlock(&dbs_data->mutex);
 
index e16a96130cb3491d30f376728144cdca92e441cd..6663ec3b30565ac7efb6a7b5842e301ad2160bba 100644 (file)
@@ -81,7 +81,7 @@ static ssize_t show_##file_name##_gov_sys                             \
        return sprintf(buf, "%u\n", tuners->file_name);                 \
 }                                                                      \
                                                                        \
-static ssize_t show_##file_name##_gov_pol                                      \
+static ssize_t show_##file_name##_gov_pol                              \
 (struct cpufreq_policy *policy, char *buf)                             \
 {                                                                      \
        struct dbs_data *dbs_data = policy->governor_data;              \
@@ -91,7 +91,7 @@ static ssize_t show_##file_name##_gov_pol                                     \
 
 #define store_one(_gov, file_name)                                     \
 static ssize_t store_##file_name##_gov_sys                             \
-(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count)  \
+(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) \
 {                                                                      \
        struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data;         \
        return store_##file_name(dbs_data, buf, count);                 \
@@ -256,7 +256,6 @@ static ssize_t show_sampling_rate_min_gov_pol                               \
        return sprintf(buf, "%u\n", dbs_data->min_sampling_rate);       \
 }
 
-u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy);
 void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
 bool need_load_eval(struct cpu_dbs_common_info *cdbs,
                unsigned int sampling_rate);
index ceee06849b9167bb63e423f2aee29ecba3751f57..9fef7d6e4e6a6f05a96e7b8153ecb0043e7a4f6e 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/cpufreq.h>
 #include <linux/init.h>
 
-
 static int cpufreq_governor_performance(struct cpufreq_policy *policy,
                                        unsigned int event)
 {
@@ -44,19 +43,16 @@ struct cpufreq_governor cpufreq_gov_performance = {
        .owner          = THIS_MODULE,
 };
 
-
 static int __init cpufreq_gov_performance_init(void)
 {
        return cpufreq_register_governor(&cpufreq_gov_performance);
 }
 
-
 static void __exit cpufreq_gov_performance_exit(void)
 {
        cpufreq_unregister_governor(&cpufreq_gov_performance);
 }
 
-
 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
 MODULE_DESCRIPTION("CPUfreq policy governor 'performance'");
 MODULE_LICENSE("GPL");
index 2d948a1711551de4b1ad95b6fd5bbc455bccab36..32109a14f5dc04e0d99c89a8113428afa545bbb7 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  linux/drivers/cpufreq/cpufreq_powersave.c
+ * linux/drivers/cpufreq/cpufreq_powersave.c
  *
- *  Copyright (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
  *
  *
  * This program is free software; you can redistribute it and/or modify
@@ -48,13 +48,11 @@ static int __init cpufreq_gov_powersave_init(void)
        return cpufreq_register_governor(&cpufreq_gov_powersave);
 }
 
-
 static void __exit cpufreq_gov_powersave_exit(void)
 {
        cpufreq_unregister_governor(&cpufreq_gov_powersave);
 }
 
-
 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
 MODULE_DESCRIPTION("CPUfreq policy governor 'powersave'");
 MODULE_LICENSE("GPL");
index fb65decffa28128ded8817441b2e5eff8ecad8e3..cd9e81713a71343b00f4c2e761f5f32c56824ab3 100644 (file)
@@ -27,7 +27,7 @@ static spinlock_t cpufreq_stats_lock;
 struct cpufreq_stats {
        unsigned int cpu;
        unsigned int total_trans;
-       unsigned long long  last_time;
+       unsigned long long last_time;
        unsigned int max_state;
        unsigned int state_num;
        unsigned int last_index;
@@ -116,7 +116,7 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
                len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
                                stat->freq_table[i]);
 
-               for (j = 0; j < stat->state_num; j++)   {
+               for (j = 0; j < stat->state_num; j++) {
                        if (len >= PAGE_SIZE)
                                break;
                        len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
@@ -349,6 +349,7 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                cpufreq_update_policy(cpu);
                break;
        case CPU_DOWN_PREPARE:
index bbeb9c0720a665ead5c76462d2f8882461f48e95..03078090b5f76e15d263f3a035f575f9e7901342 100644 (file)
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
 #include <linux/cpufreq.h>
-#include <linux/cpu.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/sysfs.h>
+#include <linux/init.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
 
-/**
- * A few values needed by the userspace governor
- */
-static DEFINE_PER_CPU(unsigned int, cpu_max_freq);
-static DEFINE_PER_CPU(unsigned int, cpu_min_freq);
-static DEFINE_PER_CPU(unsigned int, cpu_cur_freq); /* current CPU freq */
-static DEFINE_PER_CPU(unsigned int, cpu_set_freq); /* CPU freq desired by
-                                                       userspace */
 static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
-
 static DEFINE_MUTEX(userspace_mutex);
-static int cpus_using_userspace_governor;
-
-/* keep track of frequency transitions */
-static int
-userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
-       void *data)
-{
-       struct cpufreq_freqs *freq = data;
-
-       if (!per_cpu(cpu_is_managed, freq->cpu))
-               return 0;
-
-       if (val == CPUFREQ_POSTCHANGE) {
-               pr_debug("saving cpu_cur_freq of cpu %u to be %u kHz\n",
-                               freq->cpu, freq->new);
-               per_cpu(cpu_cur_freq, freq->cpu) = freq->new;
-       }
-
-       return 0;
-}
-
-static struct notifier_block userspace_cpufreq_notifier_block = {
-       .notifier_call  = userspace_cpufreq_notifier
-};
-
 
 /**
  * cpufreq_set - set the CPU frequency
@@ -80,13 +38,6 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
        if (!per_cpu(cpu_is_managed, policy->cpu))
                goto err;
 
-       per_cpu(cpu_set_freq, policy->cpu) = freq;
-
-       if (freq < per_cpu(cpu_min_freq, policy->cpu))
-               freq = per_cpu(cpu_min_freq, policy->cpu);
-       if (freq > per_cpu(cpu_max_freq, policy->cpu))
-               freq = per_cpu(cpu_max_freq, policy->cpu);
-
        /*
         * We're safe from concurrent calls to ->target() here
         * as we hold the userspace_mutex lock. If we were calling
@@ -104,10 +55,9 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
        return ret;
 }
 
-
 static ssize_t show_speed(struct cpufreq_policy *policy, char *buf)
 {
-       return sprintf(buf, "%u\n", per_cpu(cpu_cur_freq, policy->cpu));
+       return sprintf(buf, "%u\n", policy->cur);
 }
 
 static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
@@ -119,73 +69,37 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
        switch (event) {
        case CPUFREQ_GOV_START:
                BUG_ON(!policy->cur);
-               mutex_lock(&userspace_mutex);
-
-               if (cpus_using_userspace_governor == 0) {
-                       cpufreq_register_notifier(
-                                       &userspace_cpufreq_notifier_block,
-                                       CPUFREQ_TRANSITION_NOTIFIER);
-               }
-               cpus_using_userspace_governor++;
+               pr_debug("started managing cpu %u\n", cpu);
 
+               mutex_lock(&userspace_mutex);
                per_cpu(cpu_is_managed, cpu) = 1;
-               per_cpu(cpu_min_freq, cpu) = policy->min;
-               per_cpu(cpu_max_freq, cpu) = policy->max;
-               per_cpu(cpu_cur_freq, cpu) = policy->cur;
-               per_cpu(cpu_set_freq, cpu) = policy->cur;
-               pr_debug("managing cpu %u started "
-                       "(%u - %u kHz, currently %u kHz)\n",
-                               cpu,
-                               per_cpu(cpu_min_freq, cpu),
-                               per_cpu(cpu_max_freq, cpu),
-                               per_cpu(cpu_cur_freq, cpu));
-
                mutex_unlock(&userspace_mutex);
                break;
        case CPUFREQ_GOV_STOP:
-               mutex_lock(&userspace_mutex);
-               cpus_using_userspace_governor--;
-               if (cpus_using_userspace_governor == 0) {
-                       cpufreq_unregister_notifier(
-                                       &userspace_cpufreq_notifier_block,
-                                       CPUFREQ_TRANSITION_NOTIFIER);
-               }
+               pr_debug("managing cpu %u stopped\n", cpu);
 
+               mutex_lock(&userspace_mutex);
                per_cpu(cpu_is_managed, cpu) = 0;
-               per_cpu(cpu_min_freq, cpu) = 0;
-               per_cpu(cpu_max_freq, cpu) = 0;
-               per_cpu(cpu_set_freq, cpu) = 0;
-               pr_debug("managing cpu %u stopped\n", cpu);
                mutex_unlock(&userspace_mutex);
                break;
        case CPUFREQ_GOV_LIMITS:
                mutex_lock(&userspace_mutex);
-               pr_debug("limit event for cpu %u: %u - %u kHz, "
-                       "currently %u kHz, last set to %u kHz\n",
+               pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n",
                        cpu, policy->min, policy->max,
-                       per_cpu(cpu_cur_freq, cpu),
-                       per_cpu(cpu_set_freq, cpu));
-               if (policy->max < per_cpu(cpu_set_freq, cpu)) {
+                       policy->cur);
+
+               if (policy->max < policy->cur)
                        __cpufreq_driver_target(policy, policy->max,
                                                CPUFREQ_RELATION_H);
-               } else if (policy->min > per_cpu(cpu_set_freq, cpu)) {
+               else if (policy->min > policy->cur)
                        __cpufreq_driver_target(policy, policy->min,
                                                CPUFREQ_RELATION_L);
-               } else {
-                       __cpufreq_driver_target(policy,
-                                               per_cpu(cpu_set_freq, cpu),
-                                               CPUFREQ_RELATION_L);
-               }
-               per_cpu(cpu_min_freq, cpu) = policy->min;
-               per_cpu(cpu_max_freq, cpu) = policy->max;
-               per_cpu(cpu_cur_freq, cpu) = policy->cur;
                mutex_unlock(&userspace_mutex);
                break;
        }
        return rc;
 }
 
-
 #ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
 static
 #endif
@@ -202,13 +116,11 @@ static int __init cpufreq_gov_userspace_init(void)
        return cpufreq_register_governor(&cpufreq_gov_userspace);
 }
 
-
 static void __exit cpufreq_gov_userspace_exit(void)
 {
        cpufreq_unregister_governor(&cpufreq_gov_userspace);
 }
 
-
 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, "
                "Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'");
index c33c76c360faa98c92e3232374609875e022c541..551dd655c6f2ac1d49fb1238ee20f38c213e3f36 100644 (file)
@@ -114,6 +114,9 @@ static int davinci_target(struct cpufreq_policy *policy,
                pdata->set_voltage(idx);
 
 out:
+       if (ret)
+               freqs.new = freqs.old;
+
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
 
        return ret;
index 6ec6539ae0418895a4b54619e98eeac7d647159c..1fdb02b9f1ec84f221e8ba26dfeefd53105eb9a3 100644 (file)
@@ -57,13 +57,13 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
        if (ret) {
                pr_err("dbx500-cpufreq: Failed to set armss_clk to %d Hz: error %d\n",
                       freqs.new * 1000, ret);
-               return ret;
+               freqs.new = freqs.old;
        }
 
        /* post change notification */
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
 
-       return 0;
+       return ret;
 }
 
 static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu)
index 37380fb92621c6606803237d10f4b9987efd6684..a60efaeb4cf8c17291ec97a0ba86bb383fe81d55 100644 (file)
@@ -161,6 +161,9 @@ postchange:
                current_multiplier);
        }
 #endif
+       if (err)
+               freqs.new = freqs.old;
+
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
        return err;
 }
@@ -188,7 +191,7 @@ static int eps_target(struct cpufreq_policy *policy,
        }
 
        /* Make frequency transition */
-       dest_state = centaur->freq_table[newstate].index & 0xffff;
+       dest_state = centaur->freq_table[newstate].driver_data & 0xffff;
        ret = eps_set_state(centaur, policy, dest_state);
        if (ret)
                printk(KERN_ERR "eps: Timeout!\n");
@@ -380,9 +383,9 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
        f_table = &centaur->freq_table[0];
        if (brand != EPS_BRAND_C7M) {
                f_table[0].frequency = fsb * min_multiplier;
-               f_table[0].index = (min_multiplier << 8) | min_voltage;
+               f_table[0].driver_data = (min_multiplier << 8) | min_voltage;
                f_table[1].frequency = fsb * max_multiplier;
-               f_table[1].index = (max_multiplier << 8) | max_voltage;
+               f_table[1].driver_data = (max_multiplier << 8) | max_voltage;
                f_table[2].frequency = CPUFREQ_TABLE_END;
        } else {
                k = 0;
@@ -391,7 +394,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
                for (i = min_multiplier; i <= max_multiplier; i++) {
                        voltage = (k * step) / 256 + min_voltage;
                        f_table[k].frequency = fsb * i;
-                       f_table[k].index = (i << 8) | voltage;
+                       f_table[k].driver_data = (i << 8) | voltage;
                        k++;
                }
                f_table[k].frequency = CPUFREQ_TABLE_END;
index 475b4f607f0d10c469e3f2352625d3273ade0376..0d32f02ef4d644e5ec915b9205fd5fdf929b30b0 100644 (file)
@@ -113,7 +113,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
                if (ret) {
                        pr_err("%s: failed to set cpu voltage to %d\n",
                                __func__, arm_volt);
-                       goto out;
+                       freqs.new = freqs.old;
+                       goto post_notify;
                }
        }
 
@@ -123,14 +124,19 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
                if (ret) {
                        pr_err("%s: failed to set cpu voltage to %d\n",
                                __func__, safe_arm_volt);
-                       goto out;
+                       freqs.new = freqs.old;
+                       goto post_notify;
                }
        }
 
        exynos_info->set_freq(old_index, index);
 
+post_notify:
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
 
+       if (ret)
+               goto out;
+
        /* When the new frequency is lower than current frequency */
        if ((freqs.new < freqs.old) ||
           ((freqs.new > freqs.old) && safe_arm_volt)) {
index d7a79662e24c44bdb4c31c18530217b85255a019..f0d87412cc91742a73fa40a500b160387af9fb28 100644 (file)
@@ -34,8 +34,8 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
 
                        continue;
                }
-               pr_debug("table entry %u: %u kHz, %u index\n",
-                                       i, freq, table[i].index);
+               pr_debug("table entry %u: %u kHz, %u driver_data\n",
+                                       i, freq, table[i].driver_data);
                if (freq < min_freq)
                        min_freq = freq;
                if (freq > max_freq)
@@ -97,11 +97,11 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
                                   unsigned int *index)
 {
        struct cpufreq_frequency_table optimal = {
-               .index = ~0,
+               .driver_data = ~0,
                .frequency = 0,
        };
        struct cpufreq_frequency_table suboptimal = {
-               .index = ~0,
+               .driver_data = ~0,
                .frequency = 0,
        };
        unsigned int i;
@@ -129,12 +129,12 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
                        if (freq <= target_freq) {
                                if (freq >= optimal.frequency) {
                                        optimal.frequency = freq;
-                                       optimal.index = i;
+                                       optimal.driver_data = i;
                                }
                        } else {
                                if (freq <= suboptimal.frequency) {
                                        suboptimal.frequency = freq;
-                                       suboptimal.index = i;
+                                       suboptimal.driver_data = i;
                                }
                        }
                        break;
@@ -142,26 +142,26 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
                        if (freq >= target_freq) {
                                if (freq <= optimal.frequency) {
                                        optimal.frequency = freq;
-                                       optimal.index = i;
+                                       optimal.driver_data = i;
                                }
                        } else {
                                if (freq >= suboptimal.frequency) {
                                        suboptimal.frequency = freq;
-                                       suboptimal.index = i;
+                                       suboptimal.driver_data = i;
                                }
                        }
                        break;
                }
        }
-       if (optimal.index > i) {
-               if (suboptimal.index > i)
+       if (optimal.driver_data > i) {
+               if (suboptimal.driver_data > i)
                        return -EINVAL;
-               *index = suboptimal.index;
+               *index = suboptimal.driver_data;
        } else
-               *index = optimal.index;
+               *index = optimal.driver_data;
 
        pr_debug("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
-               table[*index].index);
+               table[*index].driver_data);
 
        return 0;
 }
index c0075dbaa6336a2ad92d1138dce15ef4ab6cb66f..573c14ea802df7690f0e57ff3d8764b46305e51c 100644 (file)
@@ -326,7 +326,7 @@ acpi_cpufreq_cpu_init (
        /* table init */
        for (i = 0; i <= data->acpi_data.state_count; i++)
        {
-               data->freq_table[i].index = i;
+               data->freq_table[i].driver_data = i;
                if (i < data->acpi_data.state_count) {
                        data->freq_table[i].frequency =
                              data->acpi_data.states[i].core_frequency * 1000;
index b78bc35973ba33f74cf795e67ba8eda00b069cc5..e37cdaedbb5b39b244e3aa6caec947721297999d 100644 (file)
@@ -68,8 +68,6 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
        if (freqs.old == freqs.new)
                return 0;
 
-       cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
-
        rcu_read_lock();
        opp = opp_find_freq_ceil(cpu_dev, &freq_hz);
        if (IS_ERR(opp)) {
@@ -86,13 +84,16 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
                freqs.old / 1000, volt_old / 1000,
                freqs.new / 1000, volt / 1000);
 
+       cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
        /* scaling up?  scale voltage before frequency */
        if (freqs.new > freqs.old) {
                ret = regulator_set_voltage_tol(arm_reg, volt, 0);
                if (ret) {
                        dev_err(cpu_dev,
                                "failed to scale vddarm up: %d\n", ret);
-                       return ret;
+                       freqs.new = freqs.old;
+                       goto post_notify;
                }
 
                /*
@@ -145,15 +146,18 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
        if (ret) {
                dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
                regulator_set_voltage_tol(arm_reg, volt_old, 0);
-               return ret;
+               freqs.new = freqs.old;
+               goto post_notify;
        }
 
        /* scaling down?  scale voltage after frequency */
        if (freqs.new < freqs.old) {
                ret = regulator_set_voltage_tol(arm_reg, volt, 0);
-               if (ret)
+               if (ret) {
                        dev_warn(cpu_dev,
                                 "failed to scale vddarm down: %d\n", ret);
+                       ret = 0;
+               }
 
                if (freqs.old == FREQ_1P2_GHZ / 1000) {
                        regulator_set_voltage_tol(pu_reg,
@@ -163,9 +167,10 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
                }
        }
 
+post_notify:
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
 
-       return 0;
+       return ret;
 }
 
 static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
index b2644af985ec8e741daf009262069694c671513b..c233ea617366fad2c7e4a3ed1b2bc0a7f500fda1 100644 (file)
@@ -59,7 +59,7 @@ static void kirkwood_cpufreq_set_cpu_state(struct cpufreq_policy *policy,
                unsigned int index)
 {
        struct cpufreq_freqs freqs;
-       unsigned int state = kirkwood_freq_table[index].index;
+       unsigned int state = kirkwood_freq_table[index].driver_data;
        unsigned long reg;
 
        freqs.old = kirkwood_cpufreq_get_cpu_frequency(0);
index b448638e34de0df1183a07d6b3d1e089f87e9b95..b6a0a7a406b06bf415de8e07f5d3730560d41ba0 100644 (file)
@@ -254,7 +254,7 @@ static void longhaul_setstate(struct cpufreq_policy *policy,
        u32 bm_timeout = 1000;
        unsigned int dir = 0;
 
-       mults_index = longhaul_table[table_index].index;
+       mults_index = longhaul_table[table_index].driver_data;
        /* Safety precautions */
        mult = mults[mults_index & 0x1f];
        if (mult == -1)
@@ -487,7 +487,7 @@ static int __cpuinit longhaul_get_ranges(void)
                if (ratio > maxmult || ratio < minmult)
                        continue;
                longhaul_table[k].frequency = calc_speed(ratio);
-               longhaul_table[k].index = j;
+               longhaul_table[k].driver_data   = j;
                k++;
        }
        if (k <= 1) {
@@ -508,8 +508,8 @@ static int __cpuinit longhaul_get_ranges(void)
                if (min_i != j) {
                        swap(longhaul_table[j].frequency,
                             longhaul_table[min_i].frequency);
-                       swap(longhaul_table[j].index,
-                            longhaul_table[min_i].index);
+                       swap(longhaul_table[j].driver_data,
+                            longhaul_table[min_i].driver_data);
                }
        }
 
@@ -517,7 +517,7 @@ static int __cpuinit longhaul_get_ranges(void)
 
        /* Find index we are running on */
        for (j = 0; j < k; j++) {
-               if (mults[longhaul_table[j].index & 0x1f] == mult) {
+               if (mults[longhaul_table[j].driver_data & 0x1f] == mult) {
                        longhaul_index = j;
                        break;
                }
@@ -613,7 +613,7 @@ static void __cpuinit longhaul_setup_voltagescaling(void)
                        pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
                else
                        pos = minvid.pos;
-               longhaul_table[j].index |= mV_vrm_table[pos] << 8;
+               longhaul_table[j].driver_data |= mV_vrm_table[pos] << 8;
                vid = vrm_mV_table[mV_vrm_table[pos]];
                printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
                                speed, j, vid.mV);
@@ -656,12 +656,12 @@ static int longhaul_target(struct cpufreq_policy *policy,
                 * this in hardware, C3 is old and we need to do this
                 * in software. */
                i = longhaul_index;
-               current_vid = (longhaul_table[longhaul_index].index >> 8);
+               current_vid = (longhaul_table[longhaul_index].driver_data >> 8);
                current_vid &= 0x1f;
                if (table_index > longhaul_index)
                        dir = 1;
                while (i != table_index) {
-                       vid = (longhaul_table[i].index >> 8) & 0x1f;
+                       vid = (longhaul_table[i].driver_data >> 8) & 0x1f;
                        if (vid != current_vid) {
                                longhaul_setstate(policy, i);
                                current_vid = vid;
index d53912768946b96c1c27b017dbaeb7a10e7c2feb..bb838b98507747a02ade005d99074a4c2a1d95a8 100644 (file)
@@ -72,7 +72,7 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
 
        freq =
            ((cpu_clock_freq / 1000) *
-            loongson2_clockmod_table[newstate].index) / 8;
+            loongson2_clockmod_table[newstate].driver_data) / 8;
        if (freq < policy->min || freq > policy->max)
                return -EINVAL;
 
index 0279d18a57f96499bc3f67a5a9c4e8e0ce785081..29468a522ee9a799180b8cf18b178bb43d16acb7 100644 (file)
@@ -93,9 +93,6 @@ static int omap_target(struct cpufreq_policy *policy,
        if (freqs.old == freqs.new && policy->cur == freqs.new)
                return ret;
 
-       /* notifiers */
-       cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
-
        freq = freqs.new * 1000;
        ret = clk_round_rate(mpu_clk, freq);
        if (IS_ERR_VALUE(ret)) {
@@ -125,6 +122,9 @@ static int omap_target(struct cpufreq_policy *policy,
                freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
                freqs.new / 1000, volt ? volt / 1000 : -1);
 
+       /* notifiers */
+       cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
        /* scaling up?  scale voltage before frequency */
        if (mpu_reg && (freqs.new > freqs.old)) {
                r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
index 421ef37d0bb382dcfd1e35ad9e03d55880a7f808..9ee78170ff862a20cd7439e78d9ef0d71b542e77 100644 (file)
@@ -118,7 +118,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
                return -EINVAL;
 
        freqs.old = cpufreq_p4_get(policy->cpu);
-       freqs.new = stock_freq * p4clockmod_table[newstate].index / 8;
+       freqs.new = stock_freq * p4clockmod_table[newstate].driver_data / 8;
 
        if (freqs.new == freqs.old)
                return 0;
@@ -131,7 +131,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
         * Developer's Manual, Volume 3
         */
        for_each_cpu(i, policy->cpus)
-               cpufreq_p4_setdc(i, p4clockmod_table[newstate].index);
+               cpufreq_p4_setdc(i, p4clockmod_table[newstate].driver_data);
 
        /* notifiers */
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
similarity index 98%
rename from arch/powerpc/platforms/pasemi/cpufreq.c
rename to drivers/cpufreq/pasemi-cpufreq.c
index be1e7958909eac4079a4ec641fa231e2500707a4..b704da404067061a4acd831e78b63572b54afc8c 100644 (file)
@@ -204,7 +204,8 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        /* initialize frequency table */
        for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
-               pas_freqs[i].frequency = get_astate_freq(pas_freqs[i].index) * 100000;
+               pas_freqs[i].frequency =
+                       get_astate_freq(pas_freqs[i].driver_data) * 100000;
                pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
        }
 
@@ -280,7 +281,7 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy,
        pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
                 policy->cpu,
                 pas_freqs[pas_astate_new].frequency,
-                pas_freqs[pas_astate_new].index);
+                pas_freqs[pas_astate_new].driver_data);
 
        current_astate = pas_astate_new;
 
index 0de00081a81e9b636d42a282123f902838a1e306..1581fcc4cf4a9f3cf8de7b782abe932328584ef0 100644 (file)
@@ -243,6 +243,8 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
        return 0;
 
 cmd_incomplete:
+       freqs.new = freqs.old;
+       cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
        iowrite16(0, &pcch_hdr->status);
        spin_unlock(&pcc_lock);
        return -EINVAL;
index ea0222a45b7b4241d66af2d4ba64e894a2caa178..ea8e10382ec56b46c6a378d0bf84801a1a221108 100644 (file)
@@ -58,7 +58,7 @@ static int powernow_k6_get_cpu_multiplier(void)
        msrval = POWERNOW_IOPORT + 0x0;
        wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
 
-       return clock_ratio[(invalue >> 5)&7].index;
+       return clock_ratio[(invalue >> 5)&7].driver_data;
 }
 
 
@@ -75,13 +75,13 @@ static void powernow_k6_set_state(struct cpufreq_policy *policy,
        unsigned long msrval;
        struct cpufreq_freqs freqs;
 
-       if (clock_ratio[best_i].index > max_multiplier) {
+       if (clock_ratio[best_i].driver_data > max_multiplier) {
                printk(KERN_ERR PFX "invalid target frequency\n");
                return;
        }
 
        freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
-       freqs.new = busfreq * clock_ratio[best_i].index;
+       freqs.new = busfreq * clock_ratio[best_i].driver_data;
 
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
 
@@ -156,7 +156,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
 
        /* table init */
        for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
-               f = clock_ratio[i].index;
+               f = clock_ratio[i].driver_data;
                if (f > max_multiplier)
                        clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
                else
index 53888dacbe585608b0af69d8a8fbe6df8612c54a..b9f80b713fda939c469472f7ad9193b37b374966 100644 (file)
@@ -186,7 +186,7 @@ static int get_ranges(unsigned char *pst)
                fid = *pst++;
 
                powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
-               powernow_table[j].index = fid; /* lower 8 bits */
+               powernow_table[j].driver_data = fid; /* lower 8 bits */
 
                speed = powernow_table[j].frequency;
 
@@ -203,7 +203,7 @@ static int get_ranges(unsigned char *pst)
                        maximum_speed = speed;
 
                vid = *pst++;
-               powernow_table[j].index |= (vid << 8); /* upper 8 bits */
+               powernow_table[j].driver_data |= (vid << 8); /* upper 8 bits */
 
                pr_debug("   FID: 0x%x (%d.%dx [%dMHz])  "
                         "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
@@ -212,7 +212,7 @@ static int get_ranges(unsigned char *pst)
                         mobile_vid_table[vid]%1000);
        }
        powernow_table[number_scales].frequency = CPUFREQ_TABLE_END;
-       powernow_table[number_scales].index = 0;
+       powernow_table[number_scales].driver_data = 0;
 
        return 0;
 }
@@ -260,8 +260,8 @@ static void change_speed(struct cpufreq_policy *policy, unsigned int index)
         * vid are the upper 8 bits.
         */
 
-       fid = powernow_table[index].index & 0xFF;
-       vid = (powernow_table[index].index & 0xFF00) >> 8;
+       fid = powernow_table[index].driver_data & 0xFF;
+       vid = (powernow_table[index].driver_data & 0xFF00) >> 8;
 
        rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
        cfid = fidvidstatus.bits.CFID;
@@ -373,8 +373,8 @@ static int powernow_acpi_init(void)
                fid = pc.bits.fid;
 
                powernow_table[i].frequency = fsb * fid_codes[fid] / 10;
-               powernow_table[i].index = fid; /* lower 8 bits */
-               powernow_table[i].index |= (vid << 8); /* upper 8 bits */
+               powernow_table[i].driver_data = fid; /* lower 8 bits */
+               powernow_table[i].driver_data |= (vid << 8); /* upper 8 bits */
 
                speed = powernow_table[i].frequency;
                speed_mhz = speed / 1000;
@@ -417,7 +417,7 @@ static int powernow_acpi_init(void)
        }
 
        powernow_table[i].frequency = CPUFREQ_TABLE_END;
-       powernow_table[i].index = 0;
+       powernow_table[i].driver_data = 0;
 
        /* notify BIOS that we exist */
        acpi_processor_notify_smm(THIS_MODULE);
index b828efe4b2f86976f66ce686ae335f754f5a7eeb..78f018f2a5deb5db485a718068825723ffeabba1 100644 (file)
@@ -584,9 +584,9 @@ static void print_basics(struct powernow_k8_data *data)
                                CPUFREQ_ENTRY_INVALID) {
                                printk(KERN_INFO PFX
                                        "fid 0x%x (%d MHz), vid 0x%x\n",
-                                       data->powernow_table[j].index & 0xff,
+                                       data->powernow_table[j].driver_data & 0xff,
                                        data->powernow_table[j].frequency/1000,
-                                       data->powernow_table[j].index >> 8);
+                                       data->powernow_table[j].driver_data >> 8);
                }
        }
        if (data->batps)
@@ -632,13 +632,13 @@ static int fill_powernow_table(struct powernow_k8_data *data,
 
        for (j = 0; j < data->numps; j++) {
                int freq;
-               powernow_table[j].index = pst[j].fid; /* lower 8 bits */
-               powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */
+               powernow_table[j].driver_data = pst[j].fid; /* lower 8 bits */
+               powernow_table[j].driver_data |= (pst[j].vid << 8); /* upper 8 bits */
                freq = find_khz_freq_from_fid(pst[j].fid);
                powernow_table[j].frequency = freq;
        }
        powernow_table[data->numps].frequency = CPUFREQ_TABLE_END;
-       powernow_table[data->numps].index = 0;
+       powernow_table[data->numps].driver_data = 0;
 
        if (query_current_values_with_pending_wait(data)) {
                kfree(powernow_table);
@@ -810,7 +810,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
 
        powernow_table[data->acpi_data.state_count].frequency =
                CPUFREQ_TABLE_END;
-       powernow_table[data->acpi_data.state_count].index = 0;
+       powernow_table[data->acpi_data.state_count].driver_data = 0;
        data->powernow_table = powernow_table;
 
        if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu)
@@ -865,7 +865,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
                pr_debug("   %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
 
                index = fid | (vid<<8);
-               powernow_table[i].index = index;
+               powernow_table[i].driver_data = index;
 
                freq = find_khz_freq_from_fid(fid);
                powernow_table[i].frequency = freq;
@@ -941,8 +941,8 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
         * the cpufreq frequency table in find_psb_table, vid
         * are the upper 8 bits.
         */
-       fid = data->powernow_table[index].index & 0xFF;
-       vid = (data->powernow_table[index].index & 0xFF00) >> 8;
+       fid = data->powernow_table[index].driver_data & 0xFF;
+       vid = (data->powernow_table[index].driver_data & 0xFF00) >> 8;
 
        pr_debug("table matched fid 0x%x, giving vid 0x%x\n", fid, vid);
 
@@ -967,9 +967,9 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
 
        res = transition_fid_vid(data, fid, vid);
        if (res)
-               return res;
-
-       freqs.new = find_khz_freq_from_fid(data->currfid);
+               freqs.new = freqs.old;
+       else
+               freqs.new = find_khz_freq_from_fid(data->currfid);
 
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
        return res;
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
new file mode 100644 (file)
index 0000000..3cae452
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * CPU Frequency Scaling driver for Freescale PowerPC corenet SoCs.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/errno.h>
+#include <sysdev/fsl_soc.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+
+/**
+ * struct cpu_data - per CPU data struct
+ * @clk: the clk of CPU
+ * @parent: the parent node of cpu clock
+ * @table: frequency table
+ */
+struct cpu_data {
+       struct clk *clk;
+       struct device_node *parent;
+       struct cpufreq_frequency_table *table;
+};
+
+/**
+ * struct soc_data - SoC specific data
+ * @freq_mask: mask the disallowed frequencies
+ * @flag: unique flags
+ */
+struct soc_data {
+       u32 freq_mask[4];
+       u32 flag;
+};
+
+#define FREQ_MASK      1
+/* see hardware specification for the allowed frqeuencies */
+static const struct soc_data sdata[] = {
+       { /* used by p2041 and p3041 */
+               .freq_mask = {0x8, 0x8, 0x2, 0x2},
+               .flag = FREQ_MASK,
+       },
+       { /* used by p5020 */
+               .freq_mask = {0x8, 0x2},
+               .flag = FREQ_MASK,
+       },
+       { /* used by p4080, p5040 */
+               .freq_mask = {0},
+               .flag = 0,
+       },
+};
+
+/*
+ * the minimum allowed core frequency, in Hz
+ * for chassis v1.0, >= platform frequency
+ * for chassis v2.0, >= platform frequency / 2
+ */
+static u32 min_cpufreq;
+static const u32 *fmask;
+
+/* serialize frequency changes  */
+static DEFINE_MUTEX(cpufreq_lock);
+static DEFINE_PER_CPU(struct cpu_data *, cpu_data);
+
+/* cpumask in a cluster */
+static DEFINE_PER_CPU(cpumask_var_t, cpu_mask);
+
+#ifndef CONFIG_SMP
+static inline const struct cpumask *cpu_core_mask(int cpu)
+{
+       return cpumask_of(0);
+}
+#endif
+
+static unsigned int corenet_cpufreq_get_speed(unsigned int cpu)
+{
+       struct cpu_data *data = per_cpu(cpu_data, cpu);
+
+       return clk_get_rate(data->clk) / 1000;
+}
+
+/* reduce the duplicated frequencies in frequency table */
+static void freq_table_redup(struct cpufreq_frequency_table *freq_table,
+               int count)
+{
+       int i, j;
+
+       for (i = 1; i < count; i++) {
+               for (j = 0; j < i; j++) {
+                       if (freq_table[j].frequency == CPUFREQ_ENTRY_INVALID ||
+                                       freq_table[j].frequency !=
+                                       freq_table[i].frequency)
+                               continue;
+
+                       freq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+                       break;
+               }
+       }
+}
+
+/* sort the frequencies in frequency table in descenting order */
+static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
+               int count)
+{
+       int i, j, ind;
+       unsigned int freq, max_freq;
+       struct cpufreq_frequency_table table;
+       for (i = 0; i < count - 1; i++) {
+               max_freq = freq_table[i].frequency;
+               ind = i;
+               for (j = i + 1; j < count; j++) {
+                       freq = freq_table[j].frequency;
+                       if (freq == CPUFREQ_ENTRY_INVALID ||
+                                       freq <= max_freq)
+                               continue;
+                       ind = j;
+                       max_freq = freq;
+               }
+
+               if (ind != i) {
+                       /* exchange the frequencies */
+                       table.driver_data = freq_table[i].driver_data;
+                       table.frequency = freq_table[i].frequency;
+                       freq_table[i].driver_data = freq_table[ind].driver_data;
+                       freq_table[i].frequency = freq_table[ind].frequency;
+                       freq_table[ind].driver_data = table.driver_data;
+                       freq_table[ind].frequency = table.frequency;
+               }
+       }
+}
+
+static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+       struct device_node *np;
+       int i, count, ret;
+       u32 freq, mask;
+       struct clk *clk;
+       struct cpufreq_frequency_table *table;
+       struct cpu_data *data;
+       unsigned int cpu = policy->cpu;
+
+       np = of_get_cpu_node(cpu, NULL);
+       if (!np)
+               return -ENODEV;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               pr_err("%s: no memory\n", __func__);
+               goto err_np;
+       }
+
+       data->clk = of_clk_get(np, 0);
+       if (IS_ERR(data->clk)) {
+               pr_err("%s: no clock information\n", __func__);
+               goto err_nomem2;
+       }
+
+       data->parent = of_parse_phandle(np, "clocks", 0);
+       if (!data->parent) {
+               pr_err("%s: could not get clock information\n", __func__);
+               goto err_nomem2;
+       }
+
+       count = of_property_count_strings(data->parent, "clock-names");
+       table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
+       if (!table) {
+               pr_err("%s: no memory\n", __func__);
+               goto err_node;
+       }
+
+       if (fmask)
+               mask = fmask[get_hard_smp_processor_id(cpu)];
+       else
+               mask = 0x0;
+
+       for (i = 0; i < count; i++) {
+               clk = of_clk_get(data->parent, i);
+               freq = clk_get_rate(clk);
+               /*
+                * the clock is valid if its frequency is not masked
+                * and large than minimum allowed frequency.
+                */
+               if (freq < min_cpufreq || (mask & (1 << i)))
+                       table[i].frequency = CPUFREQ_ENTRY_INVALID;
+               else
+                       table[i].frequency = freq / 1000;
+               table[i].driver_data = i;
+       }
+       freq_table_redup(table, count);
+       freq_table_sort(table, count);
+       table[i].frequency = CPUFREQ_TABLE_END;
+
+       /* set the min and max frequency properly */
+       ret = cpufreq_frequency_table_cpuinfo(policy, table);
+       if (ret) {
+               pr_err("invalid frequency table: %d\n", ret);
+               goto err_nomem1;
+       }
+
+       data->table = table;
+       per_cpu(cpu_data, cpu) = data;
+
+       /* update ->cpus if we have cluster, no harm if not */
+       cpumask_copy(policy->cpus, per_cpu(cpu_mask, cpu));
+       for_each_cpu(i, per_cpu(cpu_mask, cpu))
+               per_cpu(cpu_data, i) = data;
+
+       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+       policy->cur = corenet_cpufreq_get_speed(policy->cpu);
+
+       cpufreq_frequency_table_get_attr(table, cpu);
+       of_node_put(np);
+
+       return 0;
+
+err_nomem1:
+       kfree(table);
+err_node:
+       of_node_put(data->parent);
+err_nomem2:
+       per_cpu(cpu_data, cpu) = NULL;
+       kfree(data);
+err_np:
+       of_node_put(np);
+
+       return -ENODEV;
+}
+
+static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+       struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
+       unsigned int cpu;
+
+       cpufreq_frequency_table_put_attr(policy->cpu);
+       of_node_put(data->parent);
+       kfree(data->table);
+       kfree(data);
+
+       for_each_cpu(cpu, per_cpu(cpu_mask, policy->cpu))
+               per_cpu(cpu_data, cpu) = NULL;
+
+       return 0;
+}
+
+static int corenet_cpufreq_verify(struct cpufreq_policy *policy)
+{
+       struct cpufreq_frequency_table *table =
+               per_cpu(cpu_data, policy->cpu)->table;
+
+       return cpufreq_frequency_table_verify(policy, table);
+}
+
+static int corenet_cpufreq_target(struct cpufreq_policy *policy,
+               unsigned int target_freq, unsigned int relation)
+{
+       struct cpufreq_freqs freqs;
+       unsigned int new;
+       struct clk *parent;
+       int ret;
+       struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
+
+       cpufreq_frequency_table_target(policy, data->table,
+                       target_freq, relation, &new);
+
+       if (policy->cur == data->table[new].frequency)
+               return 0;
+
+       freqs.old = policy->cur;
+       freqs.new = data->table[new].frequency;
+
+       mutex_lock(&cpufreq_lock);
+       cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
+       parent = of_clk_get(data->parent, data->table[new].driver_data);
+       ret = clk_set_parent(data->clk, parent);
+       if (ret)
+               freqs.new = freqs.old;
+
+       cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+       mutex_unlock(&cpufreq_lock);
+
+       return ret;
+}
+
+static struct freq_attr *corenet_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
+       .name           = "ppc_cpufreq",
+       .owner          = THIS_MODULE,
+       .flags          = CPUFREQ_CONST_LOOPS,
+       .init           = corenet_cpufreq_cpu_init,
+       .exit           = __exit_p(corenet_cpufreq_cpu_exit),
+       .verify         = corenet_cpufreq_verify,
+       .target         = corenet_cpufreq_target,
+       .get            = corenet_cpufreq_get_speed,
+       .attr           = corenet_cpufreq_attr,
+};
+
+static const struct of_device_id node_matches[] __initdata = {
+       { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], },
+       { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], },
+       { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], },
+       { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], },
+       { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], },
+       { .compatible = "fsl,qoriq-clockgen-2.0", },
+       {}
+};
+
+static int __init ppc_corenet_cpufreq_init(void)
+{
+       int ret;
+       struct device_node  *np;
+       const struct of_device_id *match;
+       const struct soc_data *data;
+       unsigned int cpu;
+
+       np = of_find_matching_node(NULL, node_matches);
+       if (!np)
+               return -ENODEV;
+
+       for_each_possible_cpu(cpu) {
+               if (!alloc_cpumask_var(&per_cpu(cpu_mask, cpu), GFP_KERNEL))
+                       goto err_mask;
+               cpumask_copy(per_cpu(cpu_mask, cpu), cpu_core_mask(cpu));
+       }
+
+       match = of_match_node(node_matches, np);
+       data = match->data;
+       if (data) {
+               if (data->flag)
+                       fmask = data->freq_mask;
+               min_cpufreq = fsl_get_sys_freq();
+       } else {
+               min_cpufreq = fsl_get_sys_freq() / 2;
+       }
+
+       of_node_put(np);
+
+       ret = cpufreq_register_driver(&ppc_corenet_cpufreq_driver);
+       if (!ret)
+               pr_info("Freescale PowerPC corenet CPU frequency scaling driver\n");
+
+       return ret;
+
+err_mask:
+       for_each_possible_cpu(cpu)
+               free_cpumask_var(per_cpu(cpu_mask, cpu));
+
+       return -ENOMEM;
+}
+module_init(ppc_corenet_cpufreq_init);
+
+static void __exit ppc_corenet_cpufreq_exit(void)
+{
+       unsigned int cpu;
+
+       for_each_possible_cpu(cpu)
+               free_cpumask_var(per_cpu(cpu_mask, cpu));
+
+       cpufreq_unregister_driver(&ppc_corenet_cpufreq_driver);
+}
+module_exit(ppc_corenet_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
+MODULE_DESCRIPTION("cpufreq driver for Freescale e500mc series SoCs");
index e577a1dbbfcd572be200a7a73f81728959bb24b5..5936f8d6f2cc3e855ce52a814705ee9d1e35b10b 100644 (file)
@@ -106,7 +106,7 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        /* initialize frequency table */
        for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
-               cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index;
+               cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data;
                pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
        }
 
@@ -165,7 +165,7 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy,
                 "1/%d of max frequency\n",
                 policy->cpu,
                 cbe_freqs[cbe_pmode_new].frequency,
-                cbe_freqs[cbe_pmode_new].index);
+                cbe_freqs[cbe_pmode_new].driver_data);
 
        rc = set_pmode(policy->cpu, cbe_pmode_new);
 
index 9e5bc8e388a0239ee5061fdd427c016e8abf68b5..fb3981ac829fdb0a1eb73483ee3484fe7426990c 100644 (file)
@@ -420,7 +420,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
        /* Generate pxa25x the run cpufreq_frequency_table struct */
        for (i = 0; i < NUM_PXA25x_RUN_FREQS; i++) {
                pxa255_run_freq_table[i].frequency = pxa255_run_freqs[i].khz;
-               pxa255_run_freq_table[i].index = i;
+               pxa255_run_freq_table[i].driver_data = i;
        }
        pxa255_run_freq_table[i].frequency = CPUFREQ_TABLE_END;
 
@@ -428,7 +428,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
        for (i = 0; i < NUM_PXA25x_TURBO_FREQS; i++) {
                pxa255_turbo_freq_table[i].frequency =
                        pxa255_turbo_freqs[i].khz;
-               pxa255_turbo_freq_table[i].index = i;
+               pxa255_turbo_freq_table[i].driver_data = i;
        }
        pxa255_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END;
 
@@ -440,9 +440,9 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
                if (freq > pxa27x_maxfreq)
                        break;
                pxa27x_freq_table[i].frequency = freq;
-               pxa27x_freq_table[i].index = i;
+               pxa27x_freq_table[i].driver_data = i;
        }
-       pxa27x_freq_table[i].index = i;
+       pxa27x_freq_table[i].driver_data = i;
        pxa27x_freq_table[i].frequency = CPUFREQ_TABLE_END;
 
        /*
index 15d60f857ad567f92bfdb6735f9b2f7d51804a7c..9c92ef032a9e978800e4897a2a3e8322c0d1c031 100644 (file)
@@ -98,10 +98,10 @@ static int setup_freqs_table(struct cpufreq_policy *policy,
                return -ENOMEM;
 
        for (i = 0; i < num; i++) {
-               table[i].index = i;
+               table[i].driver_data = i;
                table[i].frequency = freqs[i].cpufreq_mhz * 1000;
        }
-       table[num].index = i;
+       table[num].driver_data = i;
        table[num].frequency = CPUFREQ_TABLE_END;
 
        pxa3xx_freqs = freqs;
index 4f1881eee3f12a803a58ae373f044551f87d4edb..e35865af96e2e1320a17bfdd001c84eb708d2c46 100644 (file)
@@ -244,7 +244,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
        if (ret != 0)
                goto out;
 
-       idx = s3c_freq->freq_table[i].index;
+       idx = s3c_freq->freq_table[i].driver_data;
 
        if (idx == SOURCE_HCLK)
                to_dvs = 1;
@@ -312,7 +312,7 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
                if (freq->frequency == CPUFREQ_ENTRY_INVALID)
                        continue;
 
-               dvfs = &s3c2416_dvfs_table[freq->index];
+               dvfs = &s3c2416_dvfs_table[freq->driver_data];
                found = 0;
 
                /* Check only the min-voltage, more is always ok on S3C2416 */
@@ -462,7 +462,7 @@ static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
        freq = s3c_freq->freq_table;
        while (freq->frequency != CPUFREQ_TABLE_END) {
                /* special handling for dvs mode */
-               if (freq->index == 0) {
+               if (freq->driver_data == 0) {
                        if (!s3c_freq->hclk) {
                                pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
                                         freq->frequency);
index 3c0e78ede0da0fcaa82512c6f9f91f3af2260f7b..3513e747716007f0700dc58df1e8c96bffdc2151 100644 (file)
@@ -70,7 +70,7 @@ static void s3c_cpufreq_getcur(struct s3c_cpufreq_config *cfg)
        cfg->freq.pclk = pclk = clk_get_rate(clk_pclk);
        cfg->freq.armclk = armclk = clk_get_rate(clk_arm);
 
-       cfg->pll.index = __raw_readl(S3C2410_MPLLCON);
+       cfg->pll.driver_data = __raw_readl(S3C2410_MPLLCON);
        cfg->pll.frequency = fclk;
 
        cfg->freq.hclk_tns = 1000000000 / (cfg->freq.hclk / 10);
@@ -431,7 +431,7 @@ static unsigned int suspend_freq;
 static int s3c_cpufreq_suspend(struct cpufreq_policy *policy)
 {
        suspend_pll.frequency = clk_get_rate(_clk_mpll);
-       suspend_pll.index = __raw_readl(S3C2410_MPLLCON);
+       suspend_pll.driver_data = __raw_readl(S3C2410_MPLLCON);
        suspend_freq = s3c_cpufreq_get(0) * 1000;
 
        return 0;
index 27cacb524796994f2cc06a5bef1478aa8e4b9e06..13bb4bae64ee11505fb8a072d041ec9a8268bf84 100644 (file)
@@ -87,7 +87,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
        freqs.old = clk_get_rate(armclk) / 1000;
        freqs.new = s3c64xx_freq_table[i].frequency;
        freqs.flags = 0;
-       dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[i].index];
+       dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[i].driver_data];
 
        if (freqs.old == freqs.new)
                return 0;
@@ -104,7 +104,8 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
                if (ret != 0) {
                        pr_err("Failed to set VDDARM for %dkHz: %d\n",
                               freqs.new, ret);
-                       goto err;
+                       freqs.new = freqs.old;
+                       goto post_notify;
                }
        }
 #endif
@@ -113,10 +114,13 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
        if (ret < 0) {
                pr_err("Failed to set rate %dkHz: %d\n",
                       freqs.new, ret);
-               goto err;
+               freqs.new = freqs.old;
        }
 
+post_notify:
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+       if (ret)
+               goto err;
 
 #ifdef CONFIG_REGULATOR
        if (vddarm && freqs.new < freqs.old) {
index f740b134d27b2f9e87edb5e5d0e76713539ebf62..77a210975fc4b66ce737703f6904483d45368776 100644 (file)
@@ -71,7 +71,7 @@ static void sc520_freq_set_cpu_state(struct cpufreq_policy *policy,
        local_irq_disable();
 
        clockspeed_reg = *cpuctl & ~0x03;
-       *cpuctl = clockspeed_reg | sc520_freq_table[state].index;
+       *cpuctl = clockspeed_reg | sc520_freq_table[state].driver_data;
 
        local_irq_enable();
 
index 306ae462bba6ac951ce6383be391d4e4066610fe..93061a40877383b09ceff0cb7bd0bc2bba60a08a 100644 (file)
@@ -308,17 +308,17 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
        struct cpufreq_frequency_table *table =
                &us2e_freq_table[cpu].table[0];
 
-       table[0].index = 0;
+       table[0].driver_data = 0;
        table[0].frequency = clock_tick / 1;
-       table[1].index = 1;
+       table[1].driver_data = 1;
        table[1].frequency = clock_tick / 2;
-       table[2].index = 2;
+       table[2].driver_data = 2;
        table[2].frequency = clock_tick / 4;
-       table[2].index = 3;
+       table[2].driver_data = 3;
        table[2].frequency = clock_tick / 6;
-       table[2].index = 4;
+       table[2].driver_data = 4;
        table[2].frequency = clock_tick / 8;
-       table[2].index = 5;
+       table[2].driver_data = 5;
        table[3].frequency = CPUFREQ_TABLE_END;
 
        policy->cpuinfo.transition_latency = 0;
index c71ee142347aadcd0ed6015ec7cc60c3f572e369..880ee293d61eda8c131187d65579a5216ce2b00d 100644 (file)
@@ -169,13 +169,13 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
        struct cpufreq_frequency_table *table =
                &us3_freq_table[cpu].table[0];
 
-       table[0].index = 0;
+       table[0].driver_data = 0;
        table[0].frequency = clock_tick / 1;
-       table[1].index = 1;
+       table[1].driver_data = 1;
        table[1].frequency = clock_tick / 2;
-       table[2].index = 2;
+       table[2].driver_data = 2;
        table[2].frequency = clock_tick / 32;
-       table[3].index = 0;
+       table[3].driver_data = 0;
        table[3].frequency = CPUFREQ_TABLE_END;
 
        policy->cpuinfo.transition_latency = 0;
index 156829f4576de63497147d6e72f5e1d05e2e5cae..c3efa7f2a9088d9ea43f68e149632939e357a8dd 100644 (file)
@@ -250,11 +250,11 @@ static int spear_cpufreq_driver_init(void)
        }
 
        for (i = 0; i < cnt; i++) {
-               freq_tbl[i].index = i;
+               freq_tbl[i].driver_data = i;
                freq_tbl[i].frequency = be32_to_cpup(val++);
        }
 
-       freq_tbl[i].index = i;
+       freq_tbl[i].driver_data = i;
        freq_tbl[i].frequency = CPUFREQ_TABLE_END;
 
        spear_cpufreq.freq_tbl = freq_tbl;
index 618e6f417b1cd48780d970c0b5a628e9b8024017..0915e712fbdcc3a6393c1974c12394e060cc3c1f 100644 (file)
@@ -79,11 +79,11 @@ static struct cpufreq_driver centrino_driver;
 
 /* Computes the correct form for IA32_PERF_CTL MSR for a particular
    frequency/voltage operating point; frequency in MHz, volts in mV.
-   This is stored as "index" in the structure. */
+   This is stored as "driver_data" in the structure. */
 #define OP(mhz, mv)                                                    \
        {                                                               \
                .frequency = (mhz) * 1000,                              \
-               .index = (((mhz)/100) << 8) | ((mv - 700) / 16)         \
+               .driver_data = (((mhz)/100) << 8) | ((mv - 700) / 16)           \
        }
 
 /*
@@ -307,7 +307,7 @@ static unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe)
                per_cpu(centrino_model, cpu)->op_points[i].frequency
                                                        != CPUFREQ_TABLE_END;
             i++) {
-               if (msr == per_cpu(centrino_model, cpu)->op_points[i].index)
+               if (msr == per_cpu(centrino_model, cpu)->op_points[i].driver_data)
                        return per_cpu(centrino_model, cpu)->
                                                        op_points[i].frequency;
        }
@@ -501,7 +501,7 @@ static int centrino_target (struct cpufreq_policy *policy,
                        break;
                }
 
-               msr = per_cpu(centrino_model, cpu)->op_points[newstate].index;
+               msr = per_cpu(centrino_model, cpu)->op_points[newstate].driver_data;
 
                if (first_cpu) {
                        rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h);
index c74c0e130ef4b2a16e20a768b05b5946b599a9d6..cd66b85d927caa47d5080f5c8b8da4bd03c51686 100644 (file)
 #include <linux/io.h>
 #include <linux/suspend.h>
 
-/* Frequency table index must be sequential starting at 0 */
 static struct cpufreq_frequency_table freq_table[] = {
-       { 0, 216000 },
-       { 1, 312000 },
-       { 2, 456000 },
-       { 3, 608000 },
-       { 4, 760000 },
-       { 5, 816000 },
-       { 6, 912000 },
-       { 7, 1000000 },
-       { 8, CPUFREQ_TABLE_END },
+       { .frequency = 216000 },
+       { .frequency = 312000 },
+       { .frequency = 456000 },
+       { .frequency = 608000 },
+       { .frequency = 760000 },
+       { .frequency = 816000 },
+       { .frequency = 912000 },
+       { .frequency = 1000000 },
+       { .frequency = CPUFREQ_TABLE_END },
 };
 
 #define NUM_CPUS       2
@@ -138,12 +137,12 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
        if (ret) {
                pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
                        freqs.new);
-               return ret;
+               freqs.new = freqs.old;
        }
 
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
 
-       return 0;
+       return ret;
 }
 
 static unsigned long tegra_cpu_highest_speed(void)
index e21cdfa4002a17bc28f1285dfe3433bb1ba195b5..0e2cd5cab4d0924392d8c4d0a99ffb9a75d4485e 100644 (file)
@@ -1,7 +1,9 @@
 
-config CPU_IDLE
+menuconfig CPU_IDLE
        bool "CPU idle PM support"
        default y if ACPI || PPC_PSERIES
+       select CPU_IDLE_GOV_LADDER if (!NO_HZ && !NO_HZ_IDLE)
+       select CPU_IDLE_GOV_MENU if (NO_HZ || NO_HZ_IDLE)
        help
          CPU idle is a generic framework for supporting software-controlled
          idle processor power management.  It includes modular cross-platform
@@ -9,9 +11,10 @@ config CPU_IDLE
 
          If you're using an ACPI-enabled platform, you should say Y here.
 
+if CPU_IDLE
+
 config CPU_IDLE_MULTIPLE_DRIVERS
         bool "Support multiple cpuidle drivers"
-        depends on CPU_IDLE
         default n
         help
          Allows the cpuidle framework to use different drivers for each CPU.
@@ -19,20 +22,13 @@ config CPU_IDLE_MULTIPLE_DRIVERS
          states. If unsure say N.
 
 config CPU_IDLE_GOV_LADDER
-       bool
-       depends on CPU_IDLE
+       bool "Ladder governor (for periodic timer tick)"
        default y
 
 config CPU_IDLE_GOV_MENU
-       bool
-       depends on CPU_IDLE && NO_HZ
+       bool "Menu governor (for tickless system)"
        default y
 
-config ARCH_NEEDS_CPU_IDLE_COUPLED
-       def_bool n
-
-if CPU_IDLE
-
 config CPU_IDLE_CALXEDA
        bool "CPU Idle Driver for Calxeda processors"
        depends on ARCH_HIGHBANK
@@ -40,4 +36,13 @@ config CPU_IDLE_CALXEDA
        help
          Select this to enable cpuidle on Calxeda processors.
 
+config CPU_IDLE_ZYNQ
+       bool "CPU Idle Driver for Xilinx Zynq processors"
+       depends on ARCH_ZYNQ
+       help
+         Select this to enable cpuidle on Xilinx Zynq processors.
+
 endif
+
+config ARCH_NEEDS_CPU_IDLE_COUPLED
+       def_bool n
index 0d8bd55e776f64d5e3f45c2f5d776366d98b9f86..8767a7b3eb913d9b5eb530f6df208eafe6476aa2 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
 
 obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
 obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
+obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o
diff --git a/drivers/cpuidle/cpuidle-zynq.c b/drivers/cpuidle/cpuidle-zynq.c
new file mode 100644 (file)
index 0000000..38e03a1
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012-2013 Xilinx
+ *
+ * CPU idle support for Xilinx Zynq
+ *
+ * based on arch/arm/mach-at91/cpuidle.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The cpu idle uses wait-for-interrupt and RAM self refresh in order
+ * to implement two idle states -
+ * #1 wait-for-interrupt
+ * #2 wait-for-interrupt and RAM self refresh
+ *
+ * Maintainer: Michal Simek <michal.simek@xilinx.com>
+ */
+
+#include <linux/init.h>
+#include <linux/cpu_pm.h>
+#include <linux/cpuidle.h>
+#include <linux/of.h>
+#include <asm/proc-fns.h>
+#include <asm/cpuidle.h>
+
+#define ZYNQ_MAX_STATES                2
+
+/* Actual code that puts the SoC in different idle states */
+static int zynq_enter_idle(struct cpuidle_device *dev,
+                          struct cpuidle_driver *drv, int index)
+{
+       /* Devices must be stopped here */
+       cpu_pm_enter();
+
+       /* Add code for DDR self refresh start */
+       cpu_do_idle();
+
+       /* Add code for DDR self refresh stop */
+       cpu_pm_exit();
+
+       return index;
+}
+
+static struct cpuidle_driver zynq_idle_driver = {
+       .name = "zynq_idle",
+       .owner = THIS_MODULE,
+       .states = {
+               ARM_CPUIDLE_WFI_STATE,
+               {
+                       .enter                  = zynq_enter_idle,
+                       .exit_latency           = 10,
+                       .target_residency       = 10000,
+                       .flags                  = CPUIDLE_FLAG_TIME_VALID |
+                                                 CPUIDLE_FLAG_TIMER_STOP,
+                       .name                   = "RAM_SR",
+                       .desc                   = "WFI and RAM Self Refresh",
+               },
+       },
+       .safe_state_index = 0,
+       .state_count = ZYNQ_MAX_STATES,
+};
+
+/* Initialize CPU idle by registering the idle states */
+static int __init zynq_cpuidle_init(void)
+{
+       if (!of_machine_is_compatible("xlnx,zynq-7000"))
+               return -ENODEV;
+
+       pr_info("Xilinx Zynq CpuIdle Driver started\n");
+
+       return cpuidle_register(&zynq_idle_driver, NULL);
+}
+
+device_initcall(zynq_cpuidle_init);
index c3a93fece819e71adb5fcae2acd84f885c0f2583..fdc432f18022b331f2102dccf13b539e74fae3ec 100644 (file)
@@ -466,7 +466,7 @@ void cpuidle_unregister(struct cpuidle_driver *drv)
        int cpu;
        struct cpuidle_device *device;
 
-       for_each_possible_cpu(cpu) {
+       for_each_cpu(cpu, drv->cpumask) {
                device = &per_cpu(cpuidle_dev, cpu);
                cpuidle_unregister_device(device);
        }
@@ -498,7 +498,7 @@ int cpuidle_register(struct cpuidle_driver *drv,
                return ret;
        }
 
-       for_each_possible_cpu(cpu) {
+       for_each_cpu(cpu, drv->cpumask) {
                device = &per_cpu(cpuidle_dev, cpu);
                device->cpu = cpu;
 
index 8dfaaae944443b5aa534c7d7a9ed5f1d7a36a4e3..3ac499d5a20784c0432e91f51575022f95c3d3d5 100644 (file)
 
 DEFINE_SPINLOCK(cpuidle_driver_lock);
 
-static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu);
-static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);
+#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
 
-static void cpuidle_setup_broadcast_timer(void *arg)
+static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
+
+/**
+ * __cpuidle_get_cpu_driver - return the cpuidle driver tied to a CPU.
+ * @cpu: the CPU handled by the driver
+ *
+ * Returns a pointer to struct cpuidle_driver or NULL if no driver has been
+ * registered for @cpu.
+ */
+static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
 {
-       int cpu = smp_processor_id();
-       clockevents_notify((long)(arg), &cpu);
+       return per_cpu(cpuidle_drivers, cpu);
 }
 
-static void __cpuidle_driver_init(struct cpuidle_driver *drv, int cpu)
+/**
+ * __cpuidle_unset_driver - unset per CPU driver variables.
+ * @drv: a valid pointer to a struct cpuidle_driver
+ *
+ * For each CPU in the driver's CPU mask, unset the registered driver per CPU
+ * variable. If @drv is different from the registered driver, the corresponding
+ * variable is not cleared.
+ */
+static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)
 {
-       int i;
-
-       drv->refcnt = 0;
+       int cpu;
 
-       for (i = drv->state_count - 1; i >= 0 ; i--) {
+       for_each_cpu(cpu, drv->cpumask) {
 
-               if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP))
+               if (drv != __cpuidle_get_cpu_driver(cpu))
                        continue;
 
-               drv->bctimer = 1;
-               on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer,
-                                (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1);
-               break;
+               per_cpu(cpuidle_drivers, cpu) = NULL;
        }
 }
 
-static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
+/**
+ * __cpuidle_set_driver - set per CPU driver variables the the given driver.
+ * @drv: a valid pointer to a struct cpuidle_driver
+ *
+ * For each CPU in the driver's cpumask, unset the registered driver per CPU
+ * to @drv.
+ *
+ * Returns 0 on success, -EBUSY if the CPUs have driver(s) already.
+ */
+static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
 {
-       if (!drv || !drv->state_count)
-               return -EINVAL;
-
-       if (cpuidle_disabled())
-               return -ENODEV;
+       int cpu;
 
-       if (__cpuidle_get_cpu_driver(cpu))
-               return -EBUSY;
+       for_each_cpu(cpu, drv->cpumask) {
 
-       __cpuidle_driver_init(drv, cpu);
+               if (__cpuidle_get_cpu_driver(cpu)) {
+                       __cpuidle_unset_driver(drv);
+                       return -EBUSY;
+               }
 
-       __cpuidle_set_cpu_driver(drv, cpu);
+               per_cpu(cpuidle_drivers, cpu) = drv;
+       }
 
        return 0;
 }
 
-static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu)
-{
-       if (drv != __cpuidle_get_cpu_driver(cpu))
-               return;
+#else
 
-       if (!WARN_ON(drv->refcnt > 0))
-               __cpuidle_set_cpu_driver(NULL, cpu);
+static struct cpuidle_driver *cpuidle_curr_driver;
 
-       if (drv->bctimer) {
-               drv->bctimer = 0;
-               on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer,
-                                (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1);
-       }
+/**
+ * __cpuidle_get_cpu_driver - return the global cpuidle driver pointer.
+ * @cpu: ignored without the multiple driver support
+ *
+ * Return a pointer to a struct cpuidle_driver object or NULL if no driver was
+ * previously registered.
+ */
+static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
+{
+       return cpuidle_curr_driver;
 }
 
-#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
+/**
+ * __cpuidle_set_driver - assign the global cpuidle driver variable.
+ * @drv: pointer to a struct cpuidle_driver object
+ *
+ * Returns 0 on success, -EBUSY if the driver is already registered.
+ */
+static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
+{
+       if (cpuidle_curr_driver)
+               return -EBUSY;
 
-static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
+       cpuidle_curr_driver = drv;
 
-static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
-{
-       per_cpu(cpuidle_drivers, cpu) = drv;
+       return 0;
 }
 
-static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
+/**
+ * __cpuidle_unset_driver - unset the global cpuidle driver variable.
+ * @drv: a pointer to a struct cpuidle_driver
+ *
+ * Reset the global cpuidle variable to NULL.  If @drv does not match the
+ * registered driver, do nothing.
+ */
+static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)
 {
-       return per_cpu(cpuidle_drivers, cpu);
+       if (drv == cpuidle_curr_driver)
+               cpuidle_curr_driver = NULL;
 }
 
-static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv)
+#endif
+
+/**
+ * cpuidle_setup_broadcast_timer - enable/disable the broadcast timer
+ * @arg: a void pointer used to match the SMP cross call API
+ *
+ * @arg is used as a value of type 'long' with on of the two values:
+ * - CLOCK_EVT_NOTIFY_BROADCAST_ON
+ * - CLOCK_EVT_NOTIFY_BROADCAST_OFF
+ *
+ * Set the broadcast timer notification for the current CPU.  This function
+ * is executed per CPU by an SMP cross call.  It not supposed to be called
+ * directly.
+ */
+static void cpuidle_setup_broadcast_timer(void *arg)
 {
-       int cpu;
-       for_each_present_cpu(cpu)
-               __cpuidle_unregister_driver(drv, cpu);
+       int cpu = smp_processor_id();
+       clockevents_notify((long)(arg), &cpu);
 }
 
-static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv)
+/**
+ * __cpuidle_driver_init - initialize the driver's internal data
+ * @drv: a valid pointer to a struct cpuidle_driver
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int __cpuidle_driver_init(struct cpuidle_driver *drv)
 {
-       int ret = 0;
-       int i, cpu;
+       int i;
 
-       for_each_present_cpu(cpu) {
-               ret = __cpuidle_register_driver(drv, cpu);
-               if (ret)
-                       break;
-       }
+       drv->refcnt = 0;
 
-       if (ret)
-               for_each_present_cpu(i) {
-                       if (i == cpu)
-                               break;
-                       __cpuidle_unregister_driver(drv, i);
-               }
+       /*
+        * Use all possible CPUs as the default, because if the kernel boots
+        * with some CPUs offline and then we online one of them, the CPU
+        * notifier has to know which driver to assign.
+        */
+       if (!drv->cpumask)
+               drv->cpumask = (struct cpumask *)cpu_possible_mask;
+
+       /*
+        * Look for the timer stop flag in the different states, so that we know
+        * if the broadcast timer has to be set up.  The loop is in the reverse
+        * order, because usually on of the the deeper states has this flag set.
+        */
+       for (i = drv->state_count - 1; i >= 0 ; i--) {
 
+               if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP))
+                       continue;
 
-       return ret;
+               drv->bctimer = 1;
+               break;
+       }
+
+       return 0;
 }
 
-int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu)
+/**
+ * __cpuidle_register_driver: register the driver
+ * @drv: a valid pointer to a struct cpuidle_driver
+ *
+ * Do some sanity checks, initialize the driver, assign the driver to the
+ * global cpuidle driver variable(s) and set up the broadcast timer if the
+ * cpuidle driver has some states that shut down the local timer.
+ *
+ * Returns 0 on success, a negative error code otherwise:
+ *  * -EINVAL if the driver pointer is NULL or no idle states are available
+ *  * -ENODEV if the cpuidle framework is disabled
+ *  * -EBUSY if the driver is already assigned to the global variable(s)
+ */
+static int __cpuidle_register_driver(struct cpuidle_driver *drv)
 {
        int ret;
 
-       spin_lock(&cpuidle_driver_lock);
-       ret = __cpuidle_register_driver(drv, cpu);
-       spin_unlock(&cpuidle_driver_lock);
+       if (!drv || !drv->state_count)
+               return -EINVAL;
 
-       return ret;
-}
+       if (cpuidle_disabled())
+               return -ENODEV;
 
-void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu)
-{
-       spin_lock(&cpuidle_driver_lock);
-       __cpuidle_unregister_driver(drv, cpu);
-       spin_unlock(&cpuidle_driver_lock);
-}
+       ret = __cpuidle_driver_init(drv);
+       if (ret)
+               return ret;
 
-/**
- * cpuidle_register_driver - registers a driver
- * @drv: the driver
- */
-int cpuidle_register_driver(struct cpuidle_driver *drv)
-{
-       int ret;
+       ret = __cpuidle_set_driver(drv);
+       if (ret)
+               return ret;
 
-       spin_lock(&cpuidle_driver_lock);
-       ret = __cpuidle_register_all_cpu_driver(drv);
-       spin_unlock(&cpuidle_driver_lock);
+       if (drv->bctimer)
+               on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
+                                (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1);
 
-       return ret;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(cpuidle_register_driver);
 
 /**
- * cpuidle_unregister_driver - unregisters a driver
- * @drv: the driver
+ * __cpuidle_unregister_driver - unregister the driver
+ * @drv: a valid pointer to a struct cpuidle_driver
+ *
+ * Check if the driver is no longer in use, reset the global cpuidle driver
+ * variable(s) and disable the timer broadcast notification mechanism if it was
+ * in use.
+ *
  */
-void cpuidle_unregister_driver(struct cpuidle_driver *drv)
+static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
 {
-       spin_lock(&cpuidle_driver_lock);
-       __cpuidle_unregister_all_cpu_driver(drv);
-       spin_unlock(&cpuidle_driver_lock);
-}
-EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
-
-#else
-
-static struct cpuidle_driver *cpuidle_curr_driver;
+       if (WARN_ON(drv->refcnt > 0))
+               return;
 
-static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
-{
-       cpuidle_curr_driver = drv;
-}
+       if (drv->bctimer) {
+               drv->bctimer = 0;
+               on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
+                                (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1);
+       }
 
-static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
-{
-       return cpuidle_curr_driver;
+       __cpuidle_unset_driver(drv);
 }
 
 /**
  * cpuidle_register_driver - registers a driver
- * @drv: the driver
+ * @drv: a pointer to a valid struct cpuidle_driver
+ *
+ * Register the driver under a lock to prevent concurrent attempts to
+ * [un]register the driver from occuring at the same time.
+ *
+ * Returns 0 on success, a negative error code (returned by
+ * __cpuidle_register_driver()) otherwise.
  */
 int cpuidle_register_driver(struct cpuidle_driver *drv)
 {
-       int ret, cpu;
+       int ret;
 
-       cpu = get_cpu();
        spin_lock(&cpuidle_driver_lock);
-       ret = __cpuidle_register_driver(drv, cpu);
+       ret = __cpuidle_register_driver(drv);
        spin_unlock(&cpuidle_driver_lock);
-       put_cpu();
 
        return ret;
 }
@@ -201,23 +268,24 @@ EXPORT_SYMBOL_GPL(cpuidle_register_driver);
 
 /**
  * cpuidle_unregister_driver - unregisters a driver
- * @drv: the driver
+ * @drv: a pointer to a valid struct cpuidle_driver
+ *
+ * Unregisters the cpuidle driver under a lock to prevent concurrent attempts
+ * to [un]register the driver from occuring at the same time.  @drv has to
+ * match the currently registered driver.
  */
 void cpuidle_unregister_driver(struct cpuidle_driver *drv)
 {
-       int cpu;
-
-       cpu = get_cpu();
        spin_lock(&cpuidle_driver_lock);
-       __cpuidle_unregister_driver(drv, cpu);
+       __cpuidle_unregister_driver(drv);
        spin_unlock(&cpuidle_driver_lock);
-       put_cpu();
 }
 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
-#endif
 
 /**
- * cpuidle_get_driver - return the current driver
+ * cpuidle_get_driver - return the driver tied to the current CPU.
+ *
+ * Returns a struct cpuidle_driver pointer, or NULL if no driver is registered.
  */
 struct cpuidle_driver *cpuidle_get_driver(void)
 {
@@ -233,7 +301,11 @@ struct cpuidle_driver *cpuidle_get_driver(void)
 EXPORT_SYMBOL_GPL(cpuidle_get_driver);
 
 /**
- * cpuidle_get_cpu_driver - return the driver tied with a cpu
+ * cpuidle_get_cpu_driver - return the driver registered for a CPU.
+ * @dev: a valid pointer to a struct cpuidle_device
+ *
+ * Returns a struct cpuidle_driver pointer, or NULL if no driver is registered
+ * for the CPU associated with @dev.
  */
 struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
 {
@@ -244,6 +316,14 @@ struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
 }
 EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
 
+/**
+ * cpuidle_driver_ref - get a reference to the driver.
+ *
+ * Increment the reference counter of the cpuidle driver associated with
+ * the current CPU.
+ *
+ * Returns a pointer to the driver, or NULL if the current CPU has no driver.
+ */
 struct cpuidle_driver *cpuidle_driver_ref(void)
 {
        struct cpuidle_driver *drv;
@@ -257,6 +337,12 @@ struct cpuidle_driver *cpuidle_driver_ref(void)
        return drv;
 }
 
+/**
+ * cpuidle_driver_unref - puts down the refcount for the driver
+ *
+ * Decrement the reference counter of the cpuidle driver associated with
+ * the current CPU.
+ */
 void cpuidle_driver_unref(void)
 {
        struct cpuidle_driver *drv = cpuidle_get_driver();
index 0f079be133051540c62d8c83d03579e132f7d6bd..31f3adba4cf3f15a693e0f3ae40d921e53a576c5 100644 (file)
@@ -67,7 +67,7 @@ comment "DEVFREQ Drivers"
 
 config ARM_EXYNOS4_BUS_DEVFREQ
        bool "ARM Exynos4210/4212/4412 Memory Bus DEVFREQ Driver"
-       depends on CPU_EXYNOS4210 || CPU_EXYNOS4212 || CPU_EXYNOS4412
+       depends on CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412
        select ARCH_HAS_OPP
        select DEVFREQ_GOV_SIMPLE_ONDEMAND
        help
@@ -78,4 +78,14 @@ config ARM_EXYNOS4_BUS_DEVFREQ
          To operate with optimal voltages, ASV support is required
          (CONFIG_EXYNOS_ASV).
 
+config ARM_EXYNOS5_BUS_DEVFREQ
+       bool "ARM Exynos5250 Bus DEVFREQ Driver"
+       depends on SOC_EXYNOS5250
+       select ARCH_HAS_OPP
+       select DEVFREQ_GOV_SIMPLE_ONDEMAND
+       help
+         This adds the DEVFREQ driver for Exynos5250 bus interface (vdd_int).
+         It reads PPMU counters of memory controllers and adjusts the
+         operating frequencies and voltages with OPP support.
+
 endif # PM_DEVFREQ
index 8c464234f7e729155c291d9ad7f15b1883655623..16138c9e0d587595f24d9d61535714e1b788d5cd 100644 (file)
@@ -5,4 +5,5 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)     += governor_powersave.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)    += governor_userspace.o
 
 # DEVFREQ Drivers
-obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)  += exynos4_bus.o
+obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)  += exynos/
+obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)  += exynos/
index 3b367973a8028c5d1cd32bd823bcf9e005d269b6..e94e619fe050103f4508ab6613c223eee122289c 100644 (file)
@@ -271,6 +271,7 @@ void devfreq_monitor_suspend(struct devfreq *devfreq)
                return;
        }
 
+       devfreq_update_status(devfreq, devfreq->previous_freq);
        devfreq->stop_polling = true;
        mutex_unlock(&devfreq->lock);
        cancel_delayed_work_sync(&devfreq->work);
@@ -287,6 +288,8 @@ EXPORT_SYMBOL(devfreq_monitor_suspend);
  */
 void devfreq_monitor_resume(struct devfreq *devfreq)
 {
+       unsigned long freq;
+
        mutex_lock(&devfreq->lock);
        if (!devfreq->stop_polling)
                goto out;
@@ -295,8 +298,14 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
                        devfreq->profile->polling_ms)
                queue_delayed_work(devfreq_wq, &devfreq->work,
                        msecs_to_jiffies(devfreq->profile->polling_ms));
+
+       devfreq->last_stat_updated = jiffies;
        devfreq->stop_polling = false;
 
+       if (devfreq->profile->get_cur_freq &&
+               !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
+               devfreq->previous_freq = freq;
+
 out:
        mutex_unlock(&devfreq->lock);
 }
@@ -477,7 +486,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
                                                GFP_KERNEL);
        devfreq->last_stat_updated = jiffies;
 
-       dev_set_name(&devfreq->dev, dev_name(dev));
+       dev_set_name(&devfreq->dev, "%s", dev_name(dev));
        err = device_register(&devfreq->dev);
        if (err) {
                put_device(&devfreq->dev);
@@ -518,6 +527,8 @@ EXPORT_SYMBOL(devfreq_add_device);
 /**
  * devfreq_remove_device() - Remove devfreq feature from a device.
  * @devfreq:   the devfreq instance to be removed
+ *
+ * The opposite of devfreq_add_device().
  */
 int devfreq_remove_device(struct devfreq *devfreq)
 {
@@ -533,6 +544,10 @@ EXPORT_SYMBOL(devfreq_remove_device);
 /**
  * devfreq_suspend_device() - Suspend devfreq of a device.
  * @devfreq: the devfreq instance to be suspended
+ *
+ * This function is intended to be called by the pm callbacks
+ * (e.g., runtime_suspend, suspend) of the device driver that
+ * holds the devfreq.
  */
 int devfreq_suspend_device(struct devfreq *devfreq)
 {
@@ -550,6 +565,10 @@ EXPORT_SYMBOL(devfreq_suspend_device);
 /**
  * devfreq_resume_device() - Resume devfreq of a device.
  * @devfreq: the devfreq instance to be resumed
+ *
+ * This function is intended to be called by the pm callbacks
+ * (e.g., runtime_resume, resume) of the device driver that
+ * holds the devfreq.
  */
 int devfreq_resume_device(struct devfreq *devfreq)
 {
@@ -905,11 +924,11 @@ static ssize_t show_trans_table(struct device *dev, struct device_attribute *att
 {
        struct devfreq *devfreq = to_devfreq(dev);
        ssize_t len;
-       int i, j, err;
+       int i, j;
        unsigned int max_state = devfreq->profile->max_state;
 
-       err = devfreq_update_status(devfreq, devfreq->previous_freq);
-       if (err)
+       if (!devfreq->stop_polling &&
+                       devfreq_update_status(devfreq, devfreq->previous_freq))
                return 0;
 
        len = sprintf(buf, "   From  :   To\n");
diff --git a/drivers/devfreq/exynos/Makefile b/drivers/devfreq/exynos/Makefile
new file mode 100644 (file)
index 0000000..bfaaf5b
--- /dev/null
@@ -0,0 +1,3 @@
+# Exynos DEVFREQ Drivers
+obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)  += exynos4_bus.o
+obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)  += exynos_ppmu.o exynos5_bus.o
similarity index 99%
rename from drivers/devfreq/exynos4_bus.c
rename to drivers/devfreq/exynos/exynos4_bus.c
index 3f37f3b3f2689bd76438d6ac5e079ce26b433642..c5f86d8caca34c6a7a3ea2341da5c242ddf41c83 100644 (file)
@@ -974,6 +974,7 @@ static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this,
                        rcu_read_unlock();
                        dev_err(data->dev, "%s: unable to find a min freq\n",
                                __func__);
+                       mutex_unlock(&data->lock);
                        return PTR_ERR(opp);
                }
                new_oppinfo.rate = opp_get_freq(opp);
diff --git a/drivers/devfreq/exynos/exynos5_bus.c b/drivers/devfreq/exynos/exynos5_bus.c
new file mode 100644 (file)
index 0000000..574b16b
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * EXYNOS5 INT clock frequency scaling support using DEVFREQ framework
+ * Based on work done by Jonghwan Choi <jhbird.choi@samsung.com>
+ * Support for only EXYNOS5250 is present.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/devfreq.h>
+#include <linux/io.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/opp.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+#include "exynos_ppmu.h"
+
+#define MAX_SAFEVOLT                   1100000 /* 1.10V */
+/* Assume that the bus is saturated if the utilization is 25% */
+#define INT_BUS_SATURATION_RATIO       25
+
+enum int_level_idx {
+       LV_0,
+       LV_1,
+       LV_2,
+       LV_3,
+       LV_4,
+       _LV_END
+};
+
+enum exynos_ppmu_list {
+       PPMU_RIGHT,
+       PPMU_END,
+};
+
+struct busfreq_data_int {
+       struct device *dev;
+       struct devfreq *devfreq;
+       struct regulator *vdd_int;
+       struct exynos_ppmu ppmu[PPMU_END];
+       unsigned long curr_freq;
+       bool disabled;
+
+       struct notifier_block pm_notifier;
+       struct mutex lock;
+       struct pm_qos_request int_req;
+       struct clk *int_clk;
+};
+
+struct int_bus_opp_table {
+       unsigned int idx;
+       unsigned long clk;
+       unsigned long volt;
+};
+
+static struct int_bus_opp_table exynos5_int_opp_table[] = {
+       {LV_0, 266000, 1025000},
+       {LV_1, 200000, 1025000},
+       {LV_2, 160000, 1025000},
+       {LV_3, 133000, 1025000},
+       {LV_4, 100000, 1025000},
+       {0, 0, 0},
+};
+
+static void busfreq_mon_reset(struct busfreq_data_int *data)
+{
+       unsigned int i;
+
+       for (i = PPMU_RIGHT; i < PPMU_END; i++) {
+               void __iomem *ppmu_base = data->ppmu[i].hw_base;
+
+               /* Reset the performance and cycle counters */
+               exynos_ppmu_reset(ppmu_base);
+
+               /* Setup count registers to monitor read/write transactions */
+               data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT;
+               exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3,
+                                       data->ppmu[i].event[PPMU_PMNCNT3]);
+
+               exynos_ppmu_start(ppmu_base);
+       }
+}
+
+static void exynos5_read_ppmu(struct busfreq_data_int *data)
+{
+       int i, j;
+
+       for (i = PPMU_RIGHT; i < PPMU_END; i++) {
+               void __iomem *ppmu_base = data->ppmu[i].hw_base;
+
+               exynos_ppmu_stop(ppmu_base);
+
+               /* Update local data from PPMU */
+               data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
+
+               for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
+                       if (data->ppmu[i].event[j] == 0)
+                               data->ppmu[i].count[j] = 0;
+                       else
+                               data->ppmu[i].count[j] =
+                                       exynos_ppmu_read(ppmu_base, j);
+               }
+       }
+
+       busfreq_mon_reset(data);
+}
+
+static int exynos5_int_setvolt(struct busfreq_data_int *data,
+                               unsigned long volt)
+{
+       return regulator_set_voltage(data->vdd_int, volt, MAX_SAFEVOLT);
+}
+
+static int exynos5_busfreq_int_target(struct device *dev, unsigned long *_freq,
+                             u32 flags)
+{
+       int err = 0;
+       struct platform_device *pdev = container_of(dev, struct platform_device,
+                                                   dev);
+       struct busfreq_data_int *data = platform_get_drvdata(pdev);
+       struct opp *opp;
+       unsigned long old_freq, freq;
+       unsigned long volt;
+
+       rcu_read_lock();
+       opp = devfreq_recommended_opp(dev, _freq, flags);
+       if (IS_ERR(opp)) {
+               rcu_read_unlock();
+               dev_err(dev, "%s: Invalid OPP.\n", __func__);
+               return PTR_ERR(opp);
+       }
+
+       freq = opp_get_freq(opp);
+       volt = opp_get_voltage(opp);
+       rcu_read_unlock();
+
+       old_freq = data->curr_freq;
+
+       if (old_freq == freq)
+               return 0;
+
+       dev_dbg(dev, "targetting %lukHz %luuV\n", freq, volt);
+
+       mutex_lock(&data->lock);
+
+       if (data->disabled)
+               goto out;
+
+       if (freq > exynos5_int_opp_table[0].clk)
+               pm_qos_update_request(&data->int_req, freq * 16 / 1000);
+       else
+               pm_qos_update_request(&data->int_req, -1);
+
+       if (old_freq < freq)
+               err = exynos5_int_setvolt(data, volt);
+       if (err)
+               goto out;
+
+       err = clk_set_rate(data->int_clk, freq * 1000);
+
+       if (err)
+               goto out;
+
+       if (old_freq > freq)
+               err = exynos5_int_setvolt(data, volt);
+       if (err)
+               goto out;
+
+       data->curr_freq = freq;
+out:
+       mutex_unlock(&data->lock);
+       return err;
+}
+
+static int exynos5_get_busier_dmc(struct busfreq_data_int *data)
+{
+       int i, j;
+       int busy = 0;
+       unsigned int temp = 0;
+
+       for (i = PPMU_RIGHT; i < PPMU_END; i++) {
+               for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
+                       if (data->ppmu[i].count[j] > temp) {
+                               temp = data->ppmu[i].count[j];
+                               busy = i;
+                       }
+               }
+       }
+
+       return busy;
+}
+
+static int exynos5_int_get_dev_status(struct device *dev,
+                                     struct devfreq_dev_status *stat)
+{
+       struct platform_device *pdev = container_of(dev, struct platform_device,
+                                                   dev);
+       struct busfreq_data_int *data = platform_get_drvdata(pdev);
+       int busier_dmc;
+
+       exynos5_read_ppmu(data);
+       busier_dmc = exynos5_get_busier_dmc(data);
+
+       stat->current_frequency = data->curr_freq;
+
+       /* Number of cycles spent on memory access */
+       stat->busy_time = data->ppmu[busier_dmc].count[PPMU_PMNCNT3];
+       stat->busy_time *= 100 / INT_BUS_SATURATION_RATIO;
+       stat->total_time = data->ppmu[busier_dmc].ccnt;
+
+       return 0;
+}
+static void exynos5_int_exit(struct device *dev)
+{
+       struct platform_device *pdev = container_of(dev, struct platform_device,
+                                                   dev);
+       struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+       devfreq_unregister_opp_notifier(dev, data->devfreq);
+}
+
+static struct devfreq_dev_profile exynos5_devfreq_int_profile = {
+       .initial_freq           = 160000,
+       .polling_ms             = 100,
+       .target                 = exynos5_busfreq_int_target,
+       .get_dev_status         = exynos5_int_get_dev_status,
+       .exit                   = exynos5_int_exit,
+};
+
+static int exynos5250_init_int_tables(struct busfreq_data_int *data)
+{
+       int i, err = 0;
+
+       for (i = LV_0; i < _LV_END; i++) {
+               err = opp_add(data->dev, exynos5_int_opp_table[i].clk,
+                               exynos5_int_opp_table[i].volt);
+               if (err) {
+                       dev_err(data->dev, "Cannot add opp entries.\n");
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static int exynos5_busfreq_int_pm_notifier_event(struct notifier_block *this,
+               unsigned long event, void *ptr)
+{
+       struct busfreq_data_int *data = container_of(this,
+                                       struct busfreq_data_int, pm_notifier);
+       struct opp *opp;
+       unsigned long maxfreq = ULONG_MAX;
+       unsigned long freq;
+       unsigned long volt;
+       int err = 0;
+
+       switch (event) {
+       case PM_SUSPEND_PREPARE:
+               /* Set Fastest and Deactivate DVFS */
+               mutex_lock(&data->lock);
+
+               data->disabled = true;
+
+               rcu_read_lock();
+               opp = opp_find_freq_floor(data->dev, &maxfreq);
+               if (IS_ERR(opp)) {
+                       rcu_read_unlock();
+                       err = PTR_ERR(opp);
+                       goto unlock;
+               }
+               freq = opp_get_freq(opp);
+               volt = opp_get_voltage(opp);
+               rcu_read_unlock();
+
+               err = exynos5_int_setvolt(data, volt);
+               if (err)
+                       goto unlock;
+
+               err = clk_set_rate(data->int_clk, freq * 1000);
+
+               if (err)
+                       goto unlock;
+
+               data->curr_freq = freq;
+unlock:
+               mutex_unlock(&data->lock);
+               if (err)
+                       return NOTIFY_BAD;
+               return NOTIFY_OK;
+       case PM_POST_RESTORE:
+       case PM_POST_SUSPEND:
+               /* Reactivate */
+               mutex_lock(&data->lock);
+               data->disabled = false;
+               mutex_unlock(&data->lock);
+               return NOTIFY_OK;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static int exynos5_busfreq_int_probe(struct platform_device *pdev)
+{
+       struct busfreq_data_int *data;
+       struct opp *opp;
+       struct device *dev = &pdev->dev;
+       struct device_node *np;
+       unsigned long initial_freq;
+       unsigned long initial_volt;
+       int err = 0;
+       int i;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data_int),
+                               GFP_KERNEL);
+       if (data == NULL) {
+               dev_err(dev, "Cannot allocate memory.\n");
+               return -ENOMEM;
+       }
+
+       np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-ppmu");
+       if (np == NULL) {
+               pr_err("Unable to find PPMU node\n");
+               return -ENOENT;
+       }
+
+       for (i = PPMU_RIGHT; i < PPMU_END; i++) {
+               /* map PPMU memory region */
+               data->ppmu[i].hw_base = of_iomap(np, i);
+               if (data->ppmu[i].hw_base == NULL) {
+                       dev_err(&pdev->dev, "failed to map memory region\n");
+                       return -ENOMEM;
+               }
+       }
+       data->pm_notifier.notifier_call = exynos5_busfreq_int_pm_notifier_event;
+       data->dev = dev;
+       mutex_init(&data->lock);
+
+       err = exynos5250_init_int_tables(data);
+       if (err)
+               goto err_regulator;
+
+       data->vdd_int = regulator_get(dev, "vdd_int");
+       if (IS_ERR(data->vdd_int)) {
+               dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
+               err = PTR_ERR(data->vdd_int);
+               goto err_regulator;
+       }
+
+       data->int_clk = clk_get(dev, "int_clk");
+       if (IS_ERR(data->int_clk)) {
+               dev_err(dev, "Cannot get clock \"int_clk\"\n");
+               err = PTR_ERR(data->int_clk);
+               goto err_clock;
+       }
+
+       rcu_read_lock();
+       opp = opp_find_freq_floor(dev,
+                       &exynos5_devfreq_int_profile.initial_freq);
+       if (IS_ERR(opp)) {
+               rcu_read_unlock();
+               dev_err(dev, "Invalid initial frequency %lu kHz.\n",
+                      exynos5_devfreq_int_profile.initial_freq);
+               err = PTR_ERR(opp);
+               goto err_opp_add;
+       }
+       initial_freq = opp_get_freq(opp);
+       initial_volt = opp_get_voltage(opp);
+       rcu_read_unlock();
+       data->curr_freq = initial_freq;
+
+       err = clk_set_rate(data->int_clk, initial_freq * 1000);
+       if (err) {
+               dev_err(dev, "Failed to set initial frequency\n");
+               goto err_opp_add;
+       }
+
+       err = exynos5_int_setvolt(data, initial_volt);
+       if (err)
+               goto err_opp_add;
+
+       platform_set_drvdata(pdev, data);
+
+       busfreq_mon_reset(data);
+
+       data->devfreq = devfreq_add_device(dev, &exynos5_devfreq_int_profile,
+                                          "simple_ondemand", NULL);
+
+       if (IS_ERR(data->devfreq)) {
+               err = PTR_ERR(data->devfreq);
+               goto err_devfreq_add;
+       }
+
+       devfreq_register_opp_notifier(dev, data->devfreq);
+
+       err = register_pm_notifier(&data->pm_notifier);
+       if (err) {
+               dev_err(dev, "Failed to setup pm notifier\n");
+               goto err_devfreq_add;
+       }
+
+       /* TODO: Add a new QOS class for int/mif bus */
+       pm_qos_add_request(&data->int_req, PM_QOS_NETWORK_THROUGHPUT, -1);
+
+       return 0;
+
+err_devfreq_add:
+       devfreq_remove_device(data->devfreq);
+       platform_set_drvdata(pdev, NULL);
+err_opp_add:
+       clk_put(data->int_clk);
+err_clock:
+       regulator_put(data->vdd_int);
+err_regulator:
+       return err;
+}
+
+static int exynos5_busfreq_int_remove(struct platform_device *pdev)
+{
+       struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+       pm_qos_remove_request(&data->int_req);
+       unregister_pm_notifier(&data->pm_notifier);
+       devfreq_remove_device(data->devfreq);
+       regulator_put(data->vdd_int);
+       clk_put(data->int_clk);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static int exynos5_busfreq_int_resume(struct device *dev)
+{
+       struct platform_device *pdev = container_of(dev, struct platform_device,
+                                                   dev);
+       struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+       busfreq_mon_reset(data);
+       return 0;
+}
+
+static const struct dev_pm_ops exynos5_busfreq_int_pm = {
+       .resume = exynos5_busfreq_int_resume,
+};
+
+/* platform device pointer for exynos5 devfreq device. */
+static struct platform_device *exynos5_devfreq_pdev;
+
+static struct platform_driver exynos5_busfreq_int_driver = {
+       .probe          = exynos5_busfreq_int_probe,
+       .remove         = exynos5_busfreq_int_remove,
+       .driver         = {
+               .name           = "exynos5-bus-int",
+               .owner          = THIS_MODULE,
+               .pm             = &exynos5_busfreq_int_pm,
+       },
+};
+
+static int __init exynos5_busfreq_int_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&exynos5_busfreq_int_driver);
+       if (ret < 0)
+               goto out;
+
+       exynos5_devfreq_pdev =
+               platform_device_register_simple("exynos5-bus-int", -1, NULL, 0);
+       if (IS_ERR_OR_NULL(exynos5_devfreq_pdev)) {
+               ret = PTR_ERR(exynos5_devfreq_pdev);
+               goto out1;
+       }
+
+       return 0;
+out1:
+       platform_driver_unregister(&exynos5_busfreq_int_driver);
+out:
+       return ret;
+}
+late_initcall(exynos5_busfreq_int_init);
+
+static void __exit exynos5_busfreq_int_exit(void)
+{
+       platform_device_unregister(exynos5_devfreq_pdev);
+       platform_driver_unregister(&exynos5_busfreq_int_driver);
+}
+module_exit(exynos5_busfreq_int_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EXYNOS5 busfreq driver with devfreq framework");
diff --git a/drivers/devfreq/exynos/exynos_ppmu.c b/drivers/devfreq/exynos/exynos_ppmu.c
new file mode 100644 (file)
index 0000000..85fc5ac
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * EXYNOS - PPMU support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include "exynos_ppmu.h"
+
+void exynos_ppmu_reset(void __iomem *ppmu_base)
+{
+       __raw_writel(PPMU_CYCLE_RESET | PPMU_COUNTER_RESET, ppmu_base);
+       __raw_writel(PPMU_ENABLE_CYCLE  |
+                    PPMU_ENABLE_COUNT0 |
+                    PPMU_ENABLE_COUNT1 |
+                    PPMU_ENABLE_COUNT2 |
+                    PPMU_ENABLE_COUNT3,
+                    ppmu_base + PPMU_CNTENS);
+}
+
+void exynos_ppmu_setevent(void __iomem *ppmu_base, unsigned int ch,
+                       unsigned int evt)
+{
+       __raw_writel(evt, ppmu_base + PPMU_BEVTSEL(ch));
+}
+
+void exynos_ppmu_start(void __iomem *ppmu_base)
+{
+       __raw_writel(PPMU_ENABLE, ppmu_base);
+}
+
+void exynos_ppmu_stop(void __iomem *ppmu_base)
+{
+       __raw_writel(PPMU_DISABLE, ppmu_base);
+}
+
+unsigned int exynos_ppmu_read(void __iomem *ppmu_base, unsigned int ch)
+{
+       unsigned int total;
+
+       if (ch == PPMU_PMNCNT3)
+               total = ((__raw_readl(ppmu_base + PMCNT_OFFSET(ch)) << 8) |
+                         __raw_readl(ppmu_base + PMCNT_OFFSET(ch + 1)));
+       else
+               total = __raw_readl(ppmu_base + PMCNT_OFFSET(ch));
+
+       return total;
+}
diff --git a/drivers/devfreq/exynos/exynos_ppmu.h b/drivers/devfreq/exynos/exynos_ppmu.h
new file mode 100644 (file)
index 0000000..7dfb221
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * EXYNOS PPMU header
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __DEVFREQ_EXYNOS_PPMU_H
+#define __DEVFREQ_EXYNOS_PPMU_H __FILE__
+
+#include <linux/ktime.h>
+
+/* For PPMU Control */
+#define PPMU_ENABLE             BIT(0)
+#define PPMU_DISABLE            0x0
+#define PPMU_CYCLE_RESET        BIT(1)
+#define PPMU_COUNTER_RESET      BIT(2)
+
+#define PPMU_ENABLE_COUNT0      BIT(0)
+#define PPMU_ENABLE_COUNT1      BIT(1)
+#define PPMU_ENABLE_COUNT2      BIT(2)
+#define PPMU_ENABLE_COUNT3      BIT(3)
+#define PPMU_ENABLE_CYCLE       BIT(31)
+
+#define PPMU_CNTENS            0x10
+#define PPMU_FLAG              0x50
+#define PPMU_CCNT_OVERFLOW     BIT(31)
+#define PPMU_CCNT              0x100
+
+#define PPMU_PMCNT0            0x110
+#define PPMU_PMCNT_OFFSET      0x10
+#define PMCNT_OFFSET(x)                (PPMU_PMCNT0 + (PPMU_PMCNT_OFFSET * x))
+
+#define PPMU_BEVT0SEL          0x1000
+#define PPMU_BEVTSEL_OFFSET    0x100
+#define PPMU_BEVTSEL(x)                (PPMU_BEVT0SEL + (ch * PPMU_BEVTSEL_OFFSET))
+
+/* For Event Selection */
+#define RD_DATA_COUNT          0x5
+#define WR_DATA_COUNT          0x6
+#define RDWR_DATA_COUNT                0x7
+
+enum ppmu_counter {
+       PPMU_PMNCNT0,
+       PPMU_PMCCNT1,
+       PPMU_PMNCNT2,
+       PPMU_PMNCNT3,
+       PPMU_PMNCNT_MAX,
+};
+
+struct bus_opp_table {
+       unsigned int idx;
+       unsigned long clk;
+       unsigned long volt;
+};
+
+struct exynos_ppmu {
+       void __iomem *hw_base;
+       unsigned int ccnt;
+       unsigned int event[PPMU_PMNCNT_MAX];
+       unsigned int count[PPMU_PMNCNT_MAX];
+       unsigned long long ns;
+       ktime_t reset_time;
+       bool ccnt_overflow;
+       bool count_overflow[PPMU_PMNCNT_MAX];
+};
+
+void exynos_ppmu_reset(void __iomem *ppmu_base);
+void exynos_ppmu_setevent(void __iomem *ppmu_base, unsigned int ch,
+                       unsigned int evt);
+void exynos_ppmu_start(void __iomem *ppmu_base);
+void exynos_ppmu_stop(void __iomem *ppmu_base);
+unsigned int exynos_ppmu_read(void __iomem *ppmu_base, unsigned int ch);
+#endif /* __DEVFREQ_EXYNOS_PPMU_H */
index 93f7992bee5c1c933e49b7f93ee41c81265698c8..9e56745f87bf164aa3b4728b52a113c9a5b68cc6 100644 (file)
@@ -663,11 +663,6 @@ static bool device_has_all_tx_types(struct dma_device *device)
                return false;
        #endif
 
-       #if defined(CONFIG_ASYNC_MEMSET) || defined(CONFIG_ASYNC_MEMSET_MODULE)
-       if (!dma_has_cap(DMA_MEMSET, device->cap_mask))
-               return false;
-       #endif
-
        #if defined(CONFIG_ASYNC_XOR) || defined(CONFIG_ASYNC_XOR_MODULE)
        if (!dma_has_cap(DMA_XOR, device->cap_mask))
                return false;
@@ -729,8 +724,6 @@ int dma_async_device_register(struct dma_device *device)
                !device->device_prep_dma_pq);
        BUG_ON(dma_has_cap(DMA_PQ_VAL, device->cap_mask) &&
                !device->device_prep_dma_pq_val);
-       BUG_ON(dma_has_cap(DMA_MEMSET, device->cap_mask) &&
-               !device->device_prep_dma_memset);
        BUG_ON(dma_has_cap(DMA_INTERRUPT, device->cap_mask) &&
                !device->device_prep_dma_interrupt);
        BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) &&
index a0de82e21a7c30d00f122071783c9280583990f4..a975ebebea8aaf9b8950497eefdcaf3793d930d2 100644 (file)
@@ -1405,7 +1405,7 @@ static int dma_runtime_idle(struct device *dev)
                        return -EAGAIN;
        }
 
-       return pm_schedule_suspend(dev, 0);
+       return 0;
 }
 
 /******************************************************************************
index 17a2393b3e25048fb495b9049941fe1be8f4cf36..5ff6fc1819dc6a2e90c035956b23e23c56f9bb5d 100644 (file)
@@ -1105,12 +1105,11 @@ static ssize_t cap_show(struct dma_chan *c, char *page)
 {
        struct dma_device *dma = c->device;
 
-       return sprintf(page, "copy%s%s%s%s%s%s\n",
+       return sprintf(page, "copy%s%s%s%s%s\n",
                       dma_has_cap(DMA_PQ, dma->cap_mask) ? " pq" : "",
                       dma_has_cap(DMA_PQ_VAL, dma->cap_mask) ? " pq_val" : "",
                       dma_has_cap(DMA_XOR, dma->cap_mask) ? " xor" : "",
                       dma_has_cap(DMA_XOR_VAL, dma->cap_mask) ? " xor_val" : "",
-                      dma_has_cap(DMA_MEMSET, dma->cap_mask)  ? " fill" : "",
                       dma_has_cap(DMA_INTERRUPT, dma->cap_mask) ? " intr" : "");
 
 }
index 29bf9448035d321305e9c8791265e6c744c5a677..212d584fe4272a37d947cc72b95e836d801b77b1 100644 (file)
@@ -123,7 +123,6 @@ static inline u16 ioat2_xferlen_to_descs(struct ioat2_dma_chan *ioat, size_t len
 struct ioat_ring_ent {
        union {
                struct ioat_dma_descriptor *hw;
-               struct ioat_fill_descriptor *fill;
                struct ioat_xor_descriptor *xor;
                struct ioat_xor_ext_descriptor *xor_ex;
                struct ioat_pq_descriptor *pq;
index ca6ea9b3551b3f0307b1440a55dcd92a64e2f466..b642e035579b0b468a42ea2772ff17c62c6b684b 100644 (file)
@@ -311,14 +311,6 @@ static void ioat3_dma_unmap(struct ioat2_dma_chan *ioat,
                if (!desc->hw->ctl_f.null) /* skip 'interrupt' ops */
                        ioat_dma_unmap(chan, flags, len, desc->hw);
                break;
-       case IOAT_OP_FILL: {
-               struct ioat_fill_descriptor *hw = desc->fill;
-
-               if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP))
-                       ioat_unmap(pdev, hw->dst_addr - offset, len,
-                                  PCI_DMA_FROMDEVICE, flags, 1);
-               break;
-       }
        case IOAT_OP_XOR_VAL:
        case IOAT_OP_XOR: {
                struct ioat_xor_descriptor *xor = desc->xor;
@@ -823,51 +815,6 @@ ioat3_tx_status(struct dma_chan *c, dma_cookie_t cookie,
        return dma_cookie_status(c, cookie, txstate);
 }
 
-static struct dma_async_tx_descriptor *
-ioat3_prep_memset_lock(struct dma_chan *c, dma_addr_t dest, int value,
-                      size_t len, unsigned long flags)
-{
-       struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
-       struct ioat_ring_ent *desc;
-       size_t total_len = len;
-       struct ioat_fill_descriptor *fill;
-       u64 src_data = (0x0101010101010101ULL) * (value & 0xff);
-       int num_descs, idx, i;
-
-       num_descs = ioat2_xferlen_to_descs(ioat, len);
-       if (likely(num_descs) && ioat2_check_space_lock(ioat, num_descs) == 0)
-               idx = ioat->head;
-       else
-               return NULL;
-       i = 0;
-       do {
-               size_t xfer_size = min_t(size_t, len, 1 << ioat->xfercap_log);
-
-               desc = ioat2_get_ring_ent(ioat, idx + i);
-               fill = desc->fill;
-
-               fill->size = xfer_size;
-               fill->src_data = src_data;
-               fill->dst_addr = dest;
-               fill->ctl = 0;
-               fill->ctl_f.op = IOAT_OP_FILL;
-
-               len -= xfer_size;
-               dest += xfer_size;
-               dump_desc_dbg(ioat, desc);
-       } while (++i < num_descs);
-
-       desc->txd.flags = flags;
-       desc->len = total_len;
-       fill->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT);
-       fill->ctl_f.fence = !!(flags & DMA_PREP_FENCE);
-       fill->ctl_f.compl_write = 1;
-       dump_desc_dbg(ioat, desc);
-
-       /* we leave the channel locked to ensure in order submission */
-       return &desc->txd;
-}
-
 static struct dma_async_tx_descriptor *
 __ioat3_prep_xor_lock(struct dma_chan *c, enum sum_check_flags *result,
                      dma_addr_t dest, dma_addr_t *src, unsigned int src_cnt,
@@ -1431,7 +1378,7 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device)
        struct page *xor_srcs[IOAT_NUM_SRC_TEST];
        struct page *xor_val_srcs[IOAT_NUM_SRC_TEST + 1];
        dma_addr_t dma_srcs[IOAT_NUM_SRC_TEST + 1];
-       dma_addr_t dma_addr, dest_dma;
+       dma_addr_t dest_dma;
        struct dma_async_tx_descriptor *tx;
        struct dma_chan *dma_chan;
        dma_cookie_t cookie;
@@ -1598,56 +1545,6 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device)
                goto free_resources;
        }
 
-       /* skip memset if the capability is not present */
-       if (!dma_has_cap(DMA_MEMSET, dma_chan->device->cap_mask))
-               goto free_resources;
-
-       /* test memset */
-       op = IOAT_OP_FILL;
-
-       dma_addr = dma_map_page(dev, dest, 0,
-                       PAGE_SIZE, DMA_FROM_DEVICE);
-       tx = dma->device_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE,
-                                        DMA_PREP_INTERRUPT |
-                                        DMA_COMPL_SKIP_SRC_UNMAP |
-                                        DMA_COMPL_SKIP_DEST_UNMAP);
-       if (!tx) {
-               dev_err(dev, "Self-test memset prep failed\n");
-               err = -ENODEV;
-               goto dma_unmap;
-       }
-
-       async_tx_ack(tx);
-       init_completion(&cmp);
-       tx->callback = ioat3_dma_test_callback;
-       tx->callback_param = &cmp;
-       cookie = tx->tx_submit(tx);
-       if (cookie < 0) {
-               dev_err(dev, "Self-test memset setup failed\n");
-               err = -ENODEV;
-               goto dma_unmap;
-       }
-       dma->device_issue_pending(dma_chan);
-
-       tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
-
-       if (dma->device_tx_status(dma_chan, cookie, NULL) != DMA_SUCCESS) {
-               dev_err(dev, "Self-test memset timed out\n");
-               err = -ENODEV;
-               goto dma_unmap;
-       }
-
-       dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE);
-
-       for (i = 0; i < PAGE_SIZE/sizeof(u32); i++) {
-               u32 *ptr = page_address(dest);
-               if (ptr[i]) {
-                       dev_err(dev, "Self-test memset failed compare\n");
-                       err = -ENODEV;
-                       goto free_resources;
-               }
-       }
-
        /* test for non-zero parity sum */
        op = IOAT_OP_XOR_VAL;
 
@@ -1706,8 +1603,7 @@ dma_unmap:
                for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++)
                        dma_unmap_page(dev, dma_srcs[i], PAGE_SIZE,
                                       DMA_TO_DEVICE);
-       } else if (op == IOAT_OP_FILL)
-               dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE);
+       }
 free_resources:
        dma->device_free_chan_resources(dma_chan);
 out:
@@ -1944,12 +1840,6 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)
                }
        }
 
-       if (is_raid_device && (device->cap & IOAT_CAP_FILL_BLOCK)) {
-               dma_cap_set(DMA_MEMSET, dma->cap_mask);
-               dma->device_prep_dma_memset = ioat3_prep_memset_lock;
-       }
-
-
        dma->device_tx_status = ioat3_tx_status;
        device->cleanup_fn = ioat3_cleanup_event;
        device->timer_fn = ioat3_timer_event;
index 5ee57d402a6ef0361ef9317a3daeb225d95f75f7..62f83e983d8d0de9e496c79bbe9b10d2951c980b 100644 (file)
@@ -100,33 +100,6 @@ struct ioat_dma_descriptor {
        uint64_t        user2;
 };
 
-struct ioat_fill_descriptor {
-       uint32_t        size;
-       union {
-               uint32_t ctl;
-               struct {
-                       unsigned int int_en:1;
-                       unsigned int rsvd:1;
-                       unsigned int dest_snoop_dis:1;
-                       unsigned int compl_write:1;
-                       unsigned int fence:1;
-                       unsigned int rsvd2:2;
-                       unsigned int dest_brk:1;
-                       unsigned int bundle:1;
-                       unsigned int rsvd4:15;
-                       #define IOAT_OP_FILL 0x01
-                       unsigned int op:8;
-               } ctl_f;
-       };
-       uint64_t        src_data;
-       uint64_t        dst_addr;
-       uint64_t        next;
-       uint64_t        rsv1;
-       uint64_t        next_dst_addr;
-       uint64_t        user1;
-       uint64_t        user2;
-};
-
 struct ioat_xor_descriptor {
        uint32_t        size;
        union {
index 7dafb9f3785fdd22f4a942ce36a77913c84da27b..c9cc08c2dbbae27d583d89e053fb98c8ecb595ec 100644 (file)
@@ -632,39 +632,6 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
        return sw_desc ? &sw_desc->async_tx : NULL;
 }
 
-static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_memset(struct dma_chan *chan, dma_addr_t dma_dest,
-                        int value, size_t len, unsigned long flags)
-{
-       struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
-       struct iop_adma_desc_slot *sw_desc, *grp_start;
-       int slot_cnt, slots_per_op;
-
-       if (unlikely(!len))
-               return NULL;
-       BUG_ON(len > IOP_ADMA_MAX_BYTE_COUNT);
-
-       dev_dbg(iop_chan->device->common.dev, "%s len: %u\n",
-               __func__, len);
-
-       spin_lock_bh(&iop_chan->lock);
-       slot_cnt = iop_chan_memset_slot_count(len, &slots_per_op);
-       sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
-       if (sw_desc) {
-               grp_start = sw_desc->group_head;
-               iop_desc_init_memset(grp_start, flags);
-               iop_desc_set_byte_count(grp_start, iop_chan, len);
-               iop_desc_set_block_fill_val(grp_start, value);
-               iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
-               sw_desc->unmap_src_cnt = 1;
-               sw_desc->unmap_len = len;
-               sw_desc->async_tx.flags = flags;
-       }
-       spin_unlock_bh(&iop_chan->lock);
-
-       return sw_desc ? &sw_desc->async_tx : NULL;
-}
-
 static struct dma_async_tx_descriptor *
 iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest,
                      dma_addr_t *dma_src, unsigned int src_cnt, size_t len,
@@ -1176,33 +1143,6 @@ iop_adma_xor_val_self_test(struct iop_adma_device *device)
                goto free_resources;
        }
 
-       /* test memset */
-       dma_addr = dma_map_page(dma_chan->device->dev, dest, 0,
-                       PAGE_SIZE, DMA_FROM_DEVICE);
-       tx = iop_adma_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE,
-                                     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-
-       cookie = iop_adma_tx_submit(tx);
-       iop_adma_issue_pending(dma_chan);
-       msleep(8);
-
-       if (iop_adma_status(dma_chan, cookie, NULL) != DMA_SUCCESS) {
-               dev_err(dma_chan->device->dev,
-                       "Self-test memset timed out, disabling\n");
-               err = -ENODEV;
-               goto free_resources;
-       }
-
-       for (i = 0; i < PAGE_SIZE/sizeof(u32); i++) {
-               u32 *ptr = page_address(dest);
-               if (ptr[i]) {
-                       dev_err(dma_chan->device->dev,
-                               "Self-test memset failed compare, disabling\n");
-                       err = -ENODEV;
-                       goto free_resources;
-               }
-       }
-
        /* test for non-zero parity sum */
        zero_sum_result = 0;
        for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++)
@@ -1487,8 +1427,6 @@ static int iop_adma_probe(struct platform_device *pdev)
        /* set prep routines based on capability */
        if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask))
                dma_dev->device_prep_dma_memcpy = iop_adma_prep_dma_memcpy;
-       if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask))
-               dma_dev->device_prep_dma_memset = iop_adma_prep_dma_memset;
        if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
                dma_dev->max_xor = iop_adma_get_max_xor();
                dma_dev->device_prep_dma_xor = iop_adma_prep_dma_xor;
@@ -1556,8 +1494,7 @@ static int iop_adma_probe(struct platform_device *pdev)
                        goto err_free_iop_chan;
        }
 
-       if (dma_has_cap(DMA_XOR, dma_dev->cap_mask) ||
-           dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)) {
+       if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
                ret = iop_adma_xor_val_self_test(adev);
                dev_dbg(&pdev->dev, "xor self test returned %d\n", ret);
                if (ret)
@@ -1584,7 +1521,6 @@ static int iop_adma_probe(struct platform_device *pdev)
                 dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask) ? "pq_val " : "",
                 dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "xor " : "",
                 dma_has_cap(DMA_XOR_VAL, dma_dev->cap_mask) ? "xor_val " : "",
-                dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)  ? "fill " : "",
                 dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "cpy " : "",
                 dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : "");
 
index d64ae14f2706e52c5c80144ae1ea73b0607b9aad..200f1a3c9a449d2fe297fa6620c148f74c463f18 100644 (file)
@@ -89,11 +89,6 @@ static void mv_desc_clear_next_desc(struct mv_xor_desc_slot *desc)
        hw_desc->phy_next_desc = 0;
 }
 
-static void mv_desc_set_block_fill_val(struct mv_xor_desc_slot *desc, u32 val)
-{
-       desc->value = val;
-}
-
 static void mv_desc_set_dest_addr(struct mv_xor_desc_slot *desc,
                                  dma_addr_t addr)
 {
@@ -128,22 +123,6 @@ static void mv_chan_set_next_descriptor(struct mv_xor_chan *chan,
        __raw_writel(next_desc_addr, XOR_NEXT_DESC(chan));
 }
 
-static void mv_chan_set_dest_pointer(struct mv_xor_chan *chan, u32 desc_addr)
-{
-       __raw_writel(desc_addr, XOR_DEST_POINTER(chan));
-}
-
-static void mv_chan_set_block_size(struct mv_xor_chan *chan, u32 block_size)
-{
-       __raw_writel(block_size, XOR_BLOCK_SIZE(chan));
-}
-
-static void mv_chan_set_value(struct mv_xor_chan *chan, u32 value)
-{
-       __raw_writel(value, XOR_INIT_VALUE_LOW(chan));
-       __raw_writel(value, XOR_INIT_VALUE_HIGH(chan));
-}
-
 static void mv_chan_unmask_interrupts(struct mv_xor_chan *chan)
 {
        u32 val = __raw_readl(XOR_INTR_MASK(chan));
@@ -186,8 +165,6 @@ static int mv_can_chain(struct mv_xor_desc_slot *desc)
 
        if (chain_old_tail->type != desc->type)
                return 0;
-       if (desc->type == DMA_MEMSET)
-               return 0;
 
        return 1;
 }
@@ -205,9 +182,6 @@ static void mv_set_mode(struct mv_xor_chan *chan,
        case DMA_MEMCPY:
                op_mode = XOR_OPERATION_MODE_MEMCPY;
                break;
-       case DMA_MEMSET:
-               op_mode = XOR_OPERATION_MODE_MEMSET;
-               break;
        default:
                dev_err(mv_chan_to_devp(chan),
                        "error: unsupported operation %d\n",
@@ -274,18 +248,9 @@ static void mv_xor_start_new_chain(struct mv_xor_chan *mv_chan,
        if (sw_desc->type != mv_chan->current_type)
                mv_set_mode(mv_chan, sw_desc->type);
 
-       if (sw_desc->type == DMA_MEMSET) {
-               /* for memset requests we need to program the engine, no
-                * descriptors used.
-                */
-               struct mv_xor_desc *hw_desc = sw_desc->hw_desc;
-               mv_chan_set_dest_pointer(mv_chan, hw_desc->phy_dest_addr);
-               mv_chan_set_block_size(mv_chan, sw_desc->unmap_len);
-               mv_chan_set_value(mv_chan, sw_desc->value);
-       } else {
-               /* set the hardware chain */
-               mv_chan_set_next_descriptor(mv_chan, sw_desc->async_tx.phys);
-       }
+       /* set the hardware chain */
+       mv_chan_set_next_descriptor(mv_chan, sw_desc->async_tx.phys);
+
        mv_chan->pending += sw_desc->slot_cnt;
        mv_xor_issue_pending(&mv_chan->dmachan);
 }
@@ -687,43 +652,6 @@ mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
        return sw_desc ? &sw_desc->async_tx : NULL;
 }
 
-static struct dma_async_tx_descriptor *
-mv_xor_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
-                      size_t len, unsigned long flags)
-{
-       struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan);
-       struct mv_xor_desc_slot *sw_desc, *grp_start;
-       int slot_cnt;
-
-       dev_dbg(mv_chan_to_devp(mv_chan),
-               "%s dest: %x len: %u flags: %ld\n",
-               __func__, dest, len, flags);
-       if (unlikely(len < MV_XOR_MIN_BYTE_COUNT))
-               return NULL;
-
-       BUG_ON(len > MV_XOR_MAX_BYTE_COUNT);
-
-       spin_lock_bh(&mv_chan->lock);
-       slot_cnt = mv_chan_memset_slot_count(len);
-       sw_desc = mv_xor_alloc_slots(mv_chan, slot_cnt, 1);
-       if (sw_desc) {
-               sw_desc->type = DMA_MEMSET;
-               sw_desc->async_tx.flags = flags;
-               grp_start = sw_desc->group_head;
-               mv_desc_init(grp_start, flags);
-               mv_desc_set_byte_count(grp_start, len);
-               mv_desc_set_dest_addr(sw_desc->group_head, dest);
-               mv_desc_set_block_fill_val(grp_start, value);
-               sw_desc->unmap_src_cnt = 1;
-               sw_desc->unmap_len = len;
-       }
-       spin_unlock_bh(&mv_chan->lock);
-       dev_dbg(mv_chan_to_devp(mv_chan),
-               "%s sw_desc %p async_tx %p \n",
-               __func__, sw_desc, &sw_desc->async_tx);
-       return sw_desc ? &sw_desc->async_tx : NULL;
-}
-
 static struct dma_async_tx_descriptor *
 mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
                    unsigned int src_cnt, size_t len, unsigned long flags)
@@ -1137,8 +1065,6 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
        /* set prep routines based on capability */
        if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask))
                dma_dev->device_prep_dma_memcpy = mv_xor_prep_dma_memcpy;
-       if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask))
-               dma_dev->device_prep_dma_memset = mv_xor_prep_dma_memset;
        if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
                dma_dev->max_xor = 8;
                dma_dev->device_prep_dma_xor = mv_xor_prep_dma_xor;
@@ -1187,9 +1113,8 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
                        goto err_free_irq;
        }
 
-       dev_info(&pdev->dev, "Marvell XOR: ( %s%s%s%s)\n",
+       dev_info(&pdev->dev, "Marvell XOR: ( %s%s%s)\n",
                 dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "xor " : "",
-                dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)  ? "fill " : "",
                 dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "cpy " : "",
                 dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : "");
 
@@ -1298,8 +1223,6 @@ static int mv_xor_probe(struct platform_device *pdev)
                                dma_cap_set(DMA_MEMCPY, cap_mask);
                        if (of_property_read_bool(np, "dmacap,xor"))
                                dma_cap_set(DMA_XOR, cap_mask);
-                       if (of_property_read_bool(np, "dmacap,memset"))
-                               dma_cap_set(DMA_MEMSET, cap_mask);
                        if (of_property_read_bool(np, "dmacap,interrupt"))
                                dma_cap_set(DMA_INTERRUPT, cap_mask);
 
index c632a4761fcff9836e6fbe9e59f90fa1f9080399..c619359cb7febd1406d06773320f2281928d3274 100644 (file)
@@ -31,7 +31,6 @@
 
 #define XOR_OPERATION_MODE_XOR         0
 #define XOR_OPERATION_MODE_MEMCPY      2
-#define XOR_OPERATION_MODE_MEMSET      4
 
 #define XOR_CURR_DESC(chan)    (chan->mmr_base + 0x210 + (chan->idx * 4))
 #define XOR_NEXT_DESC(chan)    (chan->mmr_base + 0x200 + (chan->idx * 4))
index a17553f7c02809325b06830d6eb1e36a4c95e435..7ec82f0667eb773fc916742e45ad3a5414238b1d 100644 (file)
@@ -2485,10 +2485,10 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
        struct dma_pl330_chan *pch = to_pchan(chan);
        unsigned long flags;
 
-       spin_lock_irqsave(&pch->lock, flags);
-
        tasklet_kill(&pch->task);
 
+       spin_lock_irqsave(&pch->lock, flags);
+
        pl330_release_channel(pch->pl330_chid);
        pch->pl330_chid = NULL;
 
index 5d3d95569a1e76afc6e294a09ccf538846cae9f6..1e220f8dfd8cdccbeec53675534e20624f3da4ee 100644 (file)
@@ -2322,47 +2322,6 @@ static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_memcpy(
        return sw_desc ? &sw_desc->async_tx : NULL;
 }
 
-/**
- * ppc440spe_adma_prep_dma_memset - prepare CDB for a MEMSET operation
- */
-static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_memset(
-               struct dma_chan *chan, dma_addr_t dma_dest, int value,
-               size_t len, unsigned long flags)
-{
-       struct ppc440spe_adma_chan *ppc440spe_chan;
-       struct ppc440spe_adma_desc_slot *sw_desc, *group_start;
-       int slot_cnt, slots_per_op;
-
-       ppc440spe_chan = to_ppc440spe_adma_chan(chan);
-
-       if (unlikely(!len))
-               return NULL;
-
-       BUG_ON(len > PPC440SPE_ADMA_DMA_MAX_BYTE_COUNT);
-
-       spin_lock_bh(&ppc440spe_chan->lock);
-
-       dev_dbg(ppc440spe_chan->device->common.dev,
-               "ppc440spe adma%d: %s cal: %u len: %u int_en %d\n",
-               ppc440spe_chan->device->id, __func__, value, len,
-               flags & DMA_PREP_INTERRUPT ? 1 : 0);
-
-       slot_cnt = slots_per_op = 1;
-       sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt,
-               slots_per_op);
-       if (sw_desc) {
-               group_start = sw_desc->group_head;
-               ppc440spe_desc_init_memset(group_start, value, flags);
-               ppc440spe_adma_set_dest(group_start, dma_dest, 0);
-               ppc440spe_desc_set_byte_count(group_start, ppc440spe_chan, len);
-               sw_desc->unmap_len = len;
-               sw_desc->async_tx.flags = flags;
-       }
-       spin_unlock_bh(&ppc440spe_chan->lock);
-
-       return sw_desc ? &sw_desc->async_tx : NULL;
-}
-
 /**
  * ppc440spe_adma_prep_dma_xor - prepare CDB for a XOR operation
  */
@@ -4125,7 +4084,6 @@ static void ppc440spe_adma_init_capabilities(struct ppc440spe_adma_device *adev)
        case PPC440SPE_DMA1_ID:
                dma_cap_set(DMA_MEMCPY, adev->common.cap_mask);
                dma_cap_set(DMA_INTERRUPT, adev->common.cap_mask);
-               dma_cap_set(DMA_MEMSET, adev->common.cap_mask);
                dma_cap_set(DMA_PQ, adev->common.cap_mask);
                dma_cap_set(DMA_PQ_VAL, adev->common.cap_mask);
                dma_cap_set(DMA_XOR_VAL, adev->common.cap_mask);
@@ -4151,10 +4109,6 @@ static void ppc440spe_adma_init_capabilities(struct ppc440spe_adma_device *adev)
                adev->common.device_prep_dma_memcpy =
                        ppc440spe_adma_prep_dma_memcpy;
        }
-       if (dma_has_cap(DMA_MEMSET, adev->common.cap_mask)) {
-               adev->common.device_prep_dma_memset =
-                       ppc440spe_adma_prep_dma_memset;
-       }
        if (dma_has_cap(DMA_XOR, adev->common.cap_mask)) {
                adev->common.max_xor = XOR_MAX_OPS;
                adev->common.device_prep_dma_xor =
@@ -4217,7 +4171,6 @@ static void ppc440spe_adma_init_capabilities(struct ppc440spe_adma_device *adev)
          dma_has_cap(DMA_XOR, adev->common.cap_mask) ? "xor " : "",
          dma_has_cap(DMA_XOR_VAL, adev->common.cap_mask) ? "xor_val " : "",
          dma_has_cap(DMA_MEMCPY, adev->common.cap_mask) ? "memcpy " : "",
-         dma_has_cap(DMA_MEMSET, adev->common.cap_mask)  ? "memset " : "",
          dma_has_cap(DMA_INTERRUPT, adev->common.cap_mask) ? "intr " : "");
 }
 
index 845f04786c2de4baedf0952d2ec2b5a830e62602..0d66ae68d4681a9bb1ceedfca97fcafbde144d2c 100644 (file)
@@ -24,7 +24,7 @@ static ssize_t amd64_inject_section_store(struct device *dev,
        unsigned long value;
        int ret;
 
-       ret = strict_strtoul(data, 10, &value);
+       ret = kstrtoul(data, 10, &value);
        if (ret < 0)
                return ret;
 
@@ -61,7 +61,7 @@ static ssize_t amd64_inject_word_store(struct device *dev,
        unsigned long value;
        int ret;
 
-       ret = strict_strtoul(data, 10, &value);
+       ret = kstrtoul(data, 10, &value);
        if (ret < 0)
                return ret;
 
@@ -97,7 +97,7 @@ static ssize_t amd64_inject_ecc_vector_store(struct device *dev,
        unsigned long value;
        int ret;
 
-       ret = strict_strtoul(data, 16, &value);
+       ret = kstrtoul(data, 16, &value);
        if (ret < 0)
                return ret;
 
@@ -124,7 +124,7 @@ static ssize_t amd64_inject_read_store(struct device *dev,
        u32 section, word_bits;
        int ret;
 
-       ret = strict_strtoul(data, 10, &value);
+       ret = kstrtoul(data, 10, &value);
        if (ret < 0)
                return ret;
 
@@ -157,7 +157,7 @@ static ssize_t amd64_inject_write_store(struct device *dev,
        unsigned long value;
        int ret;
 
-       ret = strict_strtoul(data, 10, &value);
+       ret = kstrtoul(data, 10, &value);
        if (ret < 0)
                return ret;
 
index 67610a6ebf875765682cb50bec4226b42f956fc3..ef15a7e613bc6b1d1feec75733a86e20cb23efa7 100644 (file)
@@ -678,7 +678,7 @@ static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
        unsigned long bandwidth = 0;
        int new_bw = 0;
 
-       if (strict_strtoul(data, 10, &bandwidth) < 0)
+       if (kstrtoul(data, 10, &bandwidth) < 0)
                return -EINVAL;
 
        new_bw = mci->set_sdram_scrub_rate(mci, bandwidth);
index 0ec3e95a12cd48c37fa100542e2bbe010cb4afad..80a963d64e58c143db789743d664e998c9e1ee66 100644 (file)
@@ -704,7 +704,7 @@ static ssize_t i7core_inject_section_store(struct device *dev,
        if (pvt->inject.enable)
                disable_inject(mci);
 
-       rc = strict_strtoul(data, 10, &value);
+       rc = kstrtoul(data, 10, &value);
        if ((rc < 0) || (value > 3))
                return -EIO;
 
@@ -741,7 +741,7 @@ struct i7core_pvt *pvt = mci->pvt_info;
        if (pvt->inject.enable)
                disable_inject(mci);
 
-       rc = strict_strtoul(data, 10, &value);
+       rc = kstrtoul(data, 10, &value);
        if ((rc < 0) || (value > 7))
                return -EIO;
 
@@ -781,7 +781,7 @@ static ssize_t i7core_inject_eccmask_store(struct device *dev,
        if (pvt->inject.enable)
                disable_inject(mci);
 
-       rc = strict_strtoul(data, 10, &value);
+       rc = kstrtoul(data, 10, &value);
        if (rc < 0)
                return -EIO;
 
@@ -830,7 +830,7 @@ static ssize_t i7core_inject_store_##param(                 \
        if (!strcasecmp(data, "any") || !strcasecmp(data, "any\n"))\
                value = -1;                                     \
        else {                                                  \
-               rc = strict_strtoul(data, 10, &value);          \
+               rc = kstrtoul(data, 10, &value);                \
                if ((rc < 0) || (value >= limit))               \
                        return -EIO;                            \
        }                                                       \
@@ -934,7 +934,7 @@ static ssize_t i7core_inject_enable_store(struct device *dev,
        if (!pvt->pci_ch[pvt->inject.channel][0])
                return 0;
 
-       rc = strict_strtoul(data, 10, &enable);
+       rc = kstrtoul(data, 10, &enable);
        if ((rc < 0))
                return 0;
 
index f3f0c930d550ebb34509eb05dec7faf17c579151..30f7309446a68e8786fa8c26dccc66684880cd43 100644 (file)
@@ -134,7 +134,8 @@ static const char * const mc5_mce_desc[] = {
        "Physical register file AG0 port",
        "Physical register file AG1 port",
        "Flag register file",
-       "DE error occurred"
+       "DE error occurred",
+       "Retire status queue"
 };
 
 static bool f12h_mc0_mce(u16 ec, u8 xec)
@@ -624,7 +625,7 @@ static void decode_mc5_mce(struct mce *m)
 
        if (xec == 0x0 || xec == 0xc)
                pr_cont("%s.\n", mc5_mce_desc[xec]);
-       else if (xec < 0xd)
+       else if (xec <= 0xd)
                pr_cont("%s parity error.\n", mc5_mce_desc[xec]);
        else
                goto wrong_mc5_mce;
index 2ae78f20cc28f3850cc26a9156927c7b4e8b085e..5e46a9fea31bef134bb9f1d4685bec3c2f108250 100644 (file)
@@ -43,7 +43,7 @@ static ssize_t edac_inject_##reg##_store(struct kobject *kobj,                \
        int ret = 0;                                                    \
        unsigned long value;                                            \
                                                                        \
-       ret = strict_strtoul(data, 16, &value);                         \
+       ret = kstrtoul(data, 16, &value);                               \
        if (ret < 0)                                                    \
                printk(KERN_ERR "Error writing MCE " #reg " field.\n"); \
                                                                        \
@@ -83,7 +83,7 @@ static ssize_t edac_inject_bank_store(struct kobject *kobj,
        int ret = 0;
        unsigned long value;
 
-       ret = strict_strtoul(data, 10, &value);
+       ret = kstrtoul(data, 10, &value);
        if (ret < 0) {
                printk(KERN_ERR "Invalid bank value!\n");
                return -EINVAL;
index 8c69803558fe9f70df26fcbba6720a5c1cf3aec4..18ccadef43fdd80f81cff69501db3679c8e6b078 100644 (file)
@@ -602,7 +602,7 @@ int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
        edev->dev->class = extcon_class;
        edev->dev->release = extcon_dev_release;
 
-       dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
+       dev_set_name(edev->dev, "%s", edev->name ? edev->name : dev_name(dev));
 
        if (edev->max_supported) {
                char buf[10];
index b95159b33c398bc3d6adb03b303eed0bde328c9a..eb760a218da4292f7c208ddc145deffb833df7ab 100644 (file)
@@ -551,9 +551,15 @@ static bool dmi_matches(const struct dmi_system_id *dmi)
                int s = dmi->matches[i].slot;
                if (s == DMI_NONE)
                        break;
-               if (dmi_ident[s]
-                   && strstr(dmi_ident[s], dmi->matches[i].substr))
-                       continue;
+               if (dmi_ident[s]) {
+                       if (!dmi->matches[i].exact_match &&
+                           strstr(dmi_ident[s], dmi->matches[i].substr))
+                               continue;
+                       else if (dmi->matches[i].exact_match &&
+                                !strcmp(dmi_ident[s], dmi->matches[i].substr))
+                               continue;
+               }
+
                /* No match */
                return false;
        }
index 202d2c85ba2e79e2db866e78a03dffa240967f25..91864ad200fffbe44cbc7e2c13d09c3e0d174ece 100644 (file)
@@ -79,10 +79,9 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
                           &entry->var.DataSize, entry->var.Data);
        size = entry->var.DataSize;
 
-       *cb_data->buf = kmalloc(size, GFP_KERNEL);
+       *cb_data->buf = kmemdup(entry->var.Data, size, GFP_KERNEL);
        if (*cb_data->buf == NULL)
                return -ENOMEM;
-       memcpy(*cb_data->buf, entry->var.Data, size);
        return size;
 }
 
@@ -236,7 +235,11 @@ static __init int efivars_pstore_init(void)
        efi_pstore_info.bufsize = 1024;
        spin_lock_init(&efi_pstore_info.buf_lock);
 
-       pstore_register(&efi_pstore_info);
+       if (pstore_register(&efi_pstore_info)) {
+               kfree(efi_pstore_info.buf);
+               efi_pstore_info.buf = NULL;
+               efi_pstore_info.bufsize = 0;
+       }
 
        return 0;
 }
index 94624370caad033f455a7dc6f64743e8175cca31..b2450ba14138ba241b691c462865a8dbed157cf0 100644 (file)
@@ -244,7 +244,7 @@ config GPIO_TS5500
 
 config GPIO_XILINX
        bool "Xilinx GPIO support"
-       depends on PPC_OF || MICROBLAZE
+       depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
        help
          Say yes here to support the Xilinx FPGA GPIO device
 
@@ -340,7 +340,7 @@ config GPIO_MAX7300
        depends on I2C
        select GPIO_MAX730X
        help
-         GPIO driver for Maxim MAX7301 I2C-based GPIO expander.
+         GPIO driver for Maxim MAX7300 I2C-based GPIO expander.
 
 config GPIO_MAX732X
        tristate "MAX7319, MAX7320-7327 I2C Port Expanders"
index 1077754f8289e37ca639541e8d9dd5936c858e7c..3e7812f0405e8d91d507384ec1f2d183afc3ce44 100644 (file)
@@ -34,10 +34,10 @@ static int devm_gpio_match(struct device *dev, void *res, void *data)
 }
 
 /**
- *      devm_gpio_request - request a gpio for a managed device
- *      @dev: device to request the gpio for
- *      @gpio: gpio to allocate
- *      @label: the name of the requested gpio
+ *      devm_gpio_request - request a GPIO for a managed device
+ *      @dev: device to request the GPIO for
+ *      @gpio: GPIO to allocate
+ *      @label: the name of the requested GPIO
  *
  *      Except for the extra @dev argument, this function takes the
  *      same arguments and performs the same function as
@@ -101,9 +101,9 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
 EXPORT_SYMBOL(devm_gpio_request_one);
 
 /**
- *      devm_gpio_free - free an interrupt
- *      @dev: device to free gpio for
- *      @gpio: gpio to free
+ *      devm_gpio_free - free a GPIO
+ *      @dev: device to free GPIO for
+ *      @gpio: GPIO to free
  *
  *      Except for the extra @dev argument, this function takes the
  *      same arguments and performs the same function as gpio_free().
index 7d9d7cb35f2861ffeb0ba4f83b575a1cedb00add..8369e71ebe4f73acdf30051ff32b68812685f15f 100644 (file)
@@ -286,7 +286,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev)
        unsigned long flags;
        int err;
 
-       pci_set_power_state(pdev, 0);
+       pci_set_power_state(pdev, PCI_D0);
        err = pci_enable_device(pdev);
        if (err)
                return err;
index 8e08b8647655dd9d3e0ea4cc386ecb4f52d6cedf..84d2478ec294cdb27be0a7f576b79bf335b6b124 100644 (file)
@@ -235,8 +235,8 @@ static irqreturn_t grgpio_irq_handler(int irq, void *dev)
  * This function will be called as a consequence of the call to
  * irq_create_mapping in grgpio_to_irq
  */
-int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
-                  irq_hw_number_t hwirq)
+static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
+                         irq_hw_number_t hwirq)
 {
        struct grgpio_priv *priv = d->host_data;
        struct grgpio_lirq *lirq;
@@ -291,7 +291,7 @@ int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
        return ret;
 }
 
-void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
+static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
 {
        struct grgpio_priv *priv = d->host_data;
        int index;
index e16d932fd444a924793f63cfb6c2be46a76106cc..2729e3d2d5bbe9da7781be8cf8de34be26d19535 100644 (file)
@@ -41,12 +41,14 @@ enum GPIO_REG {
        GPIO_USE_SEL = 0,
        GPIO_IO_SEL,
        GPIO_LVL,
+       GPO_BLINK
 };
 
-static const u8 ichx_regs[3][3] = {
+static const u8 ichx_regs[4][3] = {
        {0x00, 0x30, 0x40},     /* USE_SEL[1-3] offsets */
        {0x04, 0x34, 0x44},     /* IO_SEL[1-3] offsets */
        {0x0c, 0x38, 0x48},     /* LVL[1-3] offsets */
+       {0x18, 0x18, 0x18},     /* BLINK offset */
 };
 
 static const u8 ichx_reglen[3] = {
@@ -148,6 +150,10 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
                                        int val)
 {
+       /* Disable blink hardware which is available for GPIOs from 0 to 31. */
+       if (nr < 32)
+               ichx_write_bit(GPO_BLINK, nr, 0, 0);
+
        /* Set GPIO output value. */
        ichx_write_bit(GPIO_LVL, nr, val, 0);
 
index 62ef10a641c4250b273263c78e51bd2534ed632a..bfa1af1b519fdf74f30080b5e7701ac641bc999e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Moorestown platform Langwell chip GPIO driver
  *
- * Copyright (c) 2008 - 2009,  Intel Corporation.
+ * Copyright (c) 2008, 2009, 2013, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -20,7 +20,6 @@
 /* Supports:
  * Moorestown platform Langwell chip.
  * Medfield platform Penwell chip.
- * Whitney point.
  */
 
 #include <linux/module.h>
@@ -65,7 +64,7 @@ enum GPIO_REG {
 
 struct lnw_gpio {
        struct gpio_chip                chip;
-       void                            *reg_base;
+       void __iomem                    *reg_base;
        spinlock_t                      lock;
        struct pci_dev                  *pdev;
        struct irq_domain               *domain;
@@ -74,15 +73,13 @@ struct lnw_gpio {
 #define to_lnw_priv(chip)      container_of(chip, struct lnw_gpio, chip)
 
 static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
-                       enum GPIO_REG reg_type)
+                             enum GPIO_REG reg_type)
 {
        struct lnw_gpio *lnw = to_lnw_priv(chip);
        unsigned nreg = chip->ngpio / 32;
        u8 reg = offset / 32;
-       void __iomem *ptr;
 
-       ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
-       return ptr;
+       return lnw->reg_base + reg_type * nreg * 4 + reg * 4;
 }
 
 static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
@@ -91,10 +88,8 @@ static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
        struct lnw_gpio *lnw = to_lnw_priv(chip);
        unsigned nreg = chip->ngpio / 32;
        u8 reg = offset / 16;
-       void __iomem *ptr;
 
-       ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
-       return ptr;
+       return lnw->reg_base + reg_type * nreg * 4 + reg * 4;
 }
 
 static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -305,11 +300,7 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = {
 
 static int lnw_gpio_runtime_idle(struct device *dev)
 {
-       int err = pm_schedule_suspend(dev, 500);
-
-       if (!err)
-               return 0;
-
+       pm_schedule_suspend(dev, 500);
        return -EBUSY;
 }
 
@@ -318,56 +309,40 @@ static const struct dev_pm_ops lnw_gpio_pm_ops = {
 };
 
 static int lnw_gpio_probe(struct pci_dev *pdev,
-                       const struct pci_device_id *id)
+                         const struct pci_device_id *id)
 {
-       void *base;
-       resource_size_t start, len;
+       void __iomem *base;
        struct lnw_gpio *lnw;
        u32 gpio_base;
        u32 irq_base;
        int retval;
        int ngpio = id->driver_data;
 
-       retval = pci_enable_device(pdev);
+       retval = pcim_enable_device(pdev);
        if (retval)
                return retval;
 
-       retval = pci_request_regions(pdev, "langwell_gpio");
+       retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev));
        if (retval) {
-               dev_err(&pdev->dev, "error requesting resources\n");
-               goto err_pci_req_region;
-       }
-       /* get the gpio_base from bar1 */
-       start = pci_resource_start(pdev, 1);
-       len = pci_resource_len(pdev, 1);
-       base = ioremap_nocache(start, len);
-       if (!base) {
-               dev_err(&pdev->dev, "error mapping bar1\n");
-               retval = -EFAULT;
-               goto err_ioremap;
+               dev_err(&pdev->dev, "I/O memory mapping error\n");
+               return retval;
        }
-       irq_base = *(u32 *)base;
-       gpio_base = *((u32 *)base + 1);
+
+       base = pcim_iomap_table(pdev)[1];
+
+       irq_base = readl(base);
+       gpio_base = readl(sizeof(u32) + base);
+
        /* release the IO mapping, since we already get the info from bar1 */
-       iounmap(base);
-       /* get the register base from bar0 */
-       start = pci_resource_start(pdev, 0);
-       len = pci_resource_len(pdev, 0);
-       base = devm_ioremap_nocache(&pdev->dev, start, len);
-       if (!base) {
-               dev_err(&pdev->dev, "error mapping bar0\n");
-               retval = -EFAULT;
-               goto err_ioremap;
-       }
+       pcim_iounmap_regions(pdev, 1 << 1);
 
        lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL);
        if (!lnw) {
-               dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n");
-               retval = -ENOMEM;
-               goto err_ioremap;
+               dev_err(&pdev->dev, "can't allocate chip data\n");
+               return -ENOMEM;
        }
 
-       lnw->reg_base = base;
+       lnw->reg_base = pcim_iomap_table(pdev)[0];
        lnw->chip.label = dev_name(&pdev->dev);
        lnw->chip.request = lnw_gpio_request;
        lnw->chip.direction_input = lnw_gpio_direction_input;
@@ -380,18 +355,18 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
        lnw->chip.can_sleep = 0;
        lnw->pdev = pdev;
 
+       spin_lock_init(&lnw->lock);
+
        lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base,
                                            &lnw_gpio_irq_ops, lnw);
-       if (!lnw->domain) {
-               retval = -ENOMEM;
-               goto err_ioremap;
-       }
+       if (!lnw->domain)
+               return -ENOMEM;
 
        pci_set_drvdata(pdev, lnw);
        retval = gpiochip_add(&lnw->chip);
        if (retval) {
-               dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval);
-               goto err_ioremap;
+               dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
+               return retval;
        }
 
        lnw_irq_init_hw(lnw);
@@ -399,18 +374,10 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
        irq_set_handler_data(pdev->irq, lnw);
        irq_set_chained_handler(pdev->irq, lnw_irq_handler);
 
-       spin_lock_init(&lnw->lock);
-
        pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_allow(&pdev->dev);
 
        return 0;
-
-err_ioremap:
-       pci_release_regions(pdev);
-err_pci_req_region:
-       pci_disable_device(pdev);
-       return retval;
 }
 
 static struct pci_driver lnw_gpio_driver = {
@@ -422,88 +389,9 @@ static struct pci_driver lnw_gpio_driver = {
        },
 };
 
-
-static int wp_gpio_probe(struct platform_device *pdev)
-{
-       struct lnw_gpio *lnw;
-       struct gpio_chip *gc;
-       struct resource *rc;
-       int retval = 0;
-
-       rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!rc)
-               return -EINVAL;
-
-       lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL);
-       if (!lnw) {
-               dev_err(&pdev->dev,
-                       "can't allocate whitneypoint_gpio chip data\n");
-               return -ENOMEM;
-       }
-       lnw->reg_base = ioremap_nocache(rc->start, resource_size(rc));
-       if (lnw->reg_base == NULL) {
-               retval = -EINVAL;
-               goto err_kmalloc;
-       }
-       spin_lock_init(&lnw->lock);
-       gc = &lnw->chip;
-       gc->label = dev_name(&pdev->dev);
-       gc->owner = THIS_MODULE;
-       gc->direction_input = lnw_gpio_direction_input;
-       gc->direction_output = lnw_gpio_direction_output;
-       gc->get = lnw_gpio_get;
-       gc->set = lnw_gpio_set;
-       gc->to_irq = NULL;
-       gc->base = 0;
-       gc->ngpio = 64;
-       gc->can_sleep = 0;
-       retval = gpiochip_add(gc);
-       if (retval) {
-               dev_err(&pdev->dev, "whitneypoint gpiochip_add error %d\n",
-                                                               retval);
-               goto err_ioremap;
-       }
-       platform_set_drvdata(pdev, lnw);
-       return 0;
-err_ioremap:
-       iounmap(lnw->reg_base);
-err_kmalloc:
-       kfree(lnw);
-       return retval;
-}
-
-static int wp_gpio_remove(struct platform_device *pdev)
-{
-       struct lnw_gpio *lnw = platform_get_drvdata(pdev);
-       int err;
-       err = gpiochip_remove(&lnw->chip);
-       if (err)
-               dev_err(&pdev->dev, "failed to remove gpio_chip.\n");
-       iounmap(lnw->reg_base);
-       kfree(lnw);
-       platform_set_drvdata(pdev, NULL);
-       return 0;
-}
-
-static struct platform_driver wp_gpio_driver = {
-       .probe          = wp_gpio_probe,
-       .remove         = wp_gpio_remove,
-       .driver         = {
-               .name   = "wp_gpio",
-               .owner  = THIS_MODULE,
-       },
-};
-
 static int __init lnw_gpio_init(void)
 {
-       int ret;
-       ret =  pci_register_driver(&lnw_gpio_driver);
-       if (ret < 0)
-               return ret;
-       ret = platform_driver_register(&wp_gpio_driver);
-       if (ret < 0)
-               pci_unregister_driver(&lnw_gpio_driver);
-       return ret;
+       return pci_register_driver(&lnw_gpio_driver);
 }
 
 device_initcall(lnw_gpio_init);
index 86c17de87692c74baca7da4a67455e1745a0cf1e..761c4705dfbb357b437f263dac54d1a5c8272864 100644 (file)
@@ -447,7 +447,6 @@ static int lp_gpio_remove(struct platform_device *pdev)
        err = gpiochip_remove(&lg->chip);
        if (err)
                dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 0966f2637ad2dc849f12d7224dbf7d6af1c75c13..6da6d7667c6d70f3f57f59e5a13bfb616a5dd4a8 100644 (file)
@@ -465,6 +465,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
                        dev_warn(&pdev->dev,
                                "ml_ioh_gpio: Failed to get IRQ base num\n");
                        chip->irq_base = -1;
+                       ret = irq_base;
                        goto err_irq_alloc_descs;
                }
                chip->irq_base = irq_base;
index fb2cc90d013423ce15fe34c550493cd329ebb26d..e3ceaacde45c111990c534c887a47cda3a5ec61e 100644 (file)
@@ -652,14 +652,14 @@ static int gpio_msm_v1_probe(struct platform_device *pdev)
                return irq2;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base1 = devm_request_and_ioremap(&pdev->dev, res);
-       if (!base1)
-               return -EADDRNOTAVAIL;
+       base1 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base1))
+               return PTR_ERR(base1);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       base2 = devm_request_and_ioremap(&pdev->dev, res);
-       if (!base2)
-               return -EADDRNOTAVAIL;
+       base2 = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base2))
+               return PTR_ERR(base2);
 
        for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
                if (i - FIRST_GPIO_IRQ >=
index 3a4816adc137de912b51fca601c50d65f8baea19..80ad35e2a8cd5ac3af9f39f0cba644c7062fb592 100644 (file)
@@ -457,7 +457,7 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
                if (!(cause & (1 << i)))
                        continue;
 
-               type = irqd_get_trigger_type(irq_get_irq_data(irq));
+               type = irq_get_trigger_type(irq);
                if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
                        /* Swap polarity (race with GPIO line) */
                        u32 polarity;
index 4a430360af5a2d6932c15170a2149e7aee4b1457..dfeb3a3a8f20949098b5dc0e703ffe1ea944f245 100644 (file)
@@ -1482,7 +1482,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 #else
 #define omap_gpio_runtime_suspend NULL
 #define omap_gpio_runtime_resume NULL
-static void omap_gpio_init_context(struct gpio_bank *p) {}
+static inline void omap_gpio_init_context(struct gpio_bank *p) {}
 #endif
 
 static const struct dev_pm_ops gpio_pm_ops = {
index 6ec82f76f0195619d93ac516120cecdff73d40eb..e8198dd686155da6487440a84d5a64e04c213317 100644 (file)
@@ -232,7 +232,14 @@ static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
 
 static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
 {
-       return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & BIT(offset));
+       u32 bit = BIT(offset);
+
+       /* testing on r8a7790 shows that INDT does not show correct pin state
+        * when configured as output, so use OUTDT in case of output pins */
+       if (gpio_rcar_read(gpio_to_priv(chip), INOUTSEL) & bit)
+               return (int)(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit);
+       else
+               return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit);
 }
 
 static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
index 1bf55f67f7a54c1b2a2ae5f2b1a2dcc28dc9cfc0..368c3c00fca5973fd02bcb5661af1546ded23e16 100644 (file)
@@ -187,20 +187,18 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
                                        rdc321x_gpio_dev->reg1_data_base,
                                        &rdc321x_gpio_dev->data_reg[0]);
        if (err)
-               goto out_drvdata;
+               goto out_free;
 
        err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
                                        rdc321x_gpio_dev->reg2_data_base,
                                        &rdc321x_gpio_dev->data_reg[1]);
        if (err)
-               goto out_drvdata;
+               goto out_free;
 
        dev_info(&pdev->dev, "registering %d GPIOs\n",
                                        rdc321x_gpio_dev->chip.ngpio);
        return gpiochip_add(&rdc321x_gpio_dev->chip);
 
-out_drvdata:
-       platform_set_drvdata(pdev, NULL);
 out_free:
        kfree(rdc321x_gpio_dev);
        return err;
@@ -216,7 +214,6 @@ static int rdc321x_gpio_remove(struct platform_device *pdev)
                dev_err(&pdev->dev, "failed to unregister chip\n");
 
        kfree(rdc321x_gpio_dev);
-       platform_set_drvdata(pdev, NULL);
 
        return ret;
 }
index 558542552aae4a51590ff5e789c3db7ccb34ad89..f43ab6aea281d2f20c03608a495a32b4c0ed2d49 100644 (file)
@@ -371,8 +371,12 @@ static int gsta_probe(struct platform_device *dev)
        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 
        chip = devm_kzalloc(&dev->dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
        chip->dev = &dev->dev;
-       chip->reg_base = devm_request_and_ioremap(&dev->dev, res);
+       chip->reg_base = devm_ioremap_resource(&dev->dev, res);
+       if (IS_ERR(chip->reg_base))
+               return PTR_ERR(chip->reg_base);
 
        for (i = 0; i < GSTA_NR_BLOCKS; i++) {
                chip->regs[i] = chip->reg_base + i * 4096;
index 3ce5bc38ac3180b015548271eeeb0b6a3c6c5543..b33bad1bb4df0400f6024c46fef0ccfe072061b8 100644 (file)
@@ -271,8 +271,8 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
-                      irq_hw_number_t hwirq)
+static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
+                             irq_hw_number_t hwirq)
 {
        struct stmpe_gpio *stmpe_gpio = d->host_data;
 
@@ -292,7 +292,7 @@ int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
        return 0;
 }
 
-void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
+static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
 {
 #ifdef CONFIG_ARM
        set_irq_flags(virq, 0);
@@ -431,7 +431,6 @@ static int stmpe_gpio_remove(struct platform_device *pdev)
        if (irq >= 0)
                free_irq(irq, stmpe_gpio);
 
-       platform_set_drvdata(pdev, NULL);
        kfree(stmpe_gpio);
 
        return 0;
index 796b6c42fa7040da364351c64aaa7878b4ad8550..f371732591d2ab894798dd224dab6062094bfec0 100644 (file)
@@ -548,7 +548,8 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
 #endif
        }
 
-       err = request_threaded_irq(irq_summary,
+       err = devm_request_threaded_irq(&chip->client->dev,
+                               irq_summary,
                                NULL,
                                sx150x_irq_thread_fn,
                                IRQF_SHARED | IRQF_TRIGGER_FALLING,
@@ -567,8 +568,6 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip)
        unsigned n;
        unsigned irq;
 
-       free_irq(chip->irq_summary, chip);
-
        for (n = 0; n < chip->dev_cfg->ngpios; ++n) {
                irq = chip->irq_base + n;
                irq_set_chip_and_handler(irq, NULL, NULL);
@@ -591,18 +590,19 @@ static int sx150x_probe(struct i2c_client *client,
        if (!i2c_check_functionality(client->adapter, i2c_funcs))
                return -ENOSYS;
 
-       chip = kzalloc(sizeof(struct sx150x_chip), GFP_KERNEL);
+       chip = devm_kzalloc(&client->dev,
+               sizeof(struct sx150x_chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
 
        sx150x_init_chip(chip, client, id->driver_data, pdata);
        rc = sx150x_init_hw(chip, pdata);
        if (rc < 0)
-               goto probe_fail_pre_gpiochip_add;
+               return rc;
 
        rc = gpiochip_add(&chip->gpio_chip);
-       if (rc < 0)
-               goto probe_fail_pre_gpiochip_add;
+       if (rc)
+               return rc;
 
        if (pdata->irq_summary >= 0) {
                rc = sx150x_install_irq_chip(chip,
@@ -617,8 +617,6 @@ static int sx150x_probe(struct i2c_client *client,
        return 0;
 probe_fail_post_gpiochip_add:
        WARN_ON(gpiochip_remove(&chip->gpio_chip) < 0);
-probe_fail_pre_gpiochip_add:
-       kfree(chip);
        return rc;
 }
 
@@ -635,8 +633,6 @@ static int sx150x_remove(struct i2c_client *client)
        if (chip->irq_summary >= 0)
                sx150x_remove_irq_chip(chip);
 
-       kfree(chip);
-
        return 0;
 }
 
index d34d80dfb083620493afabc1c339fc3e013cc1a3..4a5de273c230d159883c4430f573416bcf0d4ea4 100644 (file)
@@ -407,7 +407,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev)
 
        free_irq(irq, tc3589x_gpio);
 
-       platform_set_drvdata(pdev, NULL);
        kfree(tc3589x_gpio);
 
        return 0;
index 43774058b6930ab37d60263ee2e9e6b0d44bbf06..4c65f8883204b95417c143e61aa5e3d9027ea5c9 100644 (file)
@@ -342,8 +342,6 @@ static int timbgpio_remove(struct platform_device *pdev)
        release_mem_region(iomem->start, resource_size(iomem));
        kfree(tgpio);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 2b7252cb24275d495802b1a45c85b4ad2a84d88e..cddfa22edb410dc3aaaff6ff0c616e812b339966 100644 (file)
@@ -279,7 +279,6 @@ out_release:
                release_region(res_gpi->start, resource_size(res_gpi));
        if (vg->gpo_reserved)
                release_region(res_gpi->start, resource_size(res_gpo));
-       platform_set_drvdata(pdev, NULL);
        kfree(vg);
        return ret;
 }
@@ -301,7 +300,6 @@ static int vx855gpio_remove(struct platform_device *pdev)
                release_region(res->start, resource_size(res));
        }
 
-       platform_set_drvdata(pdev, NULL);
        kfree(vg);
        return 0;
 }
index 9ae7aa8ca48a22657a26be52e791d034569af98b..792a05ad46497126e39c4ed23bc240bf3b63e66b 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Xilinx gpio driver
+ * Xilinx gpio driver for xps/axi_gpio IP.
  *
- * Copyright 2008 Xilinx, Inc.
+ * Copyright 2008 - 2013 Xilinx, 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
@@ -12,6 +12,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/bitops.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/module.h>
 #define XGPIO_DATA_OFFSET   (0x0)      /* Data register  */
 #define XGPIO_TRI_OFFSET    (0x4)      /* I/O direction register  */
 
+#define XGPIO_CHANNEL_OFFSET   0x8
+
+/* Read/Write access to the GPIO registers */
+#ifdef CONFIG_ARCH_ZYNQ
+# define xgpio_readreg(offset)         readl(offset)
+# define xgpio_writereg(offset, val)   writel(val, offset)
+#else
+# define xgpio_readreg(offset)         __raw_readl(offset)
+# define xgpio_writereg(offset, val)   __raw_writel(val, offset)
+#endif
+
+/**
+ * struct xgpio_instance - Stores information about GPIO device
+ * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks
+ * gpio_state: GPIO state shadow register
+ * gpio_dir: GPIO direction shadow register
+ * offset: GPIO channel offset
+ * gpio_lock: Lock used for synchronization
+ */
 struct xgpio_instance {
        struct of_mm_gpio_chip mmchip;
-       u32 gpio_state;         /* GPIO state shadow register */
-       u32 gpio_dir;           /* GPIO direction shadow register */
-       spinlock_t gpio_lock;   /* Lock used for synchronization */
+       u32 gpio_state;
+       u32 gpio_dir;
+       u32 offset;
+       spinlock_t gpio_lock;
 };
 
 /**
@@ -44,8 +65,12 @@ struct xgpio_instance {
 static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
        struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+       struct xgpio_instance *chip =
+           container_of(mm_gc, struct xgpio_instance, mmchip);
 
-       return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
+       void __iomem *regs = mm_gc->regs + chip->offset;
+
+       return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio));
 }
 
 /**
@@ -63,15 +88,18 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
        struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
        struct xgpio_instance *chip =
            container_of(mm_gc, struct xgpio_instance, mmchip);
+       void __iomem *regs = mm_gc->regs;
 
        spin_lock_irqsave(&chip->gpio_lock, flags);
 
        /* Write to GPIO signal and set its direction to output */
        if (val)
-               chip->gpio_state |= 1 << gpio;
+               chip->gpio_state |= BIT(gpio);
        else
-               chip->gpio_state &= ~(1 << gpio);
-       out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+               chip->gpio_state &= ~BIT(gpio);
+
+       xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+                                                        chip->gpio_state);
 
        spin_unlock_irqrestore(&chip->gpio_lock, flags);
 }
@@ -91,12 +119,13 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
        struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
        struct xgpio_instance *chip =
            container_of(mm_gc, struct xgpio_instance, mmchip);
+       void __iomem *regs = mm_gc->regs;
 
        spin_lock_irqsave(&chip->gpio_lock, flags);
 
        /* Set the GPIO bit in shadow register and set direction as input */
-       chip->gpio_dir |= (1 << gpio);
-       out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+       chip->gpio_dir |= BIT(gpio);
+       xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
 
        spin_unlock_irqrestore(&chip->gpio_lock, flags);
 
@@ -119,19 +148,21 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
        struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
        struct xgpio_instance *chip =
            container_of(mm_gc, struct xgpio_instance, mmchip);
+       void __iomem *regs = mm_gc->regs;
 
        spin_lock_irqsave(&chip->gpio_lock, flags);
 
        /* Write state of GPIO signal */
        if (val)
-               chip->gpio_state |= 1 << gpio;
+               chip->gpio_state |= BIT(gpio);
        else
-               chip->gpio_state &= ~(1 << gpio);
-       out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+               chip->gpio_state &= ~BIT(gpio);
+       xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+                      chip->gpio_state);
 
        /* Clear the GPIO bit in shadow register and set direction as output */
-       chip->gpio_dir &= (~(1 << gpio));
-       out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+       chip->gpio_dir &= ~BIT(gpio);
+       xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
 
        spin_unlock_irqrestore(&chip->gpio_lock, flags);
 
@@ -147,8 +178,10 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
        struct xgpio_instance *chip =
            container_of(mm_gc, struct xgpio_instance, mmchip);
 
-       out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
-       out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+       xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET,
+                                                       chip->gpio_state);
+       xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET,
+                                                        chip->gpio_dir);
 }
 
 /**
@@ -170,24 +203,20 @@ static int xgpio_of_probe(struct device_node *np)
                return -ENOMEM;
 
        /* Update GPIO state shadow register with default value */
-       tree_info = of_get_property(np, "xlnx,dout-default", NULL);
-       if (tree_info)
-               chip->gpio_state = be32_to_cpup(tree_info);
+       of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state);
+
+       /* By default, all pins are inputs */
+       chip->gpio_dir = 0xFFFFFFFF;
 
        /* Update GPIO direction shadow register with default value */
-       chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */
-       tree_info = of_get_property(np, "xlnx,tri-default", NULL);
-       if (tree_info)
-               chip->gpio_dir = be32_to_cpup(tree_info);
+       of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir);
+
+       /* By default assume full GPIO controller */
+       chip->mmchip.gc.ngpio = 32;
 
        /* Check device node and parent device node for device width */
-       chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */
-       tree_info = of_get_property(np, "xlnx,gpio-width", NULL);
-       if (!tree_info)
-               tree_info = of_get_property(np->parent,
-                                           "xlnx,gpio-width", NULL);
-       if (tree_info)
-               chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
+       of_property_read_u32(np, "xlnx,gpio-width",
+                             (u32 *)&chip->mmchip.gc.ngpio);
 
        spin_lock_init(&chip->gpio_lock);
 
@@ -206,6 +235,57 @@ static int xgpio_of_probe(struct device_node *np)
                       np->full_name, status);
                return status;
        }
+
+       pr_info("XGpio: %s: registered, base is %d\n", np->full_name,
+                                                       chip->mmchip.gc.base);
+
+       tree_info = of_get_property(np, "xlnx,is-dual", NULL);
+       if (tree_info && be32_to_cpup(tree_info)) {
+               chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+               if (!chip)
+                       return -ENOMEM;
+
+               /* Add dual channel offset */
+               chip->offset = XGPIO_CHANNEL_OFFSET;
+
+               /* Update GPIO state shadow register with default value */
+               of_property_read_u32(np, "xlnx,dout-default-2",
+                                    &chip->gpio_state);
+
+               /* By default, all pins are inputs */
+               chip->gpio_dir = 0xFFFFFFFF;
+
+               /* Update GPIO direction shadow register with default value */
+               of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir);
+
+               /* By default assume full GPIO controller */
+               chip->mmchip.gc.ngpio = 32;
+
+               /* Check device node and parent device node for device width */
+               of_property_read_u32(np, "xlnx,gpio2-width",
+                                    (u32 *)&chip->mmchip.gc.ngpio);
+
+               spin_lock_init(&chip->gpio_lock);
+
+               chip->mmchip.gc.direction_input = xgpio_dir_in;
+               chip->mmchip.gc.direction_output = xgpio_dir_out;
+               chip->mmchip.gc.get = xgpio_get;
+               chip->mmchip.gc.set = xgpio_set;
+
+               chip->mmchip.save_regs = xgpio_save_regs;
+
+               /* Call the OF gpio helper to setup and register the GPIO dev */
+               status = of_mm_gpiochip_add(np, &chip->mmchip);
+               if (status) {
+                       kfree(chip);
+                       pr_err("%s: error in probe function with status %d\n",
+                       np->full_name, status);
+                       return status;
+               }
+               pr_info("XGpio: %s: dual channel registered, base is %d\n",
+                                       np->full_name, chip->mmchip.gc.base);
+       }
+
        return 0;
 }
 
index c2534d62911cfd18434c9b2bb172cad265603e0d..ff0fd655729f9e22d920d4efcb20777b93469df3 100644 (file)
@@ -1214,15 +1214,14 @@ int gpiochip_add(struct gpio_chip *chip)
                }
        }
 
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
 #ifdef CONFIG_PINCTRL
        INIT_LIST_HEAD(&chip->pin_ranges);
 #endif
 
        of_gpiochip_add(chip);
 
-unlock:
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
        if (status)
                goto fail;
 
@@ -1235,6 +1234,9 @@ unlock:
                chip->label ? : "generic");
 
        return 0;
+
+unlock:
+       spin_unlock_irqrestore(&gpio_lock, flags);
 fail:
        /* failures here can mean systems won't boot... */
        pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
index 29412cc89c7aa71999c8da1f52c1ae543d766e53..817f936e2666ba6e3c8397c53dbf33c07a5a371a 100644 (file)
@@ -869,6 +869,22 @@ static const struct dmi_system_id intel_no_lvds[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"),
                },
        },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Intel D510MO",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "D510MO"),
+               },
+       },
+       {
+               .callback = intel_no_lvds_dmi_callback,
+               .ident = "Intel D525MW",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"),
+               },
+       },
 
        { }     /* terminating entry */
 };
index 5a82b6b7584910fbd3e94ef5192dde965473dca5..af85299f212673afd9ce61997aa98b2f286fd2a7 100644 (file)
@@ -372,19 +372,6 @@ static inline void list_splice_tail_init(struct list_head *list,
        for (pos = (head)->next; prefetch(pos->next), pos != (head); \
                pos = pos->next)
 
-/**
- * __list_for_each     -       iterate over a list
- * @pos:       the &struct list_head to use as a loop cursor.
- * @head:      the head for your list.
- *
- * This variant differs from list_for_each() in that it's the
- * simplest possible list iteration code, no prefetching is done.
- * Use this for code that knows the list to be very short (empty
- * or 1 entry) most of the time.
- */
-#define __list_for_each(pos, head) \
-       for (pos = (head)->next; pos != (head); pos = pos->next)
-
 /**
  * list_for_each_prev  -       iterate over a list backwards
  * @pos:       the &struct list_head to use as a loop cursor.
index 833dd1afbf463627b10062ce16474004a887c10e..66d44581e1b1e74a242a8b8cdbf28ac3196325c3 100644 (file)
@@ -75,7 +75,7 @@ static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info)
        cl->device.bus = &hsi_bus_type;
        cl->device.parent = &port->device;
        cl->device.release = hsi_client_release;
-       dev_set_name(&cl->device, info->name);
+       dev_set_name(&cl->device, "%s", info->name);
        cl->device.platform_data = info->platform_data;
        if (info->archdata)
                cl->device.archdata = *info->archdata;
index 0428e8a74b19253c1ab5da323d9026fe3e9a23c7..e989f7fd645b0d78322ba1431acf4c3f01c220b3 100644 (file)
@@ -348,11 +348,16 @@ config SENSORS_DS620
          will be called ds620.
 
 config SENSORS_DS1621
-       tristate "Dallas Semiconductor DS1621 and DS1625"
+       tristate "Dallas Semiconductor DS1621 and compatibles"
        depends on I2C
        help
-         If you say yes here you get support for Dallas Semiconductor
-         DS1621 and DS1625 sensor chips.
+         If you say yes here you get support for Dallas Semiconductor/Maxim
+         Integrated DS1621 sensor chips and compatible models including:
+
+         - Dallas Semiconductor DS1625
+         - Maxim Integrated DS1631
+         - Maxim Integrated DS1721
+         - Maxim Integrated DS1731
 
          This driver can also be built as a module.  If so, the module
          will be called ds1621.
@@ -456,6 +461,16 @@ config SENSORS_G760A
          This driver can also be built as a module.  If so, the module
          will be called g760a.
 
+config SENSORS_G762
+       tristate "GMT G762 and G763"
+       depends on I2C
+       help
+         If you say yes here you get support for Global Mixed-mode
+         Technology Inc G762 and G763 fan speed PWM controller chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called g762.
+
 config SENSORS_GL518SM
        tristate "Genesys Logic GL518SM"
        depends on I2C
index d17d3e64f9f475d7b2661140d14995e6500aea2b..4f0fb5235f42933fc16ec59e1b7371dac0505af4 100644 (file)
@@ -60,6 +60,7 @@ obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
 obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o
 obj-$(CONFIG_SENSORS_FSCHMD)   += fschmd.o
 obj-$(CONFIG_SENSORS_G760A)    += g760a.o
+obj-$(CONFIG_SENSORS_G762)     += g762.o
 obj-$(CONFIG_SENSORS_GL518SM)  += gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)  += gl520sm.o
 obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
index 1d2da31c27c64194169a41ad44e5a18252b67c77..0cac8c0b001af817b1df36d4d6a780cb673dbc19 100644 (file)
@@ -1079,7 +1079,6 @@ static int abituguru3_remove(struct platform_device *pdev)
        int i;
        struct abituguru3_data *data = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        hwmon_device_unregister(data->hwmon_dev);
        for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
                device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
index f920619cd6da5405ca5cd9c64e9f1ad31fb8a526..29dd9f746dfa23efea7206277a60f950a2d6eddf 100644 (file)
@@ -284,15 +284,11 @@ static DEVICE_ATTR(low_power, S_IWUSR | S_IRUGO, show_low_power, set_low_power);
 
 static struct attribute *adm1021_attributes[] = {
        &sensor_dev_attr_temp1_max.dev_attr.attr,
-       &sensor_dev_attr_temp1_min.dev_attr.attr,
        &sensor_dev_attr_temp1_input.dev_attr.attr,
        &sensor_dev_attr_temp2_max.dev_attr.attr,
-       &sensor_dev_attr_temp2_min.dev_attr.attr,
        &sensor_dev_attr_temp2_input.dev_attr.attr,
        &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
        &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
-       &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
        &sensor_dev_attr_temp2_fault.dev_attr.attr,
        &dev_attr_alarms.attr,
        &dev_attr_low_power.attr,
@@ -303,6 +299,18 @@ static const struct attribute_group adm1021_group = {
        .attrs = adm1021_attributes,
 };
 
+static struct attribute *adm1021_min_attributes[] = {
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adm1021_min_group = {
+       .attrs = adm1021_min_attributes,
+};
+
 /* Return 0 if detection is successful, -ENODEV otherwise */
 static int adm1021_detect(struct i2c_client *client,
                          struct i2c_board_info *info)
@@ -425,6 +433,12 @@ static int adm1021_probe(struct i2c_client *client,
        if (err)
                return err;
 
+       if (data->type != lm84) {
+               err = sysfs_create_group(&client->dev.kobj, &adm1021_min_group);
+               if (err)
+                       goto error;
+       }
+
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
                err = PTR_ERR(data->hwmon_dev);
@@ -434,6 +448,7 @@ static int adm1021_probe(struct i2c_client *client,
        return 0;
 
 error:
+       sysfs_remove_group(&client->dev.kobj, &adm1021_min_group);
        sysfs_remove_group(&client->dev.kobj, &adm1021_group);
        return err;
 }
@@ -452,6 +467,7 @@ static int adm1021_remove(struct i2c_client *client)
        struct adm1021_data *data = i2c_get_clientdata(client);
 
        hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &adm1021_min_group);
        sysfs_remove_group(&client->dev.kobj, &adm1021_group);
 
        return 0;
@@ -477,9 +493,11 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
                        data->temp_max[i] = 1000 *
                                (s8) i2c_smbus_read_byte_data(
                                        client, ADM1021_REG_TOS_R(i));
-                       data->temp_min[i] = 1000 *
-                               (s8) i2c_smbus_read_byte_data(
-                                       client, ADM1021_REG_THYST_R(i));
+                       if (data->type != lm84) {
+                               data->temp_min[i] = 1000 *
+                                 (s8) i2c_smbus_read_byte_data(client,
+                                                       ADM1021_REG_THYST_R(i));
+                       }
                }
                data->alarms = i2c_smbus_read_byte_data(client,
                                                ADM1021_REG_STATUS) & 0x7c;
index b83bf4bb95eba3489e861d7f2d51e24e6a42d15f..0f34bca9f5e577c1f1e04d43908bc9a7a91f4bce 100644 (file)
@@ -1285,7 +1285,7 @@ static int adt7470_probe(struct i2c_client *client,
        }
 
        init_completion(&data->auto_update_stop);
-       data->auto_update = kthread_run(adt7470_update_thread, client,
+       data->auto_update = kthread_run(adt7470_update_thread, client, "%s",
                                        dev_name(data->hwmon_dev));
        if (IS_ERR(data->auto_update)) {
                err = PTR_ERR(data->auto_update);
index 658ce3a8717f6af0fa44f8eec4707d91bd44988d..ade35cf3f48880ee2dad3744428624bbd71d76d3 100644 (file)
@@ -578,7 +578,6 @@ static int coretemp_probe(struct platform_device *pdev)
 
 exit_name:
        device_remove_file(&pdev->dev, &pdata->name_attr);
-       platform_set_drvdata(pdev, NULL);
 exit_free:
        kfree(pdata);
        return err;
@@ -595,7 +594,6 @@ static int coretemp_remove(struct platform_device *pdev)
 
        device_remove_file(&pdev->dev, &pdata->name_attr);
        hwmon_device_unregister(pdata->hwmon_dev);
-       platform_set_drvdata(pdev, NULL);
        kfree(pdata);
        return 0;
 }
index 1c568736baffa31d1f6df3ad3904395293970cef..a26ba7a17c2be824797c728bc415cc2e3fd49bdb 100644 (file)
@@ -6,6 +6,19 @@
  * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
  * the help of Jean Delvare <khali@linux-fr.org>
  *
+ * The DS1621 device is a digital temperature/thermometer with 9-bit
+ * resolution, a thermal alarm output (Tout), and user-defined minimum
+ * and maximum temperature thresholds (TH and TL).
+ *
+ * The DS1625, DS1631, DS1721, and DS1731 are pin compatible with the DS1621
+ * and similar in operation, with slight variations as noted in the device
+ * datasheets (please refer to www.maximintegrated.com for specific
+ * device information).
+ *
+ * Since the DS1621 was the first chipset supported by this driver,
+ * most comments will refer to this chipset, but are actually general
+ * and concern all supported chipsets, unless mentioned otherwise.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
-#include "lm75.h"
+#include <linux/kernel.h>
 
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
-                                       0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
+/* Supported devices */
+enum chips { ds1621, ds1625, ds1631, ds1721, ds1731 };
 
 /* Insmod parameters */
 static int polarity = -1;
 module_param(polarity, int, 0);
 MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low");
 
-/* Many DS1621 constants specified below */
-/* Config register used for detection         */
-/*  7    6    5    4    3    2    1    0      */
-/* |Done|THF |TLF |NVB | X  | X  |POL |1SHOT| */
+/*
+ * The Configuration/Status register
+ *
+ * - DS1621:
+ *   7    6    5    4    3    2    1    0
+ * |Done|THF |TLF |NVB | X  | X  |POL |1SHOT|
+ *
+ * - DS1625:
+ *   7    6    5    4    3    2    1    0
+ * |Done|THF |TLF |NVB | 1  | 0  |POL |1SHOT|
+ *
+ * - DS1631, DS1731:
+ *   7    6    5    4    3    2    1    0
+ * |Done|THF |TLF |NVB | R1 | R0 |POL |1SHOT|
+ *
+ * - DS1721:
+ *   7    6    5    4    3    2    1    0
+ * |Done| X  | X  | U  | R1 | R0 |POL |1SHOT|
+ *
+ * Where:
+ * - 'X' is Reserved
+ * - 'U' is Undefined
+ */
 #define DS1621_REG_CONFIG_NVB          0x10
+#define DS1621_REG_CONFIG_RESOL                0x0C
 #define DS1621_REG_CONFIG_POLARITY     0x02
 #define DS1621_REG_CONFIG_1SHOT                0x01
 #define DS1621_REG_CONFIG_DONE         0x80
 
-/* The DS1621 registers */
+#define DS1621_REG_CONFIG_RESOL_SHIFT  2
+
+/* ds1721 conversion rates: {C/LSB, time(ms), resolution bit setting} */
+static const unsigned short ds1721_convrates[] = {
+       94,     /*  9-bits (0.5,  93.75, RES[0..1] = 0 */
+       188,    /* 10-bits (0.25, 187.5, RES[0..1] = 1 */
+       375,    /* 11-bits (0.125,  375, RES[0..1] = 2 */
+       750,    /* 12-bits (0.0625, 750, RES[0..1] = 3 */
+};
+
+#define DS1621_CONVERSION_MAX  750
+#define DS1625_CONVERSION_MAX  500
+
+#define DS1621_TEMP_MAX        125000
+#define DS1621_TEMP_MIN        (-55000)
+
+/* The DS1621 temperature registers */
 static const u8 DS1621_REG_TEMP[3] = {
        0xAA,           /* input, word, RO */
        0xA2,           /* min, word, RW */
@@ -59,6 +107,7 @@ static const u8 DS1621_REG_TEMP[3] = {
 };
 #define DS1621_REG_CONF                        0xAC /* byte, RW */
 #define DS1621_COM_START               0xEE /* no data */
+#define DS1721_COM_START               0x51 /* no data */
 #define DS1621_COM_STOP                        0x22 /* no data */
 
 /* The DS1621 configuration register */
@@ -75,14 +124,37 @@ struct ds1621_data {
        struct mutex update_lock;
        char valid;                     /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
+       enum chips kind;                /* device type */
 
        u16 temp[3];                    /* Register values, word */
        u8 conf;                        /* Register encoding, combined */
+       u8 zbits;                       /* Resolution encoded as number of
+                                        * zero bits */
+       u16 update_interval;            /* Conversion rate in milliseconds */
 };
 
+static inline int DS1621_TEMP_FROM_REG(u16 reg)
+{
+       return DIV_ROUND_CLOSEST(((s16)reg / 16) * 625, 10);
+}
+
+/*
+ * TEMP: 0.001C/bit (-55C to +125C)
+ * REG:
+ *  - 1621, 1625: 0.5C/bit, 7 zero-bits
+ *  - 1631, 1721, 1731: 0.0625C/bit, 4 zero-bits
+ */
+static inline u16 DS1621_TEMP_TO_REG(long temp, u8 zbits)
+{
+       temp = clamp_val(temp, DS1621_TEMP_MIN, DS1621_TEMP_MAX);
+       temp = DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits;
+       return temp;
+}
+
 static void ds1621_init_client(struct i2c_client *client)
 {
-       u8 conf, new_conf;
+       u8 conf, new_conf, sreg, resol;
+       struct ds1621_data *data = i2c_get_clientdata(client);
 
        new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
        /* switch to continuous conversion mode */
@@ -97,8 +169,30 @@ static void ds1621_init_client(struct i2c_client *client)
        if (conf != new_conf)
                i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf);
 
+       switch (data->kind) {
+       case ds1625:
+               data->update_interval = DS1625_CONVERSION_MAX;
+               data->zbits = 7;
+               sreg = DS1621_COM_START;
+               break;
+       case ds1631:
+       case ds1721:
+       case ds1731:
+               resol = (new_conf & DS1621_REG_CONFIG_RESOL) >>
+                        DS1621_REG_CONFIG_RESOL_SHIFT;
+               data->update_interval = ds1721_convrates[resol];
+               data->zbits = 7 - resol;
+               sreg = DS1721_COM_START;
+               break;
+       default:
+               data->update_interval = DS1621_CONVERSION_MAX;
+               data->zbits = 7;
+               sreg = DS1621_COM_START;
+               break;
+       }
+
        /* start conversion */
-       i2c_smbus_write_byte(client, DS1621_COM_START);
+       i2c_smbus_write_byte(client, sreg);
 }
 
 static struct ds1621_data *ds1621_update_client(struct device *dev)
@@ -109,8 +203,8 @@ static struct ds1621_data *ds1621_update_client(struct device *dev)
 
        mutex_lock(&data->update_lock);
 
-       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
-           || !data->valid) {
+       if (time_after(jiffies, data->last_updated + data->update_interval) ||
+           !data->valid) {
                int i;
 
                dev_dbg(&client->dev, "Starting ds1621 update\n");
@@ -146,7 +240,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da,
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
        struct ds1621_data *data = ds1621_update_client(dev);
        return sprintf(buf, "%d\n",
-                      LM75_TEMP_FROM_REG(data->temp[attr->index]));
+                      DS1621_TEMP_FROM_REG(data->temp[attr->index]));
 }
 
 static ssize_t set_temp(struct device *dev, struct device_attribute *da,
@@ -163,7 +257,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
                return err;
 
        mutex_lock(&data->update_lock);
-       data->temp[attr->index] = LM75_TEMP_TO_REG(val);
+       data->temp[attr->index] = DS1621_TEMP_TO_REG(val, data->zbits);
        i2c_smbus_write_word_swapped(client, DS1621_REG_TEMP[attr->index],
                                     data->temp[attr->index]);
        mutex_unlock(&data->update_lock);
@@ -185,7 +279,47 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
        return sprintf(buf, "%d\n", !!(data->conf & attr->index));
 }
 
+static ssize_t show_convrate(struct device *dev, struct device_attribute *da,
+                         char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds1621_data *data = i2c_get_clientdata(client);
+       return scnprintf(buf, PAGE_SIZE, "%hu\n", data->update_interval);
+}
+
+static ssize_t set_convrate(struct device *dev, struct device_attribute *da,
+                           const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds1621_data *data = i2c_get_clientdata(client);
+       unsigned long convrate;
+       s32 err;
+       int resol = 0;
+
+       err = kstrtoul(buf, 10, &convrate);
+       if (err)
+               return err;
+
+       /* Convert rate into resolution bits */
+       while (resol < (ARRAY_SIZE(ds1721_convrates) - 1) &&
+              convrate > ds1721_convrates[resol])
+               resol++;
+
+       mutex_lock(&data->update_lock);
+       data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
+       data->conf &= ~DS1621_REG_CONFIG_RESOL;
+       data->conf |= (resol << DS1621_REG_CONFIG_RESOL_SHIFT);
+       i2c_smbus_write_byte_data(client, DS1621_REG_CONF, data->conf);
+       data->update_interval = ds1721_convrates[resol];
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_convrate,
+                  set_convrate);
+
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
 static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
@@ -201,48 +335,29 @@ static struct attribute *ds1621_attributes[] = {
        &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
        &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
        &dev_attr_alarms.attr,
+       &dev_attr_update_interval.attr,
        NULL
 };
 
-static const struct attribute_group ds1621_group = {
-       .attrs = ds1621_attributes,
-};
-
-
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int ds1621_detect(struct i2c_client *client,
-                        struct i2c_board_info *info)
+static umode_t ds1621_attribute_visible(struct kobject *kobj,
+                                       struct attribute *attr, int index)
 {
-       struct i2c_adapter *adapter = client->adapter;
-       int conf, temp;
-       int i;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
-                                    | I2C_FUNC_SMBUS_WORD_DATA
-                                    | I2C_FUNC_SMBUS_WRITE_BYTE))
-               return -ENODEV;
-
-       /*
-        * Now, we do the remaining detection. It is lousy.
-        *
-        * The NVB bit should be low if no EEPROM write has been requested
-        * during the latest 10ms, which is highly improbable in our case.
-        */
-       conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
-       if (conf < 0 || conf & DS1621_REG_CONFIG_NVB)
-               return -ENODEV;
-       /* The 7 lowest bits of a temperature should always be 0. */
-       for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
-               temp = i2c_smbus_read_word_data(client, DS1621_REG_TEMP[i]);
-               if (temp < 0 || (temp & 0x7f00))
-                       return -ENODEV;
-       }
-
-       strlcpy(info->type, "ds1621", I2C_NAME_SIZE);
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ds1621_data *data = i2c_get_clientdata(client);
 
-       return 0;
+       if (attr == &dev_attr_update_interval.attr)
+               if (data->kind == ds1621 || data->kind == ds1625)
+                       /* shhh, we're hiding update_interval */
+                       return 0;
+       return attr->mode;
 }
 
+static const struct attribute_group ds1621_group = {
+       .attrs = ds1621_attributes,
+       .is_visible = ds1621_attribute_visible
+};
+
 static int ds1621_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -257,6 +372,8 @@ static int ds1621_probe(struct i2c_client *client,
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
 
+       data->kind = id->driver_data;
+
        /* Initialize the DS1621 chip */
        ds1621_init_client(client);
 
@@ -289,8 +406,11 @@ static int ds1621_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ds1621_id[] = {
-       { "ds1621", 0 },
-       { "ds1625", 0 },
+       { "ds1621", ds1621 },
+       { "ds1625", ds1625 },
+       { "ds1631", ds1631 },
+       { "ds1721", ds1721 },
+       { "ds1731", ds1731 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ds1621_id);
@@ -304,8 +424,6 @@ static struct i2c_driver ds1621_driver = {
        .probe          = ds1621_probe,
        .remove         = ds1621_remove,
        .id_table       = ds1621_id,
-       .detect         = ds1621_detect,
-       .address_list   = normal_i2c,
 };
 
 module_i2c_driver(ds1621_driver);
diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c
new file mode 100644 (file)
index 0000000..73adf01
--- /dev/null
@@ -0,0 +1,1149 @@
+/*
+ * g762 - Driver for the Global Mixed-mode Technology Inc. fan speed
+ *        PWM controller chips from G762 family, i.e. G762 and G763
+ *
+ * Copyright (C) 2013, Arnaud EBALARD <arno@natisbad.org>
+ *
+ * This work is based on a basic version for 2.6.31 kernel developed
+ * by Olivier Mouchet for LaCie. Updates and correction have been
+ * performed to run on recent kernels. Additional features, like the
+ * ability to configure various characteristics via .dts file or
+ * board init file have been added. Detailed datasheet on which this
+ * development is based is available here:
+ *
+ *  http://natisbad.org/NAS/refs/GMT_EDS-762_763-080710-0.2.pdf
+ *
+ * Headers from previous developments have been kept below:
+ *
+ * Copyright (c) 2009 LaCie
+ *
+ * Author: Olivier Mouchet <olivier.mouchet@gmail.com>
+ *
+ * based on g760a code written by Herbert Valerio Riedel <hvr@gnu.org>
+ * Copyright (C) 2007  Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * g762: minimal datasheet available at:
+ *       http://www.gmt.com.tw/product/datasheet/EDS-762_3.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/g762.h>
+
+#define DRVNAME "g762"
+
+static const struct i2c_device_id g762_id[] = {
+       { "g762", 0 },
+       { "g763", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, g762_id);
+
+enum g762_regs {
+       G762_REG_SET_CNT  = 0x00,
+       G762_REG_ACT_CNT  = 0x01,
+       G762_REG_FAN_STA  = 0x02,
+       G762_REG_SET_OUT  = 0x03,
+       G762_REG_FAN_CMD1 = 0x04,
+       G762_REG_FAN_CMD2 = 0x05,
+};
+
+/* Config register bits */
+#define G762_REG_FAN_CMD1_DET_FAN_FAIL  0x80 /* enable fan_fail signal */
+#define G762_REG_FAN_CMD1_DET_FAN_OOC   0x40 /* enable fan_out_of_control */
+#define G762_REG_FAN_CMD1_OUT_MODE      0x20 /* out mode: PWM or DC */
+#define G762_REG_FAN_CMD1_FAN_MODE      0x10 /* fan mode: closed/open-loop */
+#define G762_REG_FAN_CMD1_CLK_DIV_ID1   0x08 /* clock divisor value */
+#define G762_REG_FAN_CMD1_CLK_DIV_ID0   0x04
+#define G762_REG_FAN_CMD1_PWM_POLARITY  0x02 /* PWM polarity */
+#define G762_REG_FAN_CMD1_PULSE_PER_REV 0x01 /* pulse per fan revolution */
+
+#define G762_REG_FAN_CMD2_GEAR_MODE_1   0x08 /* fan gear mode */
+#define G762_REG_FAN_CMD2_GEAR_MODE_0   0x04
+#define G762_REG_FAN_CMD2_FAN_STARTV_1  0x02 /* fan startup voltage */
+#define G762_REG_FAN_CMD2_FAN_STARTV_0  0x01
+
+#define G762_REG_FAN_STA_FAIL           0x02 /* fan fail */
+#define G762_REG_FAN_STA_OOC            0x01 /* fan out of control */
+
+/* Config register values */
+#define G762_OUT_MODE_PWM            1
+#define G762_OUT_MODE_DC             0
+
+#define G762_FAN_MODE_CLOSED_LOOP    2
+#define G762_FAN_MODE_OPEN_LOOP      1
+
+#define G762_PWM_POLARITY_NEGATIVE   1
+#define G762_PWM_POLARITY_POSITIVE   0
+
+/* Register data is read (and cached) at most once per second. */
+#define G762_UPDATE_INTERVAL    HZ
+
+/*
+ * Extract pulse count per fan revolution value (2 or 4) from given
+ * FAN_CMD1 register value.
+ */
+#define G762_PULSE_FROM_REG(reg) \
+       ((((reg) & G762_REG_FAN_CMD1_PULSE_PER_REV) + 1) << 1)
+
+/*
+ * Extract fan clock divisor (1, 2, 4 or 8) from given FAN_CMD1
+ * register value.
+ */
+#define G762_CLKDIV_FROM_REG(reg) \
+       (1 << (((reg) & (G762_REG_FAN_CMD1_CLK_DIV_ID0 |        \
+                        G762_REG_FAN_CMD1_CLK_DIV_ID1)) >> 2))
+
+/*
+ * Extract fan gear mode multiplier value (0, 2 or 4) from given
+ * FAN_CMD2 register value.
+ */
+#define G762_GEARMULT_FROM_REG(reg) \
+       (1 << (((reg) & (G762_REG_FAN_CMD2_GEAR_MODE_0 |        \
+                        G762_REG_FAN_CMD2_GEAR_MODE_1)) >> 2))
+
+struct g762_data {
+       struct i2c_client *client;
+       struct device *hwmon_dev;
+       struct clk *clk;
+
+       /* update mutex */
+       struct mutex update_lock;
+
+       /* board specific parameters. */
+       u32 clk_freq;
+
+       /* g762 register cache */
+       bool valid;
+       unsigned long last_updated; /* in jiffies */
+
+       u8 set_cnt;  /* controls fan rotation speed in closed-loop mode */
+       u8 act_cnt;  /* provides access to current fan RPM value */
+       u8 fan_sta;  /* bit 0: set when actual fan speed is more than
+                     *        25% outside requested fan speed
+                     * bit 1: set when no transition occurs on fan
+                     *        pin for 0.7s
+                     */
+       u8 set_out;  /* controls fan rotation speed in open-loop mode */
+       u8 fan_cmd1; /*   0: FG_PLS_ID0 FG pulses count per revolution
+                     *      0: 2 counts per revolution
+                     *      1: 4 counts per revolution
+                     *   1: PWM_POLARITY 1: negative_duty
+                     *                   0: positive_duty
+                     * 2,3: [FG_CLOCK_ID0, FG_CLK_ID1]
+                     *         00: Divide fan clock by 1
+                     *         01: Divide fan clock by 2
+                     *         10: Divide fan clock by 4
+                     *         11: Divide fan clock by 8
+                     *   4: FAN_MODE 1:closed-loop, 0:open-loop
+                     *   5: OUT_MODE 1:PWM, 0:DC
+                     *   6: DET_FAN_OOC enable "fan ooc" status
+                     *   7: DET_FAN_FAIL enable "fan fail" status
+                     */
+       u8 fan_cmd2; /* 0,1: FAN_STARTV 0,1,2,3 -> 0,32,64,96 dac_code
+                     * 2,3: FG_GEAR_MODE
+                     *         00: multiplier = 1
+                     *         01: multiplier = 2
+                     *         10: multiplier = 4
+                     *   4: Mask ALERT# (g763 only)
+                     */
+};
+
+/*
+ * Convert count value from fan controller register (FAN_SET_CNT) into fan
+ * speed RPM value. Note that the datasheet documents a basic formula;
+ * influence of additional parameters (fan clock divisor, fan gear mode)
+ * have been infered from examples in the datasheet and tests.
+ */
+static inline unsigned int rpm_from_cnt(u8 cnt, u32 clk_freq, u16 p,
+                                       u8 clk_div, u8 gear_mult)
+{
+       if (cnt == 0xff)  /* setting cnt to 255 stops the fan */
+               return 0;
+
+       return (clk_freq * 30 * gear_mult) / ((cnt ? cnt : 1) * p * clk_div);
+}
+
+/*
+ * Convert fan RPM value from sysfs into count value for fan controller
+ * register (FAN_SET_CNT).
+ */
+static inline unsigned char cnt_from_rpm(u32 rpm, u32 clk_freq, u16 p,
+                                        u8 clk_div, u8 gear_mult)
+{
+       if (!rpm)         /* to stop the fan, set cnt to 255 */
+               return 0xff;
+
+       return clamp_val(((clk_freq * 30 * gear_mult) / (rpm * p * clk_div)),
+                        0, 255);
+}
+
+/* helper to grab and cache data, at most one time per second */
+static struct g762_data *g762_update_client(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = i2c_get_clientdata(client);
+       int ret = 0;
+
+       mutex_lock(&data->update_lock);
+       if (time_before(jiffies, data->last_updated + G762_UPDATE_INTERVAL) &&
+           likely(data->valid))
+               goto out;
+
+       ret = i2c_smbus_read_byte_data(client, G762_REG_SET_CNT);
+       if (ret < 0)
+               goto out;
+       data->set_cnt = ret;
+
+       ret = i2c_smbus_read_byte_data(client, G762_REG_ACT_CNT);
+       if (ret < 0)
+               goto out;
+       data->act_cnt = ret;
+
+       ret = i2c_smbus_read_byte_data(client, G762_REG_FAN_STA);
+       if (ret < 0)
+               goto out;
+       data->fan_sta = ret;
+
+       ret = i2c_smbus_read_byte_data(client, G762_REG_SET_OUT);
+       if (ret < 0)
+               goto out;
+       data->set_out = ret;
+
+       ret = i2c_smbus_read_byte_data(client, G762_REG_FAN_CMD1);
+       if (ret < 0)
+               goto out;
+       data->fan_cmd1 = ret;
+
+       ret = i2c_smbus_read_byte_data(client, G762_REG_FAN_CMD2);
+       if (ret < 0)
+               goto out;
+       data->fan_cmd2 = ret;
+
+       data->last_updated = jiffies;
+       data->valid = true;
+ out:
+       mutex_unlock(&data->update_lock);
+
+       if (ret < 0) /* upon error, encode it in return value */
+               data = ERR_PTR(ret);
+
+       return data;
+}
+
+/* helpers for writing hardware parameters */
+
+/*
+ * Set input clock frequency received on CLK pin of the chip. Accepted values
+ * are between 0 and 0xffffff. If zero is given, then default frequency
+ * (32,768Hz) is used. Note that clock frequency is a characteristic of the
+ * system but an internal parameter, i.e. value is not passed to the device.
+ */
+static int do_set_clk_freq(struct device *dev, unsigned long val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = i2c_get_clientdata(client);
+
+       if (val > 0xffffff)
+               return -EINVAL;
+       if (!val)
+               val = 32768;
+
+       data->clk_freq = val;
+
+       return 0;
+}
+
+/* Set pwm mode. Accepts either 0 (PWM mode) or 1 (DC mode) */
+static int do_set_pwm_mode(struct device *dev, unsigned long val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = g762_update_client(dev);
+       int ret;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       mutex_lock(&data->update_lock);
+       switch (val) {
+       case G762_OUT_MODE_PWM:
+               data->fan_cmd1 |=  G762_REG_FAN_CMD1_OUT_MODE;
+               break;
+       case G762_OUT_MODE_DC:
+               data->fan_cmd1 &= ~G762_REG_FAN_CMD1_OUT_MODE;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+                                       data->fan_cmd1);
+       data->valid = false;
+ out:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+/* Set fan clock divisor. Accepts either 1, 2, 4 or 8. */
+static int do_set_fan_div(struct device *dev, unsigned long val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = g762_update_client(dev);
+       int ret;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       mutex_lock(&data->update_lock);
+       switch (val) {
+       case 1:
+               data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID0;
+               data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID1;
+               break;
+       case 2:
+               data->fan_cmd1 |=  G762_REG_FAN_CMD1_CLK_DIV_ID0;
+               data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID1;
+               break;
+       case 4:
+               data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID0;
+               data->fan_cmd1 |=  G762_REG_FAN_CMD1_CLK_DIV_ID1;
+               break;
+       case 8:
+               data->fan_cmd1 |=  G762_REG_FAN_CMD1_CLK_DIV_ID0;
+               data->fan_cmd1 |=  G762_REG_FAN_CMD1_CLK_DIV_ID1;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+                                       data->fan_cmd1);
+       data->valid = false;
+ out:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+/* Set fan gear mode. Accepts either 0, 1 or 2. */
+static int do_set_fan_gear_mode(struct device *dev, unsigned long val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = g762_update_client(dev);
+       int ret;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       mutex_lock(&data->update_lock);
+       switch (val) {
+       case 0:
+               data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_0;
+               data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_1;
+               break;
+       case 1:
+               data->fan_cmd2 |=  G762_REG_FAN_CMD2_GEAR_MODE_0;
+               data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_1;
+               break;
+       case 2:
+               data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_0;
+               data->fan_cmd2 |=  G762_REG_FAN_CMD2_GEAR_MODE_1;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD2,
+                                       data->fan_cmd2);
+       data->valid = false;
+ out:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+/* Set number of fan pulses per revolution. Accepts either 2 or 4. */
+static int do_set_fan_pulses(struct device *dev, unsigned long val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = g762_update_client(dev);
+       int ret;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       mutex_lock(&data->update_lock);
+       switch (val) {
+       case 2:
+               data->fan_cmd1 &= ~G762_REG_FAN_CMD1_PULSE_PER_REV;
+               break;
+       case 4:
+               data->fan_cmd1 |=  G762_REG_FAN_CMD1_PULSE_PER_REV;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+                                       data->fan_cmd1);
+       data->valid = false;
+ out:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+/* Set fan mode. Accepts either 1 (open-loop) or 2 (closed-loop). */
+static int do_set_pwm_enable(struct device *dev, unsigned long val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = g762_update_client(dev);
+       int ret;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       mutex_lock(&data->update_lock);
+       switch (val) {
+       case G762_FAN_MODE_CLOSED_LOOP:
+               data->fan_cmd1 |=  G762_REG_FAN_CMD1_FAN_MODE;
+               break;
+       case G762_FAN_MODE_OPEN_LOOP:
+               data->fan_cmd1 &= ~G762_REG_FAN_CMD1_FAN_MODE;
+               /*
+                * BUG FIX: if SET_CNT register value is 255 then, for some
+                * unknown reason, fan will not rotate as expected, no matter
+                * the value of SET_OUT (to be specific, this seems to happen
+                * only in PWM mode). To workaround this bug, we give SET_CNT
+                * value of 254 if it is 255 when switching to open-loop.
+                */
+               if (data->set_cnt == 0xff)
+                       i2c_smbus_write_byte_data(client, G762_REG_SET_CNT,
+                                                 254);
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+                                       data->fan_cmd1);
+       data->valid = false;
+ out:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+/* Set PWM polarity. Accepts either 0 (positive duty) or 1 (negative duty) */
+static int do_set_pwm_polarity(struct device *dev, unsigned long val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = g762_update_client(dev);
+       int ret;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       mutex_lock(&data->update_lock);
+       switch (val) {
+       case G762_PWM_POLARITY_POSITIVE:
+               data->fan_cmd1 &= ~G762_REG_FAN_CMD1_PWM_POLARITY;
+               break;
+       case G762_PWM_POLARITY_NEGATIVE:
+               data->fan_cmd1 |=  G762_REG_FAN_CMD1_PWM_POLARITY;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+                                       data->fan_cmd1);
+       data->valid = false;
+ out:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+/*
+ * Set pwm value. Accepts values between 0 (stops the fan) and
+ * 255 (full speed). This only makes sense in open-loop mode.
+ */
+static int do_set_pwm(struct device *dev, unsigned long val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = i2c_get_clientdata(client);
+       int ret;
+
+       if (val > 255)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       ret = i2c_smbus_write_byte_data(client, G762_REG_SET_OUT, val);
+       data->valid = false;
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+/*
+ * Set fan RPM value. Can be called both in closed and open-loop mode
+ * but effect will only be seen after closed-loop mode is configured.
+ */
+static int do_set_fan_target(struct device *dev, unsigned long val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = g762_update_client(dev);
+       int ret;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       mutex_lock(&data->update_lock);
+       data->set_cnt = cnt_from_rpm(val, data->clk_freq,
+                                    G762_PULSE_FROM_REG(data->fan_cmd1),
+                                    G762_CLKDIV_FROM_REG(data->fan_cmd1),
+                                    G762_GEARMULT_FROM_REG(data->fan_cmd2));
+       ret = i2c_smbus_write_byte_data(client, G762_REG_SET_CNT,
+                                       data->set_cnt);
+       data->valid = false;
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+/* Set fan startup voltage. Accepted values are either 0, 1, 2 or 3. */
+static int do_set_fan_startv(struct device *dev, unsigned long val)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = g762_update_client(dev);
+       int ret;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       mutex_lock(&data->update_lock);
+       switch (val) {
+       case 0:
+               data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_0;
+               data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_1;
+               break;
+       case 1:
+               data->fan_cmd2 |=  G762_REG_FAN_CMD2_FAN_STARTV_0;
+               data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_1;
+               break;
+       case 2:
+               data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_0;
+               data->fan_cmd2 |=  G762_REG_FAN_CMD2_FAN_STARTV_1;
+               break;
+       case 3:
+               data->fan_cmd2 |=  G762_REG_FAN_CMD2_FAN_STARTV_0;
+               data->fan_cmd2 |=  G762_REG_FAN_CMD2_FAN_STARTV_1;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD2,
+                                       data->fan_cmd2);
+       data->valid = false;
+ out:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+/*
+ * Helper to import hardware characteristics from .dts file and push
+ * those to the chip.
+ */
+
+#ifdef CONFIG_OF
+static struct of_device_id g762_dt_match[] = {
+       { .compatible = "gmt,g762" },
+       { .compatible = "gmt,g763" },
+       { },
+};
+
+/*
+ * Grab clock (a required property), enable it, get (fixed) clock frequency
+ * and store it. Note: upon success, clock has been prepared and enabled; it
+ * must later be unprepared and disabled (e.g. during module unloading) by a
+ * call to g762_of_clock_disable(). Note that a reference to clock is kept
+ * in our private data structure to be used in this function.
+ */
+static int g762_of_clock_enable(struct i2c_client *client)
+{
+       struct g762_data *data;
+       unsigned long clk_freq;
+       struct clk *clk;
+       int ret;
+
+       if (!client->dev.of_node)
+               return 0;
+
+       clk = of_clk_get(client->dev.of_node, 0);
+       if (IS_ERR(clk)) {
+               dev_err(&client->dev, "failed to get clock\n");
+               return PTR_ERR(clk);
+       }
+
+       ret = clk_prepare_enable(clk);
+       if (ret) {
+               dev_err(&client->dev, "failed to enable clock\n");
+               goto clk_put;
+       }
+
+       clk_freq = clk_get_rate(clk);
+       ret = do_set_clk_freq(&client->dev, clk_freq);
+       if (ret) {
+               dev_err(&client->dev, "invalid clock freq %lu\n", clk_freq);
+               goto clk_unprep;
+       }
+
+       data = i2c_get_clientdata(client);
+       data->clk = clk;
+
+       return 0;
+
+ clk_unprep:
+       clk_disable_unprepare(clk);
+
+ clk_put:
+       clk_put(clk);
+
+       return ret;
+}
+
+static void g762_of_clock_disable(struct i2c_client *client)
+{
+       struct g762_data *data = i2c_get_clientdata(client);
+
+       if (!data->clk)
+               return;
+
+       clk_disable_unprepare(data->clk);
+       clk_put(data->clk);
+}
+
+static int g762_of_prop_import_one(struct i2c_client *client,
+                                  const char *pname,
+                                  int (*psetter)(struct device *dev,
+                                                 unsigned long val))
+{
+       const __be32 *prop;
+       int len, ret;
+       u32 pval;
+
+       prop = of_get_property(client->dev.of_node, pname, &len);
+       if (!prop || len != sizeof(u32))
+               return 0;
+
+       pval = be32_to_cpu(prop[0]);
+       dev_dbg(&client->dev, "found %s (%d)\n", pname, pval);
+       ret = (*psetter)(&client->dev, pval);
+       if (ret)
+               dev_err(&client->dev, "unable to set %s (%d)\n", pname, pval);
+
+       return ret;
+}
+
+static int g762_of_prop_import(struct i2c_client *client)
+{
+       int ret;
+
+       if (!client->dev.of_node)
+               return 0;
+
+       ret = g762_of_prop_import_one(client, "fan_gear_mode",
+                                     do_set_fan_gear_mode);
+       if (ret)
+               return ret;
+
+       ret = g762_of_prop_import_one(client, "pwm_polarity",
+                                     do_set_pwm_polarity);
+       if (ret)
+               return ret;
+
+       return g762_of_prop_import_one(client, "fan_startv",
+                                      do_set_fan_startv);
+}
+
+#else
+static int g762_of_prop_import(struct i2c_client *client)
+{
+       return 0;
+}
+
+static int g762_of_clock_enable(struct i2c_client *client)
+{
+       return 0;
+}
+
+static void g762_of_clock_disable(struct i2c_client *client) { }
+#endif
+
+/*
+ * Helper to import hardware characteristics from .dts file and push
+ * those to the chip.
+ */
+
+static int g762_pdata_prop_import(struct i2c_client *client)
+{
+       struct g762_platform_data *pdata = client->dev.platform_data;
+       int ret;
+
+       if (!pdata)
+               return 0;
+
+       ret = do_set_fan_gear_mode(&client->dev, pdata->fan_gear_mode);
+       if (ret)
+               return ret;
+
+       ret = do_set_pwm_polarity(&client->dev, pdata->pwm_polarity);
+       if (ret)
+               return ret;
+
+       ret = do_set_fan_startv(&client->dev, pdata->fan_startv);
+       if (ret)
+               return ret;
+
+       return do_set_clk_freq(&client->dev, pdata->clk_freq);
+}
+
+/*
+ * sysfs attributes
+ */
+
+/*
+ * Read function for fan1_input sysfs file. Return current fan RPM value, or
+ * 0 if fan is out of control.
+ */
+static ssize_t get_fan_rpm(struct device *dev, struct device_attribute *da,
+                          char *buf)
+{
+       struct g762_data *data = g762_update_client(dev);
+       unsigned int rpm = 0;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       mutex_lock(&data->update_lock);
+       /* reverse logic: fan out of control reporting is enabled low */
+       if (data->fan_sta & G762_REG_FAN_STA_OOC) {
+               rpm = rpm_from_cnt(data->act_cnt, data->clk_freq,
+                                  G762_PULSE_FROM_REG(data->fan_cmd1),
+                                  G762_CLKDIV_FROM_REG(data->fan_cmd1),
+                                  G762_GEARMULT_FROM_REG(data->fan_cmd2));
+       }
+       mutex_unlock(&data->update_lock);
+
+       return sprintf(buf, "%u\n", rpm);
+}
+
+/*
+ * Read and write functions for pwm1_mode sysfs file. Get and set fan speed
+ * control mode i.e. PWM (1) or DC (0).
+ */
+static ssize_t get_pwm_mode(struct device *dev, struct device_attribute *da,
+                           char *buf)
+{
+       struct g762_data *data = g762_update_client(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n",
+                      !!(data->fan_cmd1 & G762_REG_FAN_CMD1_OUT_MODE));
+}
+
+static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *da,
+                           const char *buf, size_t count)
+{
+       unsigned long val;
+       int ret;
+
+       if (kstrtoul(buf, 10, &val))
+               return -EINVAL;
+
+       ret = do_set_pwm_mode(dev, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+/*
+ * Read and write functions for fan1_div sysfs file. Get and set fan
+ * controller prescaler value
+ */
+static ssize_t get_fan_div(struct device *dev,
+                          struct device_attribute *da, char *buf)
+{
+       struct g762_data *data = g762_update_client(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", G762_CLKDIV_FROM_REG(data->fan_cmd1));
+}
+
+static ssize_t set_fan_div(struct device *dev,
+                          struct device_attribute *da,
+                          const char *buf, size_t count)
+{
+       unsigned long val;
+       int ret;
+
+       if (kstrtoul(buf, 10, &val))
+               return -EINVAL;
+
+       ret = do_set_fan_div(dev, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+/*
+ * Read and write functions for fan1_pulses sysfs file. Get and set number
+ * of tachometer pulses per fan revolution.
+ */
+static ssize_t get_fan_pulses(struct device *dev,
+                             struct device_attribute *da, char *buf)
+{
+       struct g762_data *data = g762_update_client(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", G762_PULSE_FROM_REG(data->fan_cmd1));
+}
+
+static ssize_t set_fan_pulses(struct device *dev,
+                             struct device_attribute *da,
+                             const char *buf, size_t count)
+{
+       unsigned long val;
+       int ret;
+
+       if (kstrtoul(buf, 10, &val))
+               return -EINVAL;
+
+       ret = do_set_fan_pulses(dev, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+/*
+ * Read and write functions for pwm1_enable. Get and set fan speed control mode
+ * (i.e. closed or open-loop).
+ *
+ * Following documentation about hwmon's sysfs interface, a pwm1_enable node
+ * should accept followings:
+ *
+ *  0 : no fan speed control (i.e. fan at full speed)
+ *  1 : manual fan speed control enabled (use pwm[1-*]) (open-loop)
+ *  2+: automatic fan speed control enabled (use fan[1-*]_target) (closed-loop)
+ *
+ * but we do not accept 0 as this mode is not natively supported by the chip
+ * and it is not emulated by g762 driver. -EINVAL is returned in this case.
+ */
+static ssize_t get_pwm_enable(struct device *dev,
+                             struct device_attribute *da, char *buf)
+{
+       struct g762_data *data = g762_update_client(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n",
+                      (!!(data->fan_cmd1 & G762_REG_FAN_CMD1_FAN_MODE)) + 1);
+}
+
+static ssize_t set_pwm_enable(struct device *dev,
+                             struct device_attribute *da,
+                             const char *buf, size_t count)
+{
+       unsigned long val;
+       int ret;
+
+       if (kstrtoul(buf, 10, &val))
+               return -EINVAL;
+
+       ret = do_set_pwm_enable(dev, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+/*
+ * Read and write functions for pwm1 sysfs file. Get and set pwm value
+ * (which affects fan speed) in open-loop mode. 0 stops the fan and 255
+ * makes it run at full speed.
+ */
+static ssize_t get_pwm(struct device *dev, struct device_attribute *da,
+                      char *buf)
+{
+       struct g762_data *data = g762_update_client(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", data->set_out);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *da,
+                      const char *buf, size_t count)
+{
+       unsigned long val;
+       int ret;
+
+       if (kstrtoul(buf, 10, &val))
+               return -EINVAL;
+
+       ret = do_set_pwm(dev, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+/*
+ * Read and write function for fan1_target sysfs file. Get/set the fan speed in
+ * closed-loop mode. Speed is given as a RPM value; then the chip will regulate
+ * the fan speed using pulses from fan tachometer.
+ *
+ * Refer to rpm_from_cnt() implementation above to get info about count number
+ * calculation.
+ *
+ * Also note that due to rounding errors it is possible that you don't read
+ * back exactly the value you have set.
+ */
+static ssize_t get_fan_target(struct device *dev, struct device_attribute *da,
+                             char *buf)
+{
+       struct g762_data *data = g762_update_client(dev);
+       unsigned int rpm;
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       mutex_lock(&data->update_lock);
+       rpm = rpm_from_cnt(data->set_cnt, data->clk_freq,
+                          G762_PULSE_FROM_REG(data->fan_cmd1),
+                          G762_CLKDIV_FROM_REG(data->fan_cmd1),
+                          G762_GEARMULT_FROM_REG(data->fan_cmd2));
+       mutex_unlock(&data->update_lock);
+
+       return sprintf(buf, "%u\n", rpm);
+}
+
+static ssize_t set_fan_target(struct device *dev, struct device_attribute *da,
+                             const char *buf, size_t count)
+{
+       unsigned long val;
+       int ret;
+
+       if (kstrtoul(buf, 10, &val))
+               return -EINVAL;
+
+       ret = do_set_fan_target(dev, val);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+/* read function for fan1_fault sysfs file. */
+static ssize_t get_fan_failure(struct device *dev, struct device_attribute *da,
+                              char *buf)
+{
+       struct g762_data *data = g762_update_client(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%u\n", !!(data->fan_sta & G762_REG_FAN_STA_FAIL));
+}
+
+/*
+ * read function for fan1_alarm sysfs file. Note that OOC condition is
+ * enabled low
+ */
+static ssize_t get_fan_ooc(struct device *dev, struct device_attribute *da,
+                          char *buf)
+{
+       struct g762_data *data = g762_update_client(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%u\n", !(data->fan_sta & G762_REG_FAN_STA_OOC));
+}
+
+static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
+static DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, get_pwm_mode, set_pwm_mode);
+static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+                  get_pwm_enable, set_pwm_enable);
+static DEVICE_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL);
+static DEVICE_ATTR(fan1_alarm, S_IRUGO, get_fan_ooc, NULL);
+static DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan_failure, NULL);
+static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO,
+                  get_fan_target, set_fan_target);
+static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_fan_div, set_fan_div);
+static DEVICE_ATTR(fan1_pulses, S_IWUSR | S_IRUGO,
+                  get_fan_pulses, set_fan_pulses);
+
+/* Driver data */
+static struct attribute *g762_attributes[] = {
+       &dev_attr_fan1_input.attr,
+       &dev_attr_fan1_alarm.attr,
+       &dev_attr_fan1_fault.attr,
+       &dev_attr_fan1_target.attr,
+       &dev_attr_fan1_div.attr,
+       &dev_attr_fan1_pulses.attr,
+       &dev_attr_pwm1.attr,
+       &dev_attr_pwm1_mode.attr,
+       &dev_attr_pwm1_enable.attr,
+       NULL
+};
+
+static const struct attribute_group g762_group = {
+       .attrs = g762_attributes,
+};
+
+/*
+ * Enable both fan failure detection and fan out of control protection. The
+ * function does not protect change/access to data structure; it must thus
+ * only be called during initialization.
+ */
+static inline int g762_fan_init(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct g762_data *data = g762_update_client(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       data->fan_cmd1 |= G762_REG_FAN_CMD1_DET_FAN_FAIL;
+       data->fan_cmd1 |= G762_REG_FAN_CMD1_DET_FAN_OOC;
+       data->valid = false;
+
+       return i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+                                        data->fan_cmd1);
+}
+
+static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct g762_data *data;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       data = devm_kzalloc(&client->dev, sizeof(struct g762_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+       data->client = client;
+       mutex_init(&data->update_lock);
+
+       /* Enable fan failure detection and fan out of control protection */
+       ret = g762_fan_init(&client->dev);
+       if (ret)
+               return ret;
+
+       /* Get configuration via DT ... */
+       ret = g762_of_clock_enable(client);
+       if (ret)
+               return ret;
+       ret = g762_of_prop_import(client);
+       if (ret)
+               goto clock_dis;
+       /* ... or platform_data */
+       ret = g762_pdata_prop_import(client);
+       if (ret)
+               goto clock_dis;
+
+       /* Register sysfs hooks */
+       ret = sysfs_create_group(&client->dev.kobj, &g762_group);
+       if (ret)
+               goto clock_dis;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               ret = PTR_ERR(data->hwmon_dev);
+               goto sysfs_rem;
+       }
+
+       return 0;
+
+ sysfs_rem:
+       sysfs_remove_group(&client->dev.kobj, &g762_group);
+
+ clock_dis:
+       g762_of_clock_disable(client);
+
+       return ret;
+}
+
+static int g762_remove(struct i2c_client *client)
+{
+       struct g762_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &g762_group);
+       g762_of_clock_disable(client);
+
+       return 0;
+}
+
+static struct i2c_driver g762_driver = {
+       .driver = {
+               .name = DRVNAME,
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(g762_dt_match),
+       },
+       .probe    = g762_probe,
+       .remove   = g762_remove,
+       .id_table = g762_id,
+};
+
+module_i2c_driver(g762_driver);
+
+MODULE_AUTHOR("Arnaud EBALARD <arno@natisbad.org>");
+MODULE_DESCRIPTION("GMT G762/G763 driver");
+MODULE_LICENSE("GPL");
index b87c2ccee06b39196b1be67ea43cacbf8066e499..de058c278aa980145722bccb280e7840530c5916 100644 (file)
@@ -556,7 +556,6 @@ static int i5k_amb_probe(struct platform_device *pdev)
 
 err_init_failed:
        iounmap(data->amb_mmio);
-       platform_set_drvdata(pdev, NULL);
 err_map_failed:
        release_mem_region(data->amb_base, data->amb_len);
 err:
@@ -576,7 +575,6 @@ static int i5k_amb_remove(struct platform_device *pdev)
        kfree(data->attrs);
        iounmap(data->amb_mmio);
        release_mem_region(data->amb_base, data->amb_len);
-       platform_set_drvdata(pdev, NULL);
        kfree(data);
        return 0;
 }
index 52b77afebde120a17ce75bf6401103cad556d021..708081b68c6fc7007ec0524d8d0ee5745d0419f9 100644 (file)
@@ -180,6 +180,7 @@ static struct of_device_id iio_hwmon_of_match[] = {
        { .compatible = "iio-hwmon", },
        { }
 };
+MODULE_DEVICE_TABLE(of, iio_hwmon_of_match);
 
 static struct platform_driver __refdata iio_hwmon_driver = {
        .driver = {
index 4958b2f89dcefff53354e18c6c37f6f356f6eeb2..d917a2d8c30ffde4183382d8370bef781dd0e824 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/jiffies.h>
+#include <linux/of.h>
 
 #include <linux/platform_data/ina2xx.h>
 
@@ -221,6 +222,7 @@ static int ina2xx_probe(struct i2c_client *client,
        struct ina2xx_data *data;
        struct ina2xx_platform_data *pdata;
        int ret;
+       u32 val;
        long shunt = 10000; /* default shunt value 10mOhms */
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
@@ -234,6 +236,9 @@ static int ina2xx_probe(struct i2c_client *client,
                pdata =
                  (struct ina2xx_platform_data *)client->dev.platform_data;
                shunt = pdata->shunt_uohms;
+       } else if (!of_property_read_u32(client->dev.of_node,
+                               "shunt-resistor", &val)) {
+                       shunt = val;
        }
 
        if (shunt <= 0)
index 04638aee90398f44e73a620e3a3cffc9631b8d40..99cec18254203c5ebfa59ba0b1cbfdecabf77aac 100644 (file)
@@ -199,7 +199,7 @@ static const s8 NCT6775_ALARM_BITS[] = {
        0, 1, 2, 3, 8, 21, 20, 16,      /* in0.. in7 */
        17, -1, -1, -1, -1, -1, -1,     /* in8..in14 */
        -1,                             /* unused */
-       6, 7, 11, 10, 23,               /* fan1..fan5 */
+       6, 7, 11, -1, -1,               /* fan1..fan5 */
        -1, -1, -1,                     /* unused */
        4, 5, 13, -1, -1, -1,           /* temp1..temp6 */
        12, -1 };                       /* intrusion0, intrusion1 */
@@ -625,6 +625,7 @@ struct nct6775_data {
        u8 has_fan_min;         /* some fans don't have min register */
        bool has_fan_div;
 
+       u8 num_temp_alarms;     /* 2 or 3 */
        u8 temp_fixed_num;      /* 3 or 6 */
        u8 temp_type[NUM_TEMP_FIXED];
        s8 temp_offset[NUM_TEMP_FIXED];
@@ -1193,6 +1194,42 @@ show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
                       (unsigned int)((data->alarms >> nr) & 0x01));
 }
 
+static int find_temp_source(struct nct6775_data *data, int index, int count)
+{
+       int source = data->temp_src[index];
+       int nr;
+
+       for (nr = 0; nr < count; nr++) {
+               int src;
+
+               src = nct6775_read_value(data,
+                                        data->REG_TEMP_SOURCE[nr]) & 0x1f;
+               if (src == source)
+                       return nr;
+       }
+       return -1;
+}
+
+static ssize_t
+show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+       struct nct6775_data *data = nct6775_update_device(dev);
+       unsigned int alarm = 0;
+       int nr;
+
+       /*
+        * For temperatures, there is no fixed mapping from registers to alarm
+        * bits. Alarm bits are determined by the temperature source mapping.
+        */
+       nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
+       if (nr >= 0) {
+               int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
+               alarm = (data->alarms >> bit) & 0x01;
+       }
+       return sprintf(buf, "%u\n", alarm);
+}
+
 static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in_reg, NULL, 0, 0);
 static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in_reg, NULL, 1, 0);
 static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in_reg, NULL, 2, 0);
@@ -1874,22 +1911,18 @@ static struct sensor_device_attribute sda_temp_type[] = {
 };
 
 static struct sensor_device_attribute sda_temp_alarm[] = {
-       SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
-                   TEMP_ALARM_BASE),
-       SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
-                   TEMP_ALARM_BASE + 1),
-       SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
-                   TEMP_ALARM_BASE + 2),
-       SENSOR_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL,
-                   TEMP_ALARM_BASE + 3),
-       SENSOR_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL,
-                   TEMP_ALARM_BASE + 4),
-       SENSOR_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL,
-                   TEMP_ALARM_BASE + 5),
+       SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
+       SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
+       SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
+       SENSOR_ATTR(temp4_alarm, S_IRUGO, show_temp_alarm, NULL, 3),
+       SENSOR_ATTR(temp5_alarm, S_IRUGO, show_temp_alarm, NULL, 4),
+       SENSOR_ATTR(temp6_alarm, S_IRUGO, show_temp_alarm, NULL, 5),
+       SENSOR_ATTR(temp7_alarm, S_IRUGO, show_temp_alarm, NULL, 6),
+       SENSOR_ATTR(temp8_alarm, S_IRUGO, show_temp_alarm, NULL, 7),
+       SENSOR_ATTR(temp9_alarm, S_IRUGO, show_temp_alarm, NULL, 8),
+       SENSOR_ATTR(temp10_alarm, S_IRUGO, show_temp_alarm, NULL, 9),
 };
 
-#define NUM_TEMP_ALARM ARRAY_SIZE(sda_temp_alarm)
-
 static ssize_t
 show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -3215,13 +3248,11 @@ static void nct6775_device_remove_files(struct device *dev)
                device_remove_file(dev, &sda_temp_max[i].dev_attr);
                device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
                device_remove_file(dev, &sda_temp_crit[i].dev_attr);
+               device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
                if (!(data->have_temp_fixed & (1 << i)))
                        continue;
                device_remove_file(dev, &sda_temp_type[i].dev_attr);
                device_remove_file(dev, &sda_temp_offset[i].dev_attr);
-               if (i >= NUM_TEMP_ALARM)
-                       continue;
-               device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
        }
 
        device_remove_file(dev, &sda_caseopen[0].dev_attr);
@@ -3419,6 +3450,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->auto_pwm_num = 6;
                data->has_fan_div = true;
                data->temp_fixed_num = 3;
+               data->num_temp_alarms = 3;
 
                data->ALARM_BITS = NCT6775_ALARM_BITS;
 
@@ -3483,6 +3515,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->auto_pwm_num = 4;
                data->has_fan_div = false;
                data->temp_fixed_num = 3;
+               data->num_temp_alarms = 3;
 
                data->ALARM_BITS = NCT6776_ALARM_BITS;
 
@@ -3547,6 +3580,7 @@ static int nct6775_probe(struct platform_device *pdev)
                data->auto_pwm_num = 4;
                data->has_fan_div = false;
                data->temp_fixed_num = 6;
+               data->num_temp_alarms = 2;
 
                data->ALARM_BITS = NCT6779_ALARM_BITS;
 
@@ -3843,10 +3877,12 @@ static int nct6775_probe(struct platform_device *pdev)
                                                 &sda_fan_input[i].dev_attr);
                        if (err)
                                goto exit_remove;
-                       err = device_create_file(dev,
-                                                &sda_fan_alarm[i].dev_attr);
-                       if (err)
-                               goto exit_remove;
+                       if (data->ALARM_BITS[FAN_ALARM_BASE + i] >= 0) {
+                               err = device_create_file(dev,
+                                               &sda_fan_alarm[i].dev_attr);
+                               if (err)
+                                       goto exit_remove;
+                       }
                        if (data->kind != nct6776 &&
                            data->kind != nct6779) {
                                err = device_create_file(dev,
@@ -3897,6 +3933,12 @@ static int nct6775_probe(struct platform_device *pdev)
                        if (err)
                                goto exit_remove;
                }
+               if (find_temp_source(data, i, data->num_temp_alarms) >= 0) {
+                       err = device_create_file(dev,
+                                                &sda_temp_alarm[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
                if (!(data->have_temp_fixed & (1 << i)))
                        continue;
                err = device_create_file(dev, &sda_temp_type[i].dev_attr);
@@ -3905,12 +3947,6 @@ static int nct6775_probe(struct platform_device *pdev)
                err = device_create_file(dev, &sda_temp_offset[i].dev_attr);
                if (err)
                        goto exit_remove;
-               if (i >= NUM_TEMP_ALARM ||
-                   data->ALARM_BITS[TEMP_ALARM_BASE + i] < 0)
-                       continue;
-               err = device_create_file(dev, &sda_temp_alarm[i].dev_attr);
-               if (err)
-                       goto exit_remove;
        }
 
        for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) {
index d6d640a733d5425730cbd68cc15fbcfe1c229891..830a842d796af833c0b6a04785e1eff09b73599d 100644 (file)
@@ -514,7 +514,6 @@ static int ntc_thermistor_remove(struct platform_device *pdev)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
        ntc_iio_channel_release(pdata);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 016027229e81835f205f0cf90afb6a4575043d63..004801e6fbb9756d8bdeed3aac25899a7f00edaa 100644 (file)
@@ -2598,7 +2598,6 @@ static int w83627ehf_probe(struct platform_device *pdev)
 exit_remove:
        w83627ehf_device_remove_files(dev);
 exit_release:
-       platform_set_drvdata(pdev, NULL);
        release_region(res->start, IOREGION_LENGTH);
 exit:
        return err;
@@ -2611,7 +2610,6 @@ static int w83627ehf_remove(struct platform_device *pdev)
        hwmon_device_unregister(data->hwmon_dev);
        w83627ehf_device_remove_files(&pdev->dev);
        release_region(data->addr, IOREGION_LENGTH);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 73e2e7db2b64e061d94da6aca141fdceae88f7d1..527503617ee21607a11f4f2887be979770e5c061 100644 (file)
@@ -150,6 +150,7 @@ config I2C_PIIX4
            ATI SB700/SP5100
            ATI SB800
            AMD Hudson-2
+           AMD CZ
            Serverworks OSB4
            Serverworks CSB5
            Serverworks CSB6
index 650293ff4d623348c04f19ff68f8570505ac2a59..c7e3b0c1a1caf033ee326e9ce41d9bc0f7239959 100644 (file)
@@ -148,10 +148,6 @@ struct i2c_nmk_client {
  * @stop: stop condition.
  * @xfer_complete: acknowledge completion for a I2C message.
  * @result: controller propogated result.
- * @pinctrl: pinctrl handle.
- * @pins_default: default state for the pins.
- * @pins_idle: idle state for the pins.
- * @pins_sleep: sleep state for the pins.
  * @busy: Busy doing transfer.
  */
 struct nmk_i2c_dev {
@@ -165,11 +161,6 @@ struct nmk_i2c_dev {
        int                             stop;
        struct completion               xfer_complete;
        int                             result;
-       /* Three pin states - default, idle & sleep */
-       struct pinctrl                  *pinctrl;
-       struct pinctrl_state            *pins_default;
-       struct pinctrl_state            *pins_idle;
-       struct pinctrl_state            *pins_sleep;
        bool                            busy;
 };
 
@@ -645,13 +636,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
        }
 
        /* Optionaly enable pins to be muxed in and configured */
-       if (!IS_ERR(dev->pins_default)) {
-               status = pinctrl_select_state(dev->pinctrl,
-                               dev->pins_default);
-               if (status)
-                       dev_err(&dev->adev->dev,
-                               "could not set default pins\n");
-       }
+       pinctrl_pm_select_default_state(&dev->adev->dev);
 
        status = init_hw(dev);
        if (status)
@@ -681,13 +666,7 @@ out:
        clk_disable_unprepare(dev->clk);
 out_clk:
        /* Optionally let pins go into idle state */
-       if (!IS_ERR(dev->pins_idle)) {
-               status = pinctrl_select_state(dev->pinctrl,
-                               dev->pins_idle);
-               if (status)
-                       dev_err(&dev->adev->dev,
-                               "could not set pins to idle state\n");
-       }
+       pinctrl_pm_select_idle_state(&dev->adev->dev);
 
        pm_runtime_put_sync(&dev->adev->dev);
 
@@ -882,41 +861,22 @@ static int nmk_i2c_suspend(struct device *dev)
 {
        struct amba_device *adev = to_amba_device(dev);
        struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
-       int ret;
 
        if (nmk_i2c->busy)
                return -EBUSY;
 
-       if (!IS_ERR(nmk_i2c->pins_sleep)) {
-               ret = pinctrl_select_state(nmk_i2c->pinctrl,
-                               nmk_i2c->pins_sleep);
-               if (ret)
-                       dev_err(dev, "could not set pins to sleep state\n");
-       }
+       pinctrl_pm_select_sleep_state(dev);
 
        return 0;
 }
 
 static int nmk_i2c_resume(struct device *dev)
 {
-       struct amba_device *adev = to_amba_device(dev);
-       struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
-       int ret;
-
        /* First go to the default state */
-       if (!IS_ERR(nmk_i2c->pins_default)) {
-               ret = pinctrl_select_state(nmk_i2c->pinctrl,
-                               nmk_i2c->pins_default);
-               if (ret)
-                       dev_err(dev, "could not set pins to default state\n");
-       }
+       pinctrl_pm_select_default_state(dev);
        /* Then let's idle the pins until the next transfer happens */
-       if (!IS_ERR(nmk_i2c->pins_idle)) {
-               ret = pinctrl_select_state(nmk_i2c->pinctrl,
-                               nmk_i2c->pins_idle);
-               if (ret)
-                       dev_err(dev, "could not set pins to idle state\n");
-       }
+       pinctrl_pm_select_idle_state(dev);
+
        return 0;
 }
 #else
@@ -1004,39 +964,10 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
        dev->adev = adev;
        amba_set_drvdata(adev, dev);
 
-       dev->pinctrl = devm_pinctrl_get(&adev->dev);
-       if (IS_ERR(dev->pinctrl)) {
-               ret = PTR_ERR(dev->pinctrl);
-               goto err_pinctrl;
-       }
-
-       dev->pins_default = pinctrl_lookup_state(dev->pinctrl,
-                                                PINCTRL_STATE_DEFAULT);
-       if (IS_ERR(dev->pins_default)) {
-               dev_err(&adev->dev, "could not get default pinstate\n");
-       } else {
-               ret = pinctrl_select_state(dev->pinctrl,
-                                          dev->pins_default);
-               if (ret)
-                       dev_dbg(&adev->dev, "could not set default pinstate\n");
-       }
-
-       dev->pins_idle = pinctrl_lookup_state(dev->pinctrl,
-                                             PINCTRL_STATE_IDLE);
-       if (IS_ERR(dev->pins_idle)) {
-               dev_dbg(&adev->dev, "could not get idle pinstate\n");
-       } else {
-               /* If possible, let's go to idle until the first transfer */
-               ret = pinctrl_select_state(dev->pinctrl,
-                                          dev->pins_idle);
-               if (ret)
-                       dev_dbg(&adev->dev, "could not set idle pinstate\n");
-       }
-
-       dev->pins_sleep = pinctrl_lookup_state(dev->pinctrl,
-                                              PINCTRL_STATE_SLEEP);
-       if (IS_ERR(dev->pins_sleep))
-               dev_dbg(&adev->dev, "could not get sleep pinstate\n");
+       /* Select default pin state */
+       pinctrl_pm_select_default_state(&adev->dev);
+       /* If possible, let's go to idle until the first transfer */
+       pinctrl_pm_select_idle_state(&adev->dev);
 
        dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
        if (!dev->virtbase) {
@@ -1106,7 +1037,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
        iounmap(dev->virtbase);
  err_no_ioremap:
        kfree(dev);
- err_pinctrl:
  err_no_mem:
 
        return ret;
index 39ab78c1a02cc3a4f056a0294432ef01fbbfd165..d05ad590af29b5163e0920a8d7868a31d8ec0529 100644 (file)
@@ -22,7 +22,7 @@
        Intel PIIX4, 440MX
        Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
        ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800
-       AMD Hudson-2
+       AMD Hudson-2, CZ
        SMSC Victory66
 
    Note: we assume there can only be one device, with one or more
@@ -522,6 +522,7 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x790b) },
        { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
                     PCI_DEVICE_ID_SERVERWORKS_OSB4) },
        { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
index 48e31ed69dbf159f5e44f2ab2a4968896320c3eb..f32ca293ae0e30674a436afb4bc431cdb743de28 100644 (file)
@@ -435,7 +435,7 @@ static const struct dev_pm_ops i2c_device_pm_ops = {
        SET_RUNTIME_PM_OPS(
                pm_generic_runtime_suspend,
                pm_generic_runtime_resume,
-               pm_generic_runtime_idle
+               NULL
        )
 };
 
index 2ff6204449300e088883d411b3c4f0f46d2eabaf..0b510bafd90e2904d989d4f8ce06b89f50ea1f76 100644 (file)
@@ -1756,7 +1756,7 @@ static int ide_cd_probe(ide_drive_t *drive)
 
        info->dev.parent = &drive->gendev;
        info->dev.release = ide_cd_release;
-       dev_set_name(&info->dev, dev_name(&drive->gendev));
+       dev_set_name(&info->dev, "%s", dev_name(&drive->gendev));
 
        if (device_register(&info->dev))
                goto out_free_disk;
index de86631e767d6d08b6c500e3162aa5ca50551c85..838996a0039e18547a929099e5e631ccbb96f924 100644 (file)
@@ -392,7 +392,7 @@ static int ide_gd_probe(ide_drive_t *drive)
 
        idkp->dev.parent = &drive->gendev;
        idkp->dev.release = ide_disk_release;
-       dev_set_name(&idkp->dev, dev_name(&drive->gendev));
+       dev_set_name(&idkp->dev, "%s", dev_name(&drive->gendev));
 
        if (device_register(&idkp->dev))
                goto out_free_disk;
index 068cef0a987aa672566d986eb7353670d533fdd6..2a744a91370e640d1fe3603409b80e776d8041de 100644 (file)
@@ -545,7 +545,7 @@ static int ide_register_port(ide_hwif_t *hwif)
        int ret;
 
        /* register with global device tree */
-       dev_set_name(&hwif->gendev, hwif->name);
+       dev_set_name(&hwif->gendev, "%s", hwif->name);
        dev_set_drvdata(&hwif->gendev, hwif);
        if (hwif->gendev.parent == NULL)
                hwif->gendev.parent = hwif->dev;
@@ -559,7 +559,7 @@ static int ide_register_port(ide_hwif_t *hwif)
        }
 
        hwif->portdev = device_create(ide_port_class, &hwif->gendev,
-                                     MKDEV(0, 0), hwif, hwif->name);
+                                     MKDEV(0, 0), hwif, "%s", hwif->name);
        if (IS_ERR(hwif->portdev)) {
                ret = PTR_ERR(hwif->portdev);
                device_unregister(&hwif->gendev);
index c6c574bd5f59e079199072e0f27311804f4faff4..1793aea4a7d2c58192f6023d43e90c10daedbb52 100644 (file)
@@ -1985,7 +1985,7 @@ static int ide_tape_probe(ide_drive_t *drive)
 
        tape->dev.parent = &drive->gendev;
        tape->dev.release = ide_tape_release;
-       dev_set_name(&tape->dev, dev_name(&drive->gendev));
+       dev_set_name(&tape->dev, "%s", dev_name(&drive->gendev));
 
        if (device_register(&tape->dev))
                goto out_free_disk;
index 246fdc1516524cbc31940a6ed946e9b14ec741e8..99904f7d59e3ccda6cbffeaa6c0c2d2b66924690 100644 (file)
@@ -813,7 +813,7 @@ int ib_device_register_sysfs(struct ib_device *device,
 
        class_dev->class      = &ib_class;
        class_dev->parent     = device->dma_device;
-       dev_set_name(class_dev, device->name);
+       dev_set_name(class_dev, "%s", device->name);
        dev_set_drvdata(class_dev, device);
 
        INIT_LIST_HEAD(&device->port_list);
index b56c9428f3c5f5fbf574b0b9570ec2caa02cbee3..9dd0bc89c3aa83a6bf4b89faa3ce6c20e4648e3e 100644 (file)
@@ -2208,7 +2208,7 @@ int qib_cdev_init(int minor, const char *name,
                goto err_cdev;
        }
 
-       device = device_create(qib_class, NULL, dev, NULL, name);
+       device = device_create(qib_class, NULL, dev, NULL, "%s", name);
        if (!IS_ERR(device))
                goto done;
        ret = PTR_ERR(device);
index 49557f27bfa6b3be86542b20d7360a24d5ee4834..7e8b0a52af25b63108c781a19f908b084a22975c 100644 (file)
@@ -206,33 +206,6 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
        return NOTIFY_DONE;
 }
 
-/* Clear any keys in the buffer */
-static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev)
-{
-       uint8_t old_state[ckdev->cols];
-       uint8_t new_state[ckdev->cols];
-       unsigned long duration;
-       int i, ret;
-
-       /*
-        * Keep reading until we see that the scan state does not change.
-        * That indicates that we are done.
-        *
-        * Assume that the EC keyscan buffer is at most 32 deep.
-        */
-       duration = jiffies;
-       ret = cros_ec_keyb_get_state(ckdev, new_state);
-       for (i = 1; !ret && i < 32; i++) {
-               memcpy(old_state, new_state, sizeof(old_state));
-               ret = cros_ec_keyb_get_state(ckdev, new_state);
-               if (0 == memcmp(old_state, new_state, sizeof(old_state)))
-                       break;
-       }
-       duration = jiffies - duration;
-       dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i,
-               jiffies_to_usecs(duration));
-}
-
 static int cros_ec_keyb_probe(struct platform_device *pdev)
 {
        struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
@@ -299,6 +272,33 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
+/* Clear any keys in the buffer */
+static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev)
+{
+       uint8_t old_state[ckdev->cols];
+       uint8_t new_state[ckdev->cols];
+       unsigned long duration;
+       int i, ret;
+
+       /*
+        * Keep reading until we see that the scan state does not change.
+        * That indicates that we are done.
+        *
+        * Assume that the EC keyscan buffer is at most 32 deep.
+        */
+       duration = jiffies;
+       ret = cros_ec_keyb_get_state(ckdev, new_state);
+       for (i = 1; !ret && i < 32; i++) {
+               memcpy(old_state, new_state, sizeof(old_state));
+               ret = cros_ec_keyb_get_state(ckdev, new_state);
+               if (0 == memcmp(old_state, new_state, sizeof(old_state)))
+                       break;
+       }
+       duration = jiffies - duration;
+       dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i,
+               jiffies_to_usecs(duration));
+}
+
 static int cros_ec_keyb_resume(struct device *dev)
 {
        struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
index bf51abb78deed14392a4c3e80d180c41d1e76546..7acbf351e9af2d52b80909177ce89dae6a8fc558 100644 (file)
@@ -99,7 +99,7 @@ struct ivhd_header {
        u64 mmio_phys;
        u16 pci_seg;
        u16 info;
-       u32 reserved;
+       u32 efr;
 } __attribute__((packed));
 
 /*
@@ -154,6 +154,7 @@ bool amd_iommu_iotlb_sup __read_mostly = true;
 u32 amd_iommu_max_pasids __read_mostly = ~0;
 
 bool amd_iommu_v2_present __read_mostly;
+bool amd_iommu_pc_present __read_mostly;
 
 bool amd_iommu_force_isolation __read_mostly;
 
@@ -369,23 +370,23 @@ static void iommu_disable(struct amd_iommu *iommu)
  * mapping and unmapping functions for the IOMMU MMIO space. Each AMD IOMMU in
  * the system has one.
  */
-static u8 __iomem * __init iommu_map_mmio_space(u64 address)
+static u8 __iomem * __init iommu_map_mmio_space(u64 address, u64 end)
 {
-       if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu")) {
-               pr_err("AMD-Vi: Can not reserve memory region %llx for mmio\n",
-                       address);
+       if (!request_mem_region(address, end, "amd_iommu")) {
+               pr_err("AMD-Vi: Can not reserve memory region %llx-%llx for mmio\n",
+                       address, end);
                pr_err("AMD-Vi: This is a BIOS bug. Please contact your hardware vendor\n");
                return NULL;
        }
 
-       return (u8 __iomem *)ioremap_nocache(address, MMIO_REGION_LENGTH);
+       return (u8 __iomem *)ioremap_nocache(address, end);
 }
 
 static void __init iommu_unmap_mmio_space(struct amd_iommu *iommu)
 {
        if (iommu->mmio_base)
                iounmap(iommu->mmio_base);
-       release_mem_region(iommu->mmio_phys, MMIO_REGION_LENGTH);
+       release_mem_region(iommu->mmio_phys, iommu->mmio_phys_end);
 }
 
 /****************************************************************************
@@ -1085,7 +1086,18 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
        iommu->cap_ptr = h->cap_ptr;
        iommu->pci_seg = h->pci_seg;
        iommu->mmio_phys = h->mmio_phys;
-       iommu->mmio_base = iommu_map_mmio_space(h->mmio_phys);
+
+       /* Check if IVHD EFR contains proper max banks/counters */
+       if ((h->efr != 0) &&
+           ((h->efr & (0xF << 13)) != 0) &&
+           ((h->efr & (0x3F << 17)) != 0)) {
+               iommu->mmio_phys_end = MMIO_REG_END_OFFSET;
+       } else {
+               iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET;
+       }
+
+       iommu->mmio_base = iommu_map_mmio_space(iommu->mmio_phys,
+                                               iommu->mmio_phys_end);
        if (!iommu->mmio_base)
                return -ENOMEM;
 
@@ -1160,6 +1172,33 @@ static int __init init_iommu_all(struct acpi_table_header *table)
        return 0;
 }
 
+
+static void init_iommu_perf_ctr(struct amd_iommu *iommu)
+{
+       u64 val = 0xabcd, val2 = 0;
+
+       if (!iommu_feature(iommu, FEATURE_PC))
+               return;
+
+       amd_iommu_pc_present = true;
+
+       /* Check if the performance counters can be written to */
+       if ((0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val, true)) ||
+           (0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) ||
+           (val != val2)) {
+               pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n");
+               amd_iommu_pc_present = false;
+               return;
+       }
+
+       pr_info("AMD-Vi: IOMMU performance counters supported\n");
+
+       val = readl(iommu->mmio_base + MMIO_CNTR_CONF_OFFSET);
+       iommu->max_banks = (u8) ((val >> 12) & 0x3f);
+       iommu->max_counters = (u8) ((val >> 7) & 0xf);
+}
+
+
 static int iommu_init_pci(struct amd_iommu *iommu)
 {
        int cap_ptr = iommu->cap_ptr;
@@ -1226,6 +1265,8 @@ static int iommu_init_pci(struct amd_iommu *iommu)
        if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE))
                amd_iommu_np_cache = true;
 
+       init_iommu_perf_ctr(iommu);
+
        if (is_rd890_iommu(iommu->dev)) {
                int i, j;
 
@@ -1278,7 +1319,7 @@ static void print_iommu_info(void)
                                if (iommu_feature(iommu, (1ULL << i)))
                                        pr_cont(" %s", feat_str[i]);
                        }
-               pr_cont("\n");
+                       pr_cont("\n");
                }
        }
        if (irq_remapping_enabled)
@@ -2232,3 +2273,84 @@ bool amd_iommu_v2_supported(void)
        return amd_iommu_v2_present;
 }
 EXPORT_SYMBOL(amd_iommu_v2_supported);
+
+/****************************************************************************
+ *
+ * IOMMU EFR Performance Counter support functionality. This code allows
+ * access to the IOMMU PC functionality.
+ *
+ ****************************************************************************/
+
+u8 amd_iommu_pc_get_max_banks(u16 devid)
+{
+       struct amd_iommu *iommu;
+       u8 ret = 0;
+
+       /* locate the iommu governing the devid */
+       iommu = amd_iommu_rlookup_table[devid];
+       if (iommu)
+               ret = iommu->max_banks;
+
+       return ret;
+}
+EXPORT_SYMBOL(amd_iommu_pc_get_max_banks);
+
+bool amd_iommu_pc_supported(void)
+{
+       return amd_iommu_pc_present;
+}
+EXPORT_SYMBOL(amd_iommu_pc_supported);
+
+u8 amd_iommu_pc_get_max_counters(u16 devid)
+{
+       struct amd_iommu *iommu;
+       u8 ret = 0;
+
+       /* locate the iommu governing the devid */
+       iommu = amd_iommu_rlookup_table[devid];
+       if (iommu)
+               ret = iommu->max_counters;
+
+       return ret;
+}
+EXPORT_SYMBOL(amd_iommu_pc_get_max_counters);
+
+int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
+                                   u64 *value, bool is_write)
+{
+       struct amd_iommu *iommu;
+       u32 offset;
+       u32 max_offset_lim;
+
+       /* Make sure the IOMMU PC resource is available */
+       if (!amd_iommu_pc_present)
+               return -ENODEV;
+
+       /* Locate the iommu associated with the device ID */
+       iommu = amd_iommu_rlookup_table[devid];
+
+       /* Check for valid iommu and pc register indexing */
+       if (WARN_ON((iommu == NULL) || (fxn > 0x28) || (fxn & 7)))
+               return -ENODEV;
+
+       offset = (u32)(((0x40|bank) << 12) | (cntr << 8) | fxn);
+
+       /* Limit the offset to the hw defined mmio region aperture */
+       max_offset_lim = (u32)(((0x40|iommu->max_banks) << 12) |
+                               (iommu->max_counters << 8) | 0x28);
+       if ((offset < MMIO_CNTR_REG_OFFSET) ||
+           (offset > max_offset_lim))
+               return -EINVAL;
+
+       if (is_write) {
+               writel((u32)*value, iommu->mmio_base + offset);
+               writel((*value >> 32), iommu->mmio_base + offset + 4);
+       } else {
+               *value = readl(iommu->mmio_base + offset + 4);
+               *value <<= 32;
+               *value = readl(iommu->mmio_base + offset);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val);
index c294961bdd36f8f26297792d83a91953168565b8..95ed6deae47fe76ac4a7a068b1b6f27e7f8a54c3 100644 (file)
@@ -56,6 +56,13 @@ extern int amd_iommu_domain_set_gcr3(struct iommu_domain *dom, int pasid,
 extern int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, int pasid);
 extern struct iommu_domain *amd_iommu_get_v2_domain(struct pci_dev *pdev);
 
+/* IOMMU Performance Counter functions */
+extern bool amd_iommu_pc_supported(void);
+extern u8 amd_iommu_pc_get_max_banks(u16 devid);
+extern u8 amd_iommu_pc_get_max_counters(u16 devid);
+extern int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
+                                   u64 *value, bool is_write);
+
 #define PPR_SUCCESS                    0x0
 #define PPR_INVALID                    0x1
 #define PPR_FAILURE                    0xf
index 0285a215df162e18552d241ac753e0bd42c74600..e400fbe411dead310bada51fb74d1475eab55bd0 100644 (file)
@@ -38,9 +38,6 @@
 #define ALIAS_TABLE_ENTRY_SIZE         2
 #define RLOOKUP_TABLE_ENTRY_SIZE       (sizeof(void *))
 
-/* Length of the MMIO region for the AMD IOMMU */
-#define MMIO_REGION_LENGTH       0x4000
-
 /* Capability offsets used by the driver */
 #define MMIO_CAP_HDR_OFFSET    0x00
 #define MMIO_RANGE_OFFSET      0x0c
 #define MMIO_STATUS_OFFSET     0x2020
 #define MMIO_PPR_HEAD_OFFSET   0x2030
 #define MMIO_PPR_TAIL_OFFSET   0x2038
+#define MMIO_CNTR_CONF_OFFSET  0x4000
+#define MMIO_CNTR_REG_OFFSET   0x40000
+#define MMIO_REG_END_OFFSET    0x80000
+
 
 
 /* Extended Feature Bits */
@@ -507,6 +508,10 @@ struct amd_iommu {
 
        /* physical address of MMIO space */
        u64 mmio_phys;
+
+       /* physical end address of MMIO space */
+       u64 mmio_phys_end;
+
        /* virtual address of MMIO space */
        u8 __iomem *mmio_base;
 
@@ -584,6 +589,10 @@ struct amd_iommu {
 
        /* The l2 indirect registers */
        u32 stored_l2[0x83];
+
+       /* The maximum PC banks and counters/bank (PCSup=1) */
+       u8 max_banks;
+       u8 max_counters;
 };
 
 struct devid_map {
index dcfea4e39be766810a327d0b402b7a539b71900c..39f81aeefcd698f6389f0cf12799491be8e2867d 100644 (file)
@@ -51,26 +51,27 @@ static void irq_remapping_disable_io_apic(void)
 
 static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
 {
-       int node, ret, sub_handle, index = 0;
+       int node, ret, sub_handle, nvec_pow2, index = 0;
        unsigned int irq;
        struct msi_desc *msidesc;
 
-       nvec = __roundup_pow_of_two(nvec);
-
        WARN_ON(!list_is_singular(&dev->msi_list));
        msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
        WARN_ON(msidesc->irq);
        WARN_ON(msidesc->msi_attrib.multiple);
+       WARN_ON(msidesc->nvec_used);
 
        node = dev_to_node(&dev->dev);
        irq = __create_irqs(get_nr_irqs_gsi(), nvec, node);
        if (irq == 0)
                return -ENOSPC;
 
-       msidesc->msi_attrib.multiple = ilog2(nvec);
+       nvec_pow2 = __roundup_pow_of_two(nvec);
+       msidesc->nvec_used = nvec;
+       msidesc->msi_attrib.multiple = ilog2(nvec_pow2);
        for (sub_handle = 0; sub_handle < nvec; sub_handle++) {
                if (!sub_handle) {
-                       index = msi_alloc_remapped_irq(dev, irq, nvec);
+                       index = msi_alloc_remapped_irq(dev, irq, nvec_pow2);
                        if (index < 0) {
                                ret = index;
                                goto error;
@@ -95,6 +96,7 @@ error:
         * IRQs from tearing down again in default_teardown_msi_irqs()
         */
        msidesc->irq = 0;
+       msidesc->nvec_used = 0;
        msidesc->msi_attrib.multiple = 0;
 
        return ret;
index 4a33351c25dce61c805a9c99258f893792a1ec2a..1fea003ed33f63c6cef961cbc1629dd71d3656ea 100644 (file)
@@ -10,6 +10,11 @@ config ARM_GIC
 config GIC_NON_BANKED
        bool
 
+config ARM_NVIC
+       bool
+       select IRQ_DOMAIN
+       select GENERIC_IRQ_CHIP
+
 config ARM_VIC
        bool
        select IRQ_DOMAIN
@@ -25,6 +30,11 @@ config ARM_VIC_NR
          The maximum number of VICs available in the system, for
          power management.
 
+config ORION_IRQCHIP
+       bool
+       select IRQ_DOMAIN
+       select MULTI_IRQ_HANDLER
+
 config RENESAS_INTC_IRQPIN
        bool
        select IRQ_DOMAIN
@@ -33,6 +43,11 @@ config RENESAS_IRQC
        bool
        select IRQ_DOMAIN
 
+config TB10X_IRQC
+       bool
+       select IRQ_DOMAIN
+       select GENERIC_IRQ_CHIP
+
 config VERSATILE_FPGA_IRQ
        bool
        select IRQ_DOMAIN
index cda4cb5f7327b77534a45776eb39b06f3c36a43c..2065ef6a949c15b2d5795cf1b96782724f3809ad 100644 (file)
@@ -7,12 +7,15 @@ obj-$(CONFIG_ARCH_MXS)                        += irq-mxs.o
 obj-$(CONFIG_ARCH_S3C24XX)             += irq-s3c24xx.o
 obj-$(CONFIG_METAG)                    += irq-metag-ext.o
 obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)   += irq-metag.o
+obj-$(CONFIG_ORION_IRQCHIP)            += irq-orion.o
 obj-$(CONFIG_ARCH_SUNXI)               += irq-sun4i.o
 obj-$(CONFIG_ARCH_SPEAR3XX)            += spear-shirq.o
 obj-$(CONFIG_ARM_GIC)                  += irq-gic.o
+obj-$(CONFIG_ARM_NVIC)                 += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)                  += irq-vic.o
 obj-$(CONFIG_SIRF_IRQ)                 += irq-sirfsoc.o
 obj-$(CONFIG_RENESAS_INTC_IRQPIN)      += irq-renesas-intc-irqpin.o
 obj-$(CONFIG_RENESAS_IRQC)             += irq-renesas-irqc.o
 obj-$(CONFIG_VERSATILE_FPGA_IRQ)       += irq-versatile-fpga.o
 obj-$(CONFIG_ARCH_VT8500)              += irq-vt8500.o
+obj-$(CONFIG_TB10X_IRQC)               += irq-tb10x.o
index a9d2b2fa4afd3149b261fb256fb47bcde79c81aa..4c6826513901f3e5f49148e5280addfee01974ae 100644 (file)
@@ -204,10 +204,10 @@ static unsigned int combiner_lookup_irq(int group)
        return 0;
 }
 
-void __init combiner_init(void __iomem *combiner_base,
-                         struct device_node *np,
-                         unsigned int max_nr,
-                         int irq_base)
+static void __init combiner_init(void __iomem *combiner_base,
+                                struct device_node *np,
+                                unsigned int max_nr,
+                                int irq_base)
 {
        int i, irq;
        unsigned int nr_irq;
diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c
new file mode 100644 (file)
index 0000000..8d0c8b3
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * drivers/irq/irq-nvic.c
+ *
+ * Copyright (C) 2008 ARM Limited, All Rights Reserved.
+ * Copyright (C) 2013 Pengutronix
+ *
+ * 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.
+ *
+ * Support for the Nested Vectored Interrupt Controller found on the
+ * ARMv7-M CPUs (Cortex-M3/M4)
+ */
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+
+#include <asm/v7m.h>
+#include <asm/exception.h>
+
+#include "irqchip.h"
+
+#define NVIC_ISER              0x000
+#define NVIC_ICER              0x080
+#define NVIC_IPR               0x300
+
+#define NVIC_MAX_BANKS         16
+/*
+ * Each bank handles 32 irqs. Only the 16th (= last) bank handles only
+ * 16 irqs.
+ */
+#define NVIC_MAX_IRQ           ((NVIC_MAX_BANKS - 1) * 32 + 16)
+
+static struct irq_domain *nvic_irq_domain;
+
+asmlinkage void __exception_irq_entry
+nvic_handle_irq(irq_hw_number_t hwirq, struct pt_regs *regs)
+{
+       unsigned int irq = irq_linear_revmap(nvic_irq_domain, hwirq);
+
+       handle_IRQ(irq, regs);
+}
+
+static void nvic_eoi(struct irq_data *d)
+{
+       /*
+        * This is a no-op as end of interrupt is signaled by the exception
+        * return sequence.
+        */
+}
+
+static int __init nvic_of_init(struct device_node *node,
+                              struct device_node *parent)
+{
+       unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+       unsigned int irqs, i, ret, numbanks;
+       void __iomem *nvic_base;
+
+       numbanks = (readl_relaxed(V7M_SCS_ICTR) &
+                   V7M_SCS_ICTR_INTLINESNUM_MASK) + 1;
+
+       nvic_base = of_iomap(node, 0);
+       if (!nvic_base) {
+               pr_warn("unable to map nvic registers\n");
+               return -ENOMEM;
+       }
+
+       irqs = numbanks * 32;
+       if (irqs > NVIC_MAX_IRQ)
+               irqs = NVIC_MAX_IRQ;
+
+       nvic_irq_domain =
+               irq_domain_add_linear(node, irqs, &irq_generic_chip_ops, NULL);
+       if (!nvic_irq_domain) {
+               pr_warn("Failed to allocate irq domain\n");
+               return -ENOMEM;
+       }
+
+       ret = irq_alloc_domain_generic_chips(nvic_irq_domain, 32, numbanks,
+                                            "nvic_irq", handle_fasteoi_irq,
+                                            clr, 0, IRQ_GC_INIT_MASK_CACHE);
+       if (ret) {
+               pr_warn("Failed to allocate irq chips\n");
+               irq_domain_remove(nvic_irq_domain);
+               return ret;
+       }
+
+       for (i = 0; i < numbanks; ++i) {
+               struct irq_chip_generic *gc;
+
+               gc = irq_get_domain_generic_chip(nvic_irq_domain, 32 * i);
+               gc->reg_base = nvic_base + 4 * i;
+               gc->chip_types[0].regs.enable = NVIC_ISER;
+               gc->chip_types[0].regs.disable = NVIC_ICER;
+               gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
+               gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
+               gc->chip_types[0].chip.irq_eoi = nvic_eoi;
+
+               /* disable interrupts */
+               writel_relaxed(~0, gc->reg_base + NVIC_ICER);
+       }
+
+       /* Set priority on all interrupts */
+       for (i = 0; i < irqs; i += 4)
+               writel_relaxed(0, nvic_base + NVIC_IPR + i);
+
+       return 0;
+}
+IRQCHIP_DECLARE(armv7m_nvic, "arm,armv7m-nvic", nvic_of_init);
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
new file mode 100644 (file)
index 0000000..e51d400
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Marvell Orion SoCs IRQ chip driver.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.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/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#include "irqchip.h"
+
+/*
+ * Orion SoC main interrupt controller
+ */
+#define ORION_IRQS_PER_CHIP            32
+
+#define ORION_IRQ_CAUSE                        0x00
+#define ORION_IRQ_MASK                 0x04
+#define ORION_IRQ_FIQ_MASK             0x08
+#define ORION_IRQ_ENDP_MASK            0x0c
+
+static struct irq_domain *orion_irq_domain;
+
+static asmlinkage void
+__exception_irq_entry orion_handle_irq(struct pt_regs *regs)
+{
+       struct irq_domain_chip_generic *dgc = orion_irq_domain->gc;
+       int n, base = 0;
+
+       for (n = 0; n < dgc->num_chips; n++, base += ORION_IRQS_PER_CHIP) {
+               struct irq_chip_generic *gc =
+                       irq_get_domain_generic_chip(orion_irq_domain, base);
+               u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) &
+                       gc->mask_cache;
+               while (stat) {
+                       u32 hwirq = ffs(stat) - 1;
+                       u32 irq = irq_find_mapping(orion_irq_domain,
+                                                  gc->irq_base + hwirq);
+                       handle_IRQ(irq, regs);
+                       stat &= ~(1 << hwirq);
+               }
+       }
+}
+
+static int __init orion_irq_init(struct device_node *np,
+                                struct device_node *parent)
+{
+       unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+       int n, ret, base, num_chips = 0;
+       struct resource r;
+
+       /* count number of irq chips by valid reg addresses */
+       while (of_address_to_resource(np, num_chips, &r) == 0)
+               num_chips++;
+
+       orion_irq_domain = irq_domain_add_linear(np,
+                               num_chips * ORION_IRQS_PER_CHIP,
+                               &irq_generic_chip_ops, NULL);
+       if (!orion_irq_domain)
+               panic("%s: unable to add irq domain\n", np->name);
+
+       ret = irq_alloc_domain_generic_chips(orion_irq_domain,
+                               ORION_IRQS_PER_CHIP, 1, np->name,
+                               handle_level_irq, clr, 0,
+                               IRQ_GC_INIT_MASK_CACHE);
+       if (ret)
+               panic("%s: unable to alloc irq domain gc\n", np->name);
+
+       for (n = 0, base = 0; n < num_chips; n++, base += ORION_IRQS_PER_CHIP) {
+               struct irq_chip_generic *gc =
+                       irq_get_domain_generic_chip(orion_irq_domain, base);
+
+               of_address_to_resource(np, n, &r);
+
+               if (!request_mem_region(r.start, resource_size(&r), np->name))
+                       panic("%s: unable to request mem region %d",
+                             np->name, n);
+
+               gc->reg_base = ioremap(r.start, resource_size(&r));
+               if (!gc->reg_base)
+                       panic("%s: unable to map resource %d", np->name, n);
+
+               gc->chip_types[0].regs.mask = ORION_IRQ_MASK;
+               gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+               gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+               /* mask all interrupts */
+               writel(0, gc->reg_base + ORION_IRQ_MASK);
+       }
+
+       set_handle_irq(orion_handle_irq);
+       return 0;
+}
+IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);
+
+/*
+ * Orion SoC bridge interrupt controller
+ */
+#define ORION_BRIDGE_IRQ_CAUSE 0x00
+#define ORION_BRIDGE_IRQ_MASK  0x04
+
+static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_domain *d = irq_get_handler_data(irq);
+       struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
+       u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
+                  gc->mask_cache;
+
+       while (stat) {
+               u32 hwirq = ffs(stat) - 1;
+
+               generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq));
+               stat &= ~(1 << hwirq);
+       }
+}
+
+static int __init orion_bridge_irq_init(struct device_node *np,
+                                       struct device_node *parent)
+{
+       unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+       struct resource r;
+       struct irq_domain *domain;
+       struct irq_chip_generic *gc;
+       int ret, irq, nrirqs = 32;
+
+       /* get optional number of interrupts provided */
+       of_property_read_u32(np, "marvell,#interrupts", &nrirqs);
+
+       domain = irq_domain_add_linear(np, nrirqs,
+                                      &irq_generic_chip_ops, NULL);
+       if (!domain) {
+               pr_err("%s: unable to add irq domain\n", np->name);
+               return -ENOMEM;
+       }
+
+       ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name,
+                            handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+       if (ret) {
+               pr_err("%s: unable to alloc irq domain gc\n", np->name);
+               return ret;
+       }
+
+       ret = of_address_to_resource(np, 0, &r);
+       if (ret) {
+               pr_err("%s: unable to get resource\n", np->name);
+               return ret;
+       }
+
+       if (!request_mem_region(r.start, resource_size(&r), np->name)) {
+               pr_err("%s: unable to request mem region\n", np->name);
+               return -ENOMEM;
+       }
+
+       /* Map the parent interrupt for the chained handler */
+       irq = irq_of_parse_and_map(np, 0);
+       if (irq <= 0) {
+               pr_err("%s: unable to parse irq\n", np->name);
+               return -EINVAL;
+       }
+
+       gc = irq_get_domain_generic_chip(domain, 0);
+       gc->reg_base = ioremap(r.start, resource_size(&r));
+       if (!gc->reg_base) {
+               pr_err("%s: unable to map resource\n", np->name);
+               return -ENOMEM;
+       }
+
+       gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE;
+       gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK;
+       gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
+       gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+       gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+       /* mask all interrupts */
+       writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK);
+
+       irq_set_handler_data(irq, domain);
+       irq_set_chained_handler(irq, orion_bridge_irq_handler);
+
+       return 0;
+}
+IRQCHIP_DECLARE(orion_bridge_intc,
+               "marvell,orion-bridge-intc", orion_bridge_irq_init);
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
new file mode 100644 (file)
index 0000000..7c44c99
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Abilis Systems interrupt controller driver
+ *
+ * Copyright (C) Abilis Systems 2012
+ *
+ * Author: Christian Ruppert <christian.ruppert@abilis.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include "irqchip.h"
+
+#define AB_IRQCTL_INT_ENABLE   0x00
+#define AB_IRQCTL_INT_STATUS   0x04
+#define AB_IRQCTL_SRC_MODE     0x08
+#define AB_IRQCTL_SRC_POLARITY 0x0C
+#define AB_IRQCTL_INT_MODE     0x10
+#define AB_IRQCTL_INT_POLARITY 0x14
+#define AB_IRQCTL_INT_FORCE    0x18
+
+#define AB_IRQCTL_MAXIRQ       32
+
+static inline void ab_irqctl_writereg(struct irq_chip_generic *gc, u32 reg,
+       u32 val)
+{
+       irq_reg_writel(val, gc->reg_base + reg);
+}
+
+static inline u32 ab_irqctl_readreg(struct irq_chip_generic *gc, u32 reg)
+{
+       return irq_reg_readl(gc->reg_base + reg);
+}
+
+static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+       uint32_t im, mod, pol;
+
+       im = data->mask;
+
+       irq_gc_lock(gc);
+
+       mod = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_MODE) | im;
+       pol = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_POLARITY) | im;
+
+       switch (flow_type & IRQF_TRIGGER_MASK) {
+       case IRQ_TYPE_EDGE_FALLING:
+               pol ^= im;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               mod ^= im;
+               break;
+       case IRQ_TYPE_NONE:
+               flow_type = IRQ_TYPE_LEVEL_LOW;
+       case IRQ_TYPE_LEVEL_LOW:
+               mod ^= im;
+               pol ^= im;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               break;
+       default:
+               irq_gc_unlock(gc);
+               pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
+                       __func__, data->irq);
+               return -EBADR;
+       }
+
+       irqd_set_trigger_type(data, flow_type);
+       irq_setup_alt_chip(data, flow_type);
+
+       ab_irqctl_writereg(gc, AB_IRQCTL_SRC_MODE, mod);
+       ab_irqctl_writereg(gc, AB_IRQCTL_SRC_POLARITY, pol);
+       ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, im);
+
+       irq_gc_unlock(gc);
+
+       return IRQ_SET_MASK_OK;
+}
+
+static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_domain *domain = irq_desc_get_handler_data(desc);
+
+       generic_handle_irq(irq_find_mapping(domain, irq));
+}
+
+static int __init of_tb10x_init_irq(struct device_node *ictl,
+                                       struct device_node *parent)
+{
+       int i, ret, nrirqs = of_irq_count(ictl);
+       struct resource mem;
+       struct irq_chip_generic *gc;
+       struct irq_domain *domain;
+       void __iomem *reg_base;
+
+       if (of_address_to_resource(ictl, 0, &mem)) {
+               pr_err("%s: No registers declared in DeviceTree.\n",
+                       ictl->name);
+               return -EINVAL;
+       }
+
+       if (!request_mem_region(mem.start, resource_size(&mem),
+               ictl->name)) {
+               pr_err("%s: Request mem region failed.\n", ictl->name);
+               return -EBUSY;
+       }
+
+       reg_base = ioremap(mem.start, resource_size(&mem));
+       if (!reg_base) {
+               ret = -EBUSY;
+               pr_err("%s: ioremap failed.\n", ictl->name);
+               goto ioremap_fail;
+       }
+
+       domain = irq_domain_add_linear(ictl, AB_IRQCTL_MAXIRQ,
+                                       &irq_generic_chip_ops, NULL);
+       if (!domain) {
+               ret = -ENOMEM;
+               pr_err("%s: Could not register interrupt domain.\n",
+                       ictl->name);
+               goto irq_domain_add_fail;
+       }
+
+       ret = irq_alloc_domain_generic_chips(domain, AB_IRQCTL_MAXIRQ,
+                               2, ictl->name, handle_level_irq,
+                               IRQ_NOREQUEST, IRQ_NOPROBE,
+                               IRQ_GC_INIT_MASK_CACHE);
+       if (ret) {
+               pr_err("%s: Could not allocate generic interrupt chip.\n",
+                       ictl->name);
+               goto gc_alloc_fail;
+       }
+
+       gc = domain->gc->gc[0];
+       gc->reg_base                         = reg_base;
+
+       gc->chip_types[0].type               = IRQ_TYPE_LEVEL_MASK;
+       gc->chip_types[0].chip.irq_mask      = irq_gc_mask_clr_bit;
+       gc->chip_types[0].chip.irq_unmask    = irq_gc_mask_set_bit;
+       gc->chip_types[0].chip.irq_set_type  = tb10x_irq_set_type;
+       gc->chip_types[0].regs.mask          = AB_IRQCTL_INT_ENABLE;
+
+       gc->chip_types[1].type               = IRQ_TYPE_EDGE_BOTH;
+       gc->chip_types[1].chip.name          = gc->chip_types[0].chip.name;
+       gc->chip_types[1].chip.irq_ack       = irq_gc_ack_set_bit;
+       gc->chip_types[1].chip.irq_mask      = irq_gc_mask_clr_bit;
+       gc->chip_types[1].chip.irq_unmask    = irq_gc_mask_set_bit;
+       gc->chip_types[1].chip.irq_set_type  = tb10x_irq_set_type;
+       gc->chip_types[1].regs.ack           = AB_IRQCTL_INT_STATUS;
+       gc->chip_types[1].regs.mask          = AB_IRQCTL_INT_ENABLE;
+       gc->chip_types[1].handler            = handle_edge_irq;
+
+       for (i = 0; i < nrirqs; i++) {
+               unsigned int irq = irq_of_parse_and_map(ictl, i);
+
+               irq_set_handler_data(irq, domain);
+               irq_set_chained_handler(irq, tb10x_irq_cascade);
+       }
+
+       ab_irqctl_writereg(gc, AB_IRQCTL_INT_ENABLE, 0);
+       ab_irqctl_writereg(gc, AB_IRQCTL_INT_MODE, 0);
+       ab_irqctl_writereg(gc, AB_IRQCTL_INT_POLARITY, 0);
+       ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, ~0UL);
+
+       return 0;
+
+gc_alloc_fail:
+       irq_domain_remove(domain);
+irq_domain_add_fail:
+       iounmap(reg_base);
+ioremap_fail:
+       release_mem_region(mem.start, resource_size(&mem));
+       return ret;
+}
+IRQCHIP_DECLARE(tb10x_intc, "abilis,tb10x-ictl", of_tb10x_init_irq);
index 88305c9cbff5334a474345a16860b6f727d3e614..8b1a66c6ca8aa0e3c5a647945ba895172d3a4974 100644 (file)
@@ -102,7 +102,7 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
        entry->dev.class = elements_class;
        entry->dev.release = mISDN_dsp_dev_release;
        dev_set_drvdata(&entry->dev, elem);
-       dev_set_name(&entry->dev, elem->name);
+       dev_set_name(&entry->dev, "%s", elem->name);
        ret = device_register(&entry->dev);
        if (ret) {
                printk(KERN_ERR "%s: failed to register %s\n",
index ef992293598a6d71296c28209e116cbbea75b026..e43402dd1dead6aa6e2e77cc4b392287402727a0 100644 (file)
@@ -388,12 +388,12 @@ config LEDS_DELL_NETBOOKS
          notebooks that have an external LED.
 
 config LEDS_MC13783
-       tristate "LED Support for MC13783 PMIC"
+       tristate "LED Support for MC13XXX PMIC"
        depends on LEDS_CLASS
-       depends on MFD_MC13783
+       depends on MFD_MC13XXX
        help
          This option enable support for on-chip LED drivers found
-         on Freescale Semiconductor MC13783 PMIC.
+         on Freescale Semiconductor MC13783/MC13892 PMIC.
 
 config LEDS_NS2
        tristate "LED support for Network Space v2 GPIO LEDs"
index a20752f562bce37315c984f914660691c14ec0d0..4336e37a97f498266de1cfd14857f01731a23714 100644 (file)
@@ -156,7 +156,7 @@ void led_classdev_resume(struct led_classdev *led_cdev)
 }
 EXPORT_SYMBOL_GPL(led_classdev_resume);
 
-static int led_suspend(struct device *dev, pm_message_t state)
+static int led_suspend(struct device *dev)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
 
@@ -176,6 +176,11 @@ static int led_resume(struct device *dev)
        return 0;
 }
 
+static const struct dev_pm_ops leds_class_dev_pm_ops = {
+       .suspend        = led_suspend,
+       .resume         = led_resume,
+};
+
 /**
  * led_classdev_register - register a new object of led_classdev class.
  * @parent: The device to register.
@@ -252,8 +257,7 @@ static int __init leds_init(void)
        leds_class = class_create(THIS_MODULE, "leds");
        if (IS_ERR(leds_class))
                return PTR_ERR(leds_class);
-       leds_class->suspend = led_suspend;
-       leds_class->resume = led_resume;
+       leds_class->pm = &leds_class_dev_pm_ops;
        leds_class->dev_attrs = led_class_attrs;
        return 0;
 }
index f5b9ea31579009f2c745d8678c41b336a038a23b..232b3ce902e55f6d3c7ea696a93808121e304ace 100644 (file)
@@ -204,7 +204,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
                sprintf(data->name, "led1-blue");
                break;
        }
-       dev_set_drvdata(&pdev->dev, data);
+       platform_set_drvdata(pdev, data);
        data->chip = chip;
        data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
        data->port = pdev->id;
index 8a39c5b20f76811731b73e12db54631fa88b2396..90518f84b9c07aeacf06664c0adcf32671512269 100644 (file)
@@ -129,7 +129,6 @@ static int pwmled_remove(struct platform_device *pdev)
                pwm_channel_free(&led->pwmc);
        }
 
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index b02b679abf3183a7b6d798c212ed21b349453548..84d74c373cae89cd046554f653b7da34fb761a64 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/module.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/err.h>
 
 struct gpio_led_data {
@@ -236,13 +235,8 @@ static int gpio_led_probe(struct platform_device *pdev)
 {
        struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
        struct gpio_leds_priv *priv;
-       struct pinctrl *pinctrl;
        int i, ret = 0;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl))
-               dev_warn(&pdev->dev,
-                       "pins are not configured from the driver\n");
 
        if (pdata && pdata->num_leds) {
                priv = devm_kzalloc(&pdev->dev,
@@ -282,8 +276,6 @@ static int gpio_led_remove(struct platform_device *pdev)
        for (i = 0; i < priv->num_leds; i++)
                delete_gpio_led(&priv->leds[i]);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 19752c928aa2d6f99c2d15383fae905414f0bcdc..1392feb1bcf7849559ba29b38f163afa01a305bb 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/mutex.h>
 #include <linux/platform_data/leds-lp55xx.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 #include "leds-lp55xx-common.h"
 
@@ -416,12 +417,20 @@ static int lp5521_probe(struct i2c_client *client,
        int ret;
        struct lp55xx_chip *chip;
        struct lp55xx_led *led;
-       struct lp55xx_platform_data *pdata = client->dev.platform_data;
-
-       if (!pdata) {
-               dev_err(&client->dev, "no platform data\n");
-               return -EINVAL;
+       struct lp55xx_platform_data *pdata;
+       struct device_node *np = client->dev.of_node;
+
+       if (!client->dev.platform_data) {
+               if (np) {
+                       ret = lp55xx_of_populate_pdata(&client->dev, np);
+                       if (ret < 0)
+                               return ret;
+               } else {
+                       dev_err(&client->dev, "no platform data\n");
+                       return -EINVAL;
+               }
        }
+       pdata = client->dev.platform_data;
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
@@ -485,9 +494,18 @@ static const struct i2c_device_id lp5521_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, lp5521_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id of_lp5521_leds_match[] = {
+       { .compatible = "national,lp5521", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, of_lp5521_leds_match);
+#endif
 static struct i2c_driver lp5521_driver = {
        .driver = {
                .name   = "lp5521",
+               .of_match_table = of_match_ptr(of_lp5521_leds_match),
        },
        .probe          = lp5521_probe,
        .remove         = lp5521_remove,
index 229f734040af8a8669f029583aa8d739e266798f..3979428f3100ab9d274a5e3bb3afa1333399efee 100644 (file)
@@ -429,12 +429,20 @@ static int lp5523_probe(struct i2c_client *client,
        int ret;
        struct lp55xx_chip *chip;
        struct lp55xx_led *led;
-       struct lp55xx_platform_data *pdata = client->dev.platform_data;
-
-       if (!pdata) {
-               dev_err(&client->dev, "no platform data\n");
-               return -EINVAL;
+       struct lp55xx_platform_data *pdata;
+       struct device_node *np = client->dev.of_node;
+
+       if (!client->dev.platform_data) {
+               if (np) {
+                       ret = lp55xx_of_populate_pdata(&client->dev, np);
+                       if (ret < 0)
+                               return ret;
+               } else {
+                       dev_err(&client->dev, "no platform data\n");
+                       return -EINVAL;
+               }
        }
+       pdata = client->dev.platform_data;
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
@@ -500,9 +508,19 @@ static const struct i2c_device_id lp5523_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, lp5523_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id of_lp5523_leds_match[] = {
+       { .compatible = "national,lp5523", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, of_lp5523_leds_match);
+#endif
+
 static struct i2c_driver lp5523_driver = {
        .driver = {
                .name   = "lp5523x",
+               .of_match_table = of_match_ptr(of_lp5523_leds_match),
        },
        .probe          = lp5523_probe,
        .remove         = lp5523_remove,
index 513f2390ca2d8d279079c2939c109dae06c05f45..cbd856dac15041c3c6396741aa7913bfee85ab34 100644 (file)
@@ -515,12 +515,20 @@ static int lp5562_probe(struct i2c_client *client,
        int ret;
        struct lp55xx_chip *chip;
        struct lp55xx_led *led;
-       struct lp55xx_platform_data *pdata = client->dev.platform_data;
-
-       if (!pdata) {
-               dev_err(&client->dev, "no platform data\n");
-               return -EINVAL;
+       struct lp55xx_platform_data *pdata;
+       struct device_node *np = client->dev.of_node;
+
+       if (!client->dev.platform_data) {
+               if (np) {
+                       ret = lp55xx_of_populate_pdata(&client->dev, np);
+                       if (ret < 0)
+                               return ret;
+               } else {
+                       dev_err(&client->dev, "no platform data\n");
+                       return -EINVAL;
+               }
        }
+       pdata = client->dev.platform_data;
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
@@ -583,9 +591,19 @@ static const struct i2c_device_id lp5562_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, lp5562_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id of_lp5562_leds_match[] = {
+       { .compatible = "ti,lp5562", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, of_lp5562_leds_match);
+#endif
+
 static struct i2c_driver lp5562_driver = {
        .driver = {
                .name   = "lp5562",
+               .of_match_table = of_match_ptr(of_lp5562_leds_match),
        },
        .probe          = lp5562_probe,
        .remove         = lp5562_remove,
index ba34199dc3d93e51a2b83526db61db2658f5e7b0..c2fecd4d391ce33cee56aad60d3d1d80a62ffc02 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/platform_data/leds-lp55xx.h>
+#include <linux/slab.h>
 
 #include "leds-lp55xx-common.h"
 
@@ -554,6 +555,50 @@ void lp55xx_unregister_sysfs(struct lp55xx_chip *chip)
 }
 EXPORT_SYMBOL_GPL(lp55xx_unregister_sysfs);
 
+int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np)
+{
+       struct device_node *child;
+       struct lp55xx_platform_data *pdata;
+       struct lp55xx_led_config *cfg;
+       int num_channels;
+       int i = 0;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       num_channels = of_get_child_count(np);
+       if (num_channels == 0) {
+               dev_err(dev, "no LED channels\n");
+               return -EINVAL;
+       }
+
+       cfg = devm_kzalloc(dev, sizeof(*cfg) * num_channels, GFP_KERNEL);
+       if (!cfg)
+               return -ENOMEM;
+
+       pdata->led_config = &cfg[0];
+       pdata->num_channels = num_channels;
+
+       for_each_child_of_node(np, child) {
+               cfg[i].chan_nr = i;
+
+               of_property_read_string(child, "chan-name", &cfg[i].name);
+               of_property_read_u8(child, "led-cur", &cfg[i].led_current);
+               of_property_read_u8(child, "max-cur", &cfg[i].max_current);
+
+               i++;
+       }
+
+       of_property_read_string(np, "label", &pdata->label);
+       of_property_read_u8(np, "clock-mode", &pdata->clock_mode);
+
+       dev->platform_data = pdata;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lp55xx_of_populate_pdata);
+
 MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
 MODULE_DESCRIPTION("LP55xx Common Driver");
 MODULE_LICENSE("GPL");
index fa6a078bf5471131f14ac1e4d7d1091fa87c36e4..dbbf86df0f1fcdbe4d14de589b7fc90ef85f1a24 100644 (file)
@@ -135,4 +135,8 @@ extern void lp55xx_unregister_leds(struct lp55xx_led *led,
 extern int lp55xx_register_sysfs(struct lp55xx_chip *chip);
 extern void lp55xx_unregister_sysfs(struct lp55xx_chip *chip);
 
+/* common device tree population function */
+extern int lp55xx_of_populate_pdata(struct device *dev,
+                                   struct device_node *np);
+
 #endif /* _LEDS_LP55XX_COMMON_H */
index e942adaa750410c844468ad3bee7d139572c2442..fa9b439323bd06d0d126a48a7828e4b47665c6b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * LEDs driver for Freescale MC13783
+ * LEDs driver for Freescale MC13783/MC13892
  *
  * Copyright (C) 2010 Philippe Rétornaz
  *
 #include <linux/leds.h>
 #include <linux/workqueue.h>
 #include <linux/mfd/mc13xxx.h>
-#include <linux/slab.h>
 
-struct mc13783_led {
+#define MC13XXX_REG_LED_CONTROL(x)     (51 + (x))
+
+struct mc13xxx_led_devtype {
+       int     led_min;
+       int     led_max;
+       int     num_regs;
+};
+
+struct mc13xxx_led {
        struct led_classdev     cdev;
        struct work_struct      work;
        struct mc13xxx          *master;
@@ -32,66 +39,35 @@ struct mc13783_led {
        int                     id;
 };
 
-#define MC13783_REG_LED_CONTROL_0      51
-#define MC13783_LED_C0_ENABLE_BIT      (1 << 0)
-#define MC13783_LED_C0_TRIODE_MD_BIT   (1 << 7)
-#define MC13783_LED_C0_TRIODE_AD_BIT   (1 << 8)
-#define MC13783_LED_C0_TRIODE_KP_BIT   (1 << 9)
-#define MC13783_LED_C0_BOOST_BIT       (1 << 10)
-#define MC13783_LED_C0_ABMODE_MASK     0x7
-#define MC13783_LED_C0_ABMODE          11
-#define MC13783_LED_C0_ABREF_MASK      0x3
-#define MC13783_LED_C0_ABREF           14
-
-#define MC13783_REG_LED_CONTROL_1      52
-#define MC13783_LED_C1_TC1HALF_BIT     (1 << 18)
-
-#define MC13783_REG_LED_CONTROL_2      53
-#define MC13783_LED_C2_BL_P_MASK       0xf
-#define MC13783_LED_C2_MD_P            9
-#define MC13783_LED_C2_AD_P            13
-#define MC13783_LED_C2_KP_P            17
-#define MC13783_LED_C2_BL_C_MASK       0x7
-#define MC13783_LED_C2_MD_C            0
-#define MC13783_LED_C2_AD_C            3
-#define MC13783_LED_C2_KP_C            6
-
-#define MC13783_REG_LED_CONTROL_3      54
-#define MC13783_LED_C3_TC_P            6
-#define MC13783_LED_C3_TC_P_MASK       0x1f
-
-#define MC13783_REG_LED_CONTROL_4      55
-#define MC13783_REG_LED_CONTROL_5      56
-
-#define MC13783_LED_Cx_PERIOD          21
-#define MC13783_LED_Cx_PERIOD_MASK     0x3
-#define MC13783_LED_Cx_SLEWLIM_BIT      (1 << 23)
-#define MC13783_LED_Cx_TRIODE_TC_BIT   (1 << 23)
-#define MC13783_LED_Cx_TC_C_MASK       0x3
-
-static void mc13783_led_work(struct work_struct *work)
+struct mc13xxx_leds {
+       struct mc13xxx_led_devtype      *devtype;
+       int                             num_leds;
+       struct mc13xxx_led              led[0];
+};
+
+static void mc13xxx_led_work(struct work_struct *work)
 {
-       struct mc13783_led *led = container_of(work, struct mc13783_led, work);
-       int reg = 0;
-       int mask = 0;
-       int value = 0;
-       int bank, off, shift;
+       struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work);
+       int reg, mask, value, bank, off, shift;
 
        switch (led->id) {
        case MC13783_LED_MD:
-               reg = MC13783_REG_LED_CONTROL_2;
-               mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_MD_P;
-               value = (led->new_brightness >> 4) << MC13783_LED_C2_MD_P;
+               reg = MC13XXX_REG_LED_CONTROL(2);
+               shift = 9;
+               mask = 0x0f;
+               value = led->new_brightness >> 4;
                break;
        case MC13783_LED_AD:
-               reg = MC13783_REG_LED_CONTROL_2;
-               mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_AD_P;
-               value = (led->new_brightness >> 4) << MC13783_LED_C2_AD_P;
+               reg = MC13XXX_REG_LED_CONTROL(2);
+               shift = 13;
+               mask = 0x0f;
+               value = led->new_brightness >> 4;
                break;
        case MC13783_LED_KP:
-               reg = MC13783_REG_LED_CONTROL_2;
-               mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_KP_P;
-               value = (led->new_brightness >> 4) << MC13783_LED_C2_KP_P;
+               reg = MC13XXX_REG_LED_CONTROL(2);
+               shift = 17;
+               mask = 0x0f;
+               value = led->new_brightness >> 4;
                break;
        case MC13783_LED_R1:
        case MC13783_LED_G1:
@@ -103,57 +79,78 @@ static void mc13783_led_work(struct work_struct *work)
        case MC13783_LED_G3:
        case MC13783_LED_B3:
                off = led->id - MC13783_LED_R1;
-               bank = off/3;
-               reg = MC13783_REG_LED_CONTROL_3 + off/3;
-               shift = (off - bank * 3) * 5 + MC13783_LED_C3_TC_P;
-               value = (led->new_brightness >> 3) << shift;
-               mask = MC13783_LED_C3_TC_P_MASK << shift;
+               bank = off / 3;
+               reg = MC13XXX_REG_LED_CONTROL(3) + bank;
+               shift = (off - bank * 3) * 5 + 6;
+               value = led->new_brightness >> 3;
+               mask = 0x1f;
+               break;
+       case MC13892_LED_MD:
+               reg = MC13XXX_REG_LED_CONTROL(0);
+               shift = 3;
+               mask = 0x3f;
+               value = led->new_brightness >> 2;
+               break;
+       case MC13892_LED_AD:
+               reg = MC13XXX_REG_LED_CONTROL(0);
+               shift = 15;
+               mask = 0x3f;
+               value = led->new_brightness >> 2;
+               break;
+       case MC13892_LED_KP:
+               reg = MC13XXX_REG_LED_CONTROL(1);
+               shift = 3;
+               mask = 0x3f;
+               value = led->new_brightness >> 2;
                break;
+       case MC13892_LED_R:
+       case MC13892_LED_G:
+       case MC13892_LED_B:
+               off = led->id - MC13892_LED_R;
+               bank = off / 2;
+               reg = MC13XXX_REG_LED_CONTROL(2) + bank;
+               shift = (off - bank * 2) * 12 + 3;
+               value = led->new_brightness >> 2;
+               mask = 0x3f;
+               break;
+       default:
+               BUG();
        }
 
        mc13xxx_lock(led->master);
-
-       mc13xxx_reg_rmw(led->master, reg, mask, value);
-
+       mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift);
        mc13xxx_unlock(led->master);
 }
 
-static void mc13783_led_set(struct led_classdev *led_cdev,
-                          enum led_brightness value)
+static void mc13xxx_led_set(struct led_classdev *led_cdev,
+                           enum led_brightness value)
 {
-       struct mc13783_led *led;
+       struct mc13xxx_led *led =
+               container_of(led_cdev, struct mc13xxx_led, cdev);
 
-       led = container_of(led_cdev, struct mc13783_led, cdev);
        led->new_brightness = value;
        schedule_work(&led->work);
 }
 
-static int mc13783_led_setup(struct mc13783_led *led, int max_current)
+static int __init mc13xxx_led_setup(struct mc13xxx_led *led, int max_current)
 {
-       int shift = 0;
-       int mask = 0;
-       int value = 0;
-       int reg = 0;
-       int ret, bank;
+       int shift, mask, reg, ret, bank;
 
        switch (led->id) {
        case MC13783_LED_MD:
-               shift = MC13783_LED_C2_MD_C;
-               mask = MC13783_LED_C2_BL_C_MASK;
-               value = max_current & MC13783_LED_C2_BL_C_MASK;
-               reg = MC13783_REG_LED_CONTROL_2;
+               reg = MC13XXX_REG_LED_CONTROL(2);
+               shift = 0;
+               mask = 0x07;
                break;
        case MC13783_LED_AD:
-               shift = MC13783_LED_C2_AD_C;
-               mask = MC13783_LED_C2_BL_C_MASK;
-               value = max_current & MC13783_LED_C2_BL_C_MASK;
-               reg = MC13783_REG_LED_CONTROL_2;
+               reg = MC13XXX_REG_LED_CONTROL(2);
+               shift = 3;
+               mask = 0x07;
                break;
        case MC13783_LED_KP:
-               shift = MC13783_LED_C2_KP_C;
-               mask = MC13783_LED_C2_BL_C_MASK;
-               value = max_current & MC13783_LED_C2_BL_C_MASK;
-               reg = MC13783_REG_LED_CONTROL_2;
+               reg = MC13XXX_REG_LED_CONTROL(2);
+               shift = 6;
+               mask = 0x07;
                break;
        case MC13783_LED_R1:
        case MC13783_LED_G1:
@@ -164,229 +161,195 @@ static int mc13783_led_setup(struct mc13783_led *led, int max_current)
        case MC13783_LED_R3:
        case MC13783_LED_G3:
        case MC13783_LED_B3:
-               bank = (led->id - MC13783_LED_R1)/3;
-               reg = MC13783_REG_LED_CONTROL_3 + bank;
+               bank = (led->id - MC13783_LED_R1) / 3;
+               reg = MC13XXX_REG_LED_CONTROL(3) + bank;
                shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2;
-               mask = MC13783_LED_Cx_TC_C_MASK;
-               value = max_current & MC13783_LED_Cx_TC_C_MASK;
+               mask = 0x03;
+               break;
+       case MC13892_LED_MD:
+               reg = MC13XXX_REG_LED_CONTROL(0);
+               shift = 9;
+               mask = 0x07;
                break;
+       case MC13892_LED_AD:
+               reg = MC13XXX_REG_LED_CONTROL(0);
+               shift = 21;
+               mask = 0x07;
+               break;
+       case MC13892_LED_KP:
+               reg = MC13XXX_REG_LED_CONTROL(1);
+               shift = 9;
+               mask = 0x07;
+               break;
+       case MC13892_LED_R:
+       case MC13892_LED_G:
+       case MC13892_LED_B:
+               bank = (led->id - MC13892_LED_R) / 2;
+               reg = MC13XXX_REG_LED_CONTROL(2) + bank;
+               shift = ((led->id - MC13892_LED_R) - bank * 2) * 12 + 9;
+               mask = 0x07;
+               break;
+       default:
+               BUG();
        }
 
        mc13xxx_lock(led->master);
-
        ret = mc13xxx_reg_rmw(led->master, reg, mask << shift,
-                                               value << shift);
-
+                             max_current << shift);
        mc13xxx_unlock(led->master);
-       return ret;
-}
-
-static int mc13783_leds_prepare(struct platform_device *pdev)
-{
-       struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       struct mc13xxx *dev = dev_get_drvdata(pdev->dev.parent);
-       int ret = 0;
-       int reg = 0;
-
-       mc13xxx_lock(dev);
-
-       if (pdata->flags & MC13783_LED_TC1HALF)
-               reg |= MC13783_LED_C1_TC1HALF_BIT;
-
-       if (pdata->flags & MC13783_LED_SLEWLIMTC)
-               reg |= MC13783_LED_Cx_SLEWLIM_BIT;
-
-       ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_1, reg);
-       if (ret)
-               goto out;
-
-       reg = (pdata->bl_period & MC13783_LED_Cx_PERIOD_MASK) <<
-                                                       MC13783_LED_Cx_PERIOD;
-
-       if (pdata->flags & MC13783_LED_SLEWLIMBL)
-               reg |= MC13783_LED_Cx_SLEWLIM_BIT;
-
-       ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_2, reg);
-       if (ret)
-               goto out;
-
-       reg = (pdata->tc1_period & MC13783_LED_Cx_PERIOD_MASK) <<
-                                                       MC13783_LED_Cx_PERIOD;
 
-       if (pdata->flags & MC13783_LED_TRIODE_TC1)
-               reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
-
-       ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_3, reg);
-       if (ret)
-               goto out;
-
-       reg = (pdata->tc2_period & MC13783_LED_Cx_PERIOD_MASK) <<
-                                                       MC13783_LED_Cx_PERIOD;
-
-       if (pdata->flags & MC13783_LED_TRIODE_TC2)
-               reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
-
-       ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_4, reg);
-       if (ret)
-               goto out;
-
-       reg = (pdata->tc3_period & MC13783_LED_Cx_PERIOD_MASK) <<
-                                                       MC13783_LED_Cx_PERIOD;
-
-       if (pdata->flags & MC13783_LED_TRIODE_TC3)
-               reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
-
-       ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_5, reg);
-       if (ret)
-               goto out;
-
-       reg = MC13783_LED_C0_ENABLE_BIT;
-       if (pdata->flags & MC13783_LED_TRIODE_MD)
-               reg |= MC13783_LED_C0_TRIODE_MD_BIT;
-       if (pdata->flags & MC13783_LED_TRIODE_AD)
-               reg |= MC13783_LED_C0_TRIODE_AD_BIT;
-       if (pdata->flags & MC13783_LED_TRIODE_KP)
-               reg |= MC13783_LED_C0_TRIODE_KP_BIT;
-       if (pdata->flags & MC13783_LED_BOOST_EN)
-               reg |= MC13783_LED_C0_BOOST_BIT;
-
-       reg |= (pdata->abmode & MC13783_LED_C0_ABMODE_MASK) <<
-                                                       MC13783_LED_C0_ABMODE;
-       reg |= (pdata->abref & MC13783_LED_C0_ABREF_MASK) <<
-                                                       MC13783_LED_C0_ABREF;
-
-       ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_0, reg);
-
-out:
-       mc13xxx_unlock(dev);
        return ret;
 }
 
-static int mc13783_led_probe(struct platform_device *pdev)
+static int __init mc13xxx_led_probe(struct platform_device *pdev)
 {
        struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       struct mc13xxx_led_platform_data *led_cur;
-       struct mc13783_led *led, *led_dat;
-       int ret, i;
-       int init_led = 0;
-
-       if (pdata == NULL) {
-               dev_err(&pdev->dev, "missing platform data\n");
+       struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent);
+       struct mc13xxx_led_devtype *devtype =
+               (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data;
+       struct mc13xxx_leds *leds;
+       int i, id, num_leds, ret = -ENODATA;
+       u32 reg, init_led = 0;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "Missing platform data\n");
                return -ENODEV;
        }
 
-       if (pdata->num_leds < 1 || pdata->num_leds > (MC13783_LED_MAX + 1)) {
-               dev_err(&pdev->dev, "Invalid led count %d\n", pdata->num_leds);
+       num_leds = pdata->num_leds;
+
+       if ((num_leds < 1) ||
+           (num_leds > (devtype->led_max - devtype->led_min + 1))) {
+               dev_err(&pdev->dev, "Invalid LED count %d\n", num_leds);
                return -EINVAL;
        }
 
-       led = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*led),
-                               GFP_KERNEL);
-       if (led == NULL) {
-               dev_err(&pdev->dev, "failed to alloc memory\n");
+       leds = devm_kzalloc(&pdev->dev, num_leds * sizeof(struct mc13xxx_led) +
+                           sizeof(struct mc13xxx_leds), GFP_KERNEL);
+       if (!leds)
                return -ENOMEM;
+
+       leds->devtype = devtype;
+       leds->num_leds = num_leds;
+       platform_set_drvdata(pdev, leds);
+
+       mc13xxx_lock(mcdev);
+       for (i = 0; i < devtype->num_regs; i++) {
+               reg = pdata->led_control[i];
+               WARN_ON(reg >= (1 << 24));
+               ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg);
+               if (ret)
+                       break;
        }
+       mc13xxx_unlock(mcdev);
 
-       ret = mc13783_leds_prepare(pdev);
        if (ret) {
-               dev_err(&pdev->dev, "unable to init led driver\n");
+               dev_err(&pdev->dev, "Unable to init LED driver\n");
                return ret;
        }
 
-       for (i = 0; i < pdata->num_leds; i++) {
-               led_dat = &led[i];
-               led_cur = &pdata->led[i];
+       for (i = 0; i < num_leds; i++) {
+               const char *name, *trig;
+               char max_current;
+
+               ret = -EINVAL;
 
-               if (led_cur->id > MC13783_LED_MAX || led_cur->id < 0) {
-                       dev_err(&pdev->dev, "invalid id %d\n", led_cur->id);
-                       ret = -EINVAL;
-                       goto err_register;
+               id = pdata->led[i].id;
+               name = pdata->led[i].name;
+               trig = pdata->led[i].default_trigger;
+               max_current = pdata->led[i].max_current;
+
+               if ((id > devtype->led_max) || (id < devtype->led_min)) {
+                       dev_err(&pdev->dev, "Invalid ID %i\n", id);
+                       break;
                }
 
-               if (init_led & (1 << led_cur->id)) {
-                       dev_err(&pdev->dev, "led %d already initialized\n",
-                                       led_cur->id);
-                       ret = -EINVAL;
-                       goto err_register;
+               if (init_led & (1 << id)) {
+                       dev_warn(&pdev->dev,
+                                "LED %i already initialized\n", id);
+                       break;
                }
 
-               init_led |= 1 << led_cur->id;
-               led_dat->cdev.name = led_cur->name;
-               led_dat->cdev.default_trigger = led_cur->default_trigger;
-               led_dat->cdev.brightness_set = mc13783_led_set;
-               led_dat->cdev.brightness = LED_OFF;
-               led_dat->id = led_cur->id;
-               led_dat->master = dev_get_drvdata(pdev->dev.parent);
+               init_led |= 1 << id;
+               leds->led[i].id = id;
+               leds->led[i].master = mcdev;
+               leds->led[i].cdev.name = name;
+               leds->led[i].cdev.default_trigger = trig;
+               leds->led[i].cdev.brightness_set = mc13xxx_led_set;
+               leds->led[i].cdev.brightness = LED_OFF;
 
-               INIT_WORK(&led_dat->work, mc13783_led_work);
+               INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
 
-               ret = led_classdev_register(pdev->dev.parent, &led_dat->cdev);
+               ret = mc13xxx_led_setup(&leds->led[i], max_current);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to register led %d\n",
-                                       led_dat->id);
-                       goto err_register;
+                       dev_err(&pdev->dev, "Unable to setup LED %i\n", id);
+                       break;
                }
-
-               ret = mc13783_led_setup(led_dat, led_cur->max_current);
+               ret = led_classdev_register(pdev->dev.parent,
+                                           &leds->led[i].cdev);
                if (ret) {
-                       dev_err(&pdev->dev, "unable to init led %d\n",
-                                       led_dat->id);
-                       i++;
-                       goto err_register;
+                       dev_err(&pdev->dev, "Failed to register LED %i\n", id);
+                       break;
                }
        }
 
-       platform_set_drvdata(pdev, led);
-       return 0;
-
-err_register:
-       for (i = i - 1; i >= 0; i--) {
-               led_classdev_unregister(&led[i].cdev);
-               cancel_work_sync(&led[i].work);
-       }
+       if (ret)
+               while (--i >= 0) {
+                       led_classdev_unregister(&leds->led[i].cdev);
+                       cancel_work_sync(&leds->led[i].work);
+               }
 
        return ret;
 }
 
-static int mc13783_led_remove(struct platform_device *pdev)
+static int mc13xxx_led_remove(struct platform_device *pdev)
 {
-       struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       struct mc13783_led *led = platform_get_drvdata(pdev);
-       struct mc13xxx *dev = dev_get_drvdata(pdev->dev.parent);
+       struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent);
+       struct mc13xxx_leds *leds = platform_get_drvdata(pdev);
        int i;
 
-       for (i = 0; i < pdata->num_leds; i++) {
-               led_classdev_unregister(&led[i].cdev);
-               cancel_work_sync(&led[i].work);
+       for (i = 0; i < leds->num_leds; i++) {
+               led_classdev_unregister(&leds->led[i].cdev);
+               cancel_work_sync(&leds->led[i].work);
        }
 
-       mc13xxx_lock(dev);
-
-       mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_0, 0);
-       mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_1, 0);
-       mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_2, 0);
-       mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_3, 0);
-       mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_4, 0);
-       mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_5, 0);
-
-       mc13xxx_unlock(dev);
+       mc13xxx_lock(mcdev);
+       for (i = 0; i < leds->devtype->num_regs; i++)
+               mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0);
+       mc13xxx_unlock(mcdev);
 
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
-static struct platform_driver mc13783_led_driver = {
+static const struct mc13xxx_led_devtype mc13783_led_devtype = {
+       .led_min        = MC13783_LED_MD,
+       .led_max        = MC13783_LED_B3,
+       .num_regs       = 6,
+};
+
+static const struct mc13xxx_led_devtype mc13892_led_devtype = {
+       .led_min        = MC13892_LED_MD,
+       .led_max        = MC13892_LED_B,
+       .num_regs       = 4,
+};
+
+static const struct platform_device_id mc13xxx_led_id_table[] = {
+       { "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, },
+       { "mc13892-led", (kernel_ulong_t)&mc13892_led_devtype, },
+       { }
+};
+MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table);
+
+static struct platform_driver mc13xxx_led_driver = {
        .driver = {
-               .name   = "mc13783-led",
+               .name   = "mc13xxx-led",
                .owner  = THIS_MODULE,
        },
-       .probe          = mc13783_led_probe,
-       .remove         = mc13783_led_remove,
+       .remove         = mc13xxx_led_remove,
+       .id_table       = mc13xxx_led_id_table,
 };
+module_platform_driver_probe(mc13xxx_led_driver, mc13xxx_led_probe);
 
-module_platform_driver(mc13783_led_driver);
-
-MODULE_DESCRIPTION("LEDs driver for Freescale MC13783 PMIC");
+MODULE_DESCRIPTION("LEDs driver for Freescale MC13XXX PMIC");
 MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mc13783-led");
index 70137b1eecf5bdebe130a9f3a079567bb53df9c3..e7df9875c400f3af314a8aaf8d74ce0f323e720e 100644 (file)
@@ -374,8 +374,6 @@ static int ns2_led_remove(struct platform_device *pdev)
        for (i = 0; i < priv->num_leds; i++)
                delete_ns2_led(&priv->leds_data[i]);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 9483f1c1078d406184c4c5c1a113c6d6c75adf58..adebf4931e1e0fdc65a9f199819b6a26fd975059 100644 (file)
@@ -63,7 +63,7 @@ static DEFINE_SPINLOCK(r_tpu_lock);
 #define TGRC 8 /* Timer general register C (+0x20) */
 #define TGRD 9 /* Timer general register D (+0x24) */
 
-static inline unsigned short r_tpu_read(struct r_tpu_priv *p, int reg_nr)
+static inline u16 r_tpu_read(struct r_tpu_priv *p, int reg_nr)
 {
        struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
        void __iomem *base = p->mapbase;
@@ -75,8 +75,7 @@ static inline unsigned short r_tpu_read(struct r_tpu_priv *p, int reg_nr)
        return ioread16(base + offs);
 }
 
-static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr,
-                              unsigned short value)
+static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr, u16 value)
 {
        struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
        void __iomem *base = p->mapbase;
@@ -93,7 +92,8 @@ static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr,
 static void r_tpu_start_stop_ch(struct r_tpu_priv *p, int start)
 {
        struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
-       unsigned long flags, value;
+       unsigned long flags;
+       u16 value;
 
        /* start stop register shared by multiple timer channels */
        spin_lock_irqsave(&r_tpu_lock, flags);
index 89792990088de247060f7ed868636b414756c92a..388632d23d447130ca3a8368cd48bae9a9b410eb 100644 (file)
@@ -159,14 +159,14 @@ static int sunfire_led_generic_probe(struct platform_device *pdev,
                }
        }
 
-       dev_set_drvdata(&pdev->dev, p);
+       platform_set_drvdata(pdev, p);
 
        return 0;
 }
 
 static int sunfire_led_generic_remove(struct platform_device *pdev)
 {
-       struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev);
+       struct sunfire_drvdata *p = platform_get_drvdata(pdev);
        int i;
 
        for (i = 0; i < NUM_LEDS_PER_BOARD; i++)
index 6bd5c679d877fd2dcf4e447b781ec6d3363f2546..120815a427014dc80bf5ebb5ccce35c52e4ec46b 100644 (file)
@@ -241,7 +241,7 @@ static int wm831x_status_probe(struct platform_device *pdev)
                               GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
-       dev_set_drvdata(&pdev->dev, drvdata);
+       platform_set_drvdata(pdev, drvdata);
 
        drvdata->wm831x = wm831x;
        drvdata->reg = res->start;
index f0a3347b644190b4ca76b199daf9903f32c2578a..516923926335285ce5628c205291eb22859952f3 100644 (file)
@@ -700,7 +700,7 @@ void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start)
         * interrupts are enabled.  We always leave interrupts enabled while
         * running the Guest.
         */
-       regs->eflags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;
+       regs->eflags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
 
        /*
         * The "Extended Instruction Pointer" register says where the Guest is
index b72a59d3216a68d94a3abda5ff4bc0637b87b805..e0634c8b7e0b4a8a8d564112bdfd04728fd54a69 100644 (file)
@@ -2020,7 +2020,8 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
                /* start async thread */
                chip->wt.function = chip_thread_wake;
                chip->wt.data     = (unsigned long)chip;
-               chip->thread = kthread_run(chip_thread, chip, client->name);
+               chip->thread = kthread_run(chip_thread, chip, "%s",
+                                          client->name);
                if (IS_ERR(chip->thread)) {
                        v4l2_warn(sd, "failed to create kthread\n");
                        chip->thread = NULL;
index 67b61cf3e03a32fdf6e8e61fc4c3152d5a84c634..004d8ace5019a7921e1ff7e0cc189e4c260beffa 100644 (file)
@@ -695,7 +695,7 @@ static int cx18_create_in_workq(struct cx18 *cx)
 {
        snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
                 cx->v4l2_dev.name);
-       cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0);
+       cx->in_work_queue = alloc_ordered_workqueue("%s", 0, cx->in_workq_name);
        if (cx->in_work_queue == NULL) {
                CX18_ERR("Unable to create incoming mailbox handler thread\n");
                return -ENOMEM;
index 07b8460953b6bfff7e05ecde46c4980ba2594438..b809bc868a9f01070bee7cc37e1a85f1b73d888f 100644 (file)
@@ -753,7 +753,7 @@ static int ivtv_init_struct1(struct ivtv *itv)
 
        init_kthread_worker(&itv->irq_worker);
        itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker,
-                                          itv->v4l2_dev.name);
+                                          "%s", itv->v4l2_dev.name);
        if (IS_ERR(itv->irq_worker_task)) {
                IVTV_ERR("Could not create ivtv task\n");
                return -1;
index bce695d42f10db7b6bbe4105f899840c5e76e983..25eaf61b98b487dd2c421c1f1b3ae337bfa7f6fc 100644 (file)
@@ -220,7 +220,7 @@ if V4L_TEST_DRIVERS
 config VIDEO_VIVI
        tristate "Virtual Video Driver"
        depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
-       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
+       select FONT_SUPPORT
        select FONT_8x16
        select VIDEOBUF2_VMALLOC
        default n
index 85bc314382d3e7159c0ef67e561f0478b93f3acd..1d3f1196519669cca0509c1972bdb320d2d35ad1 100644 (file)
@@ -768,7 +768,8 @@ static int vivi_start_generating(struct vivi_dev *dev)
 
        dma_q->frame = 0;
        dma_q->ini_jiffies = jiffies;
-       dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name);
+       dma_q->kthread = kthread_run(vivi_thread, dev, "%s",
+                                    dev->v4l2_dev.name);
 
        if (IS_ERR(dma_q->kthread)) {
                v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
index c37d3756d8d27acd6a7d54252b3e3ac0bdd7e80f..aeabaa5aedf7d2cbf4a76fa15b2547349adc0dd5 100644 (file)
@@ -1046,20 +1046,9 @@ static struct pci_driver jmb38x_ms_driver = {
        .resume = jmb38x_ms_resume
 };
 
-static int __init jmb38x_ms_init(void)
-{
-       return pci_register_driver(&jmb38x_ms_driver);
-}
-
-static void __exit jmb38x_ms_exit(void)
-{
-       pci_unregister_driver(&jmb38x_ms_driver);
-}
+module_pci_driver(jmb38x_ms_driver);
 
 MODULE_AUTHOR("Alex Dubov");
 MODULE_DESCRIPTION("JMicron jmb38x MemoryStick driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, jmb38x_ms_id_tbl);
-
-module_init(jmb38x_ms_init);
-module_exit(jmb38x_ms_exit);
index 9718661c1fb600d5433bfe202013dbfaae79a717..1b6e91345222f7aa3e41bb4c7066fad833feae94 100644 (file)
@@ -884,18 +884,7 @@ static struct pci_driver r852_pci_driver = {
        .driver.pm      = &r592_pm_ops,
 };
 
-static __init int r592_module_init(void)
-{
-       return pci_register_driver(&r852_pci_driver);
-}
-
-static void __exit r592_module_exit(void)
-{
-       pci_unregister_driver(&r852_pci_driver);
-}
-
-module_init(r592_module_init);
-module_exit(r592_module_exit);
+module_pci_driver(r852_pci_driver);
 
 module_param_named(enable_dma, r592_enable_dma, bool, S_IRUGO);
 MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)");
index 8a5b2d8f4daf8b0996102abcf6dcdf2452815e9f..813eaa33fa1431af96a2c2f3ac40b1000dd9ed7b 100644 (file)
@@ -84,8 +84,8 @@ int i2o_driver_register(struct i2o_driver *drv)
        osm_debug("Register driver %s\n", drv->name);
 
        if (drv->event) {
-               drv->event_queue = alloc_workqueue(drv->name,
-                                                  WQ_MEM_RECLAIM, 1);
+               drv->event_queue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1,
+                                                  drv->name);
                if (!drv->event_queue) {
                        osm_err("Could not initialize event queue for driver "
                                "%s\n", drv->name);
index 13f7866de46eb21a4cdf0363f0386d315f8171dd..3598b0ecf8c74c3c9a3377379bb20a4b9f70fa36 100644 (file)
@@ -886,12 +886,6 @@ static int ab8500_gpadc_runtime_resume(struct device *dev)
        return ret;
 }
 
-static int ab8500_gpadc_runtime_idle(struct device *dev)
-{
-       pm_runtime_suspend(dev);
-       return 0;
-}
-
 static int ab8500_gpadc_suspend(struct device *dev)
 {
        struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
@@ -1039,7 +1033,7 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
 static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
        SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
                           ab8500_gpadc_runtime_resume,
-                          ab8500_gpadc_runtime_idle)
+                          NULL)
        SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend,
                                ab8500_gpadc_resume)
 
index 6ab03043fd609a23cf95f4061b6a1a1fca799b34..74b4481754fdcb2679513dde2046266a481e040e 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/mfd/core.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
 #include <linux/slab.h>
 
 #include <linux/mfd/arizona/core.h>
@@ -344,6 +348,17 @@ static int arizona_runtime_resume(struct device *dev)
 
        switch (arizona->type) {
        case WM5102:
+               if (arizona->external_dcvdd) {
+                       ret = regmap_update_bits(arizona->regmap,
+                                                ARIZONA_ISOLATION_CONTROL,
+                                                ARIZONA_ISOLATE_DCVDD1, 0);
+                       if (ret != 0) {
+                               dev_err(arizona->dev,
+                                       "Failed to connect DCVDD: %d\n", ret);
+                               goto err;
+                       }
+               }
+
                ret = wm5102_patch(arizona);
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to apply patch: %d\n",
@@ -365,6 +380,28 @@ static int arizona_runtime_resume(struct device *dev)
                        goto err;
                }
 
+               if (arizona->external_dcvdd) {
+                       ret = regmap_update_bits(arizona->regmap,
+                                                ARIZONA_ISOLATION_CONTROL,
+                                                ARIZONA_ISOLATE_DCVDD1, 0);
+                       if (ret != 0) {
+                               dev_err(arizona->dev,
+                                       "Failed to connect DCVDD: %d\n", ret);
+                               goto err;
+                       }
+               }
+               break;
+       }
+
+       switch (arizona->type) {
+       case WM5102:
+               ret = wm5102_patch(arizona);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to apply patch: %d\n",
+                               ret);
+                       goto err;
+               }
+       default:
                break;
        }
 
@@ -385,9 +422,22 @@ err:
 static int arizona_runtime_suspend(struct device *dev)
 {
        struct arizona *arizona = dev_get_drvdata(dev);
+       int ret;
 
        dev_dbg(arizona->dev, "Entering AoD mode\n");
 
+       if (arizona->external_dcvdd) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_ISOLATION_CONTROL,
+                                        ARIZONA_ISOLATE_DCVDD1,
+                                        ARIZONA_ISOLATE_DCVDD1);
+               if (ret != 0) {
+                       dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
        regulator_disable(arizona->dcvdd);
        regcache_cache_only(arizona->regmap, true);
        regcache_mark_dirty(arizona->regmap);
@@ -397,6 +447,26 @@ static int arizona_runtime_suspend(struct device *dev)
 #endif
 
 #ifdef CONFIG_PM_SLEEP
+static int arizona_suspend(struct device *dev)
+{
+       struct arizona *arizona = dev_get_drvdata(dev);
+
+       dev_dbg(arizona->dev, "Suspend, disabling IRQ\n");
+       disable_irq(arizona->irq);
+
+       return 0;
+}
+
+static int arizona_suspend_late(struct device *dev)
+{
+       struct arizona *arizona = dev_get_drvdata(dev);
+
+       dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n");
+       enable_irq(arizona->irq);
+
+       return 0;
+}
+
 static int arizona_resume_noirq(struct device *dev)
 {
        struct arizona *arizona = dev_get_drvdata(dev);
@@ -422,13 +492,78 @@ const struct dev_pm_ops arizona_pm_ops = {
        SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
                           arizona_runtime_resume,
                           NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume)
 #ifdef CONFIG_PM_SLEEP
+       .suspend_late = arizona_suspend_late,
        .resume_noirq = arizona_resume_noirq,
 #endif
 };
 EXPORT_SYMBOL_GPL(arizona_pm_ops);
 
+#ifdef CONFIG_OF
+int arizona_of_get_type(struct device *dev)
+{
+       const struct of_device_id *id = of_match_device(arizona_of_match, dev);
+
+       if (id)
+               return (int)id->data;
+       else
+               return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_of_get_type);
+
+static int arizona_of_get_core_pdata(struct arizona *arizona)
+{
+       int ret, i;
+
+       arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node,
+                                                "wlf,reset", 0);
+       if (arizona->pdata.reset < 0)
+               arizona->pdata.reset = 0;
+
+       arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node,
+                                                 "wlf,ldoena", 0);
+       if (arizona->pdata.ldoena < 0)
+               arizona->pdata.ldoena = 0;
+
+       ret = of_property_read_u32_array(arizona->dev->of_node,
+                                        "wlf,gpio-defaults",
+                                        arizona->pdata.gpio_defaults,
+                                        ARRAY_SIZE(arizona->pdata.gpio_defaults));
+       if (ret >= 0) {
+               /*
+                * All values are literal except out of range values
+                * which are chip default, translate into platform
+                * data which uses 0 as chip default and out of range
+                * as zero.
+                */
+               for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
+                       if (arizona->pdata.gpio_defaults[i] > 0xffff)
+                               arizona->pdata.gpio_defaults[i] = 0;
+                       if (arizona->pdata.gpio_defaults[i] == 0)
+                               arizona->pdata.gpio_defaults[i] = 0x10000;
+               }
+       } else {
+               dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n",
+                       ret);
+       }
+
+       return 0;
+}
+
+const struct of_device_id arizona_of_match[] = {
+       { .compatible = "wlf,wm5102", .data = (void *)WM5102 },
+       { .compatible = "wlf,wm5110", .data = (void *)WM5110 },
+       {},
+};
+EXPORT_SYMBOL_GPL(arizona_of_match);
+#else
+static inline int arizona_of_get_core_pdata(struct arizona *arizona)
+{
+       return 0;
+}
+#endif
+
 static struct mfd_cell early_devs[] = {
        { .name = "arizona-ldo1" },
 };
@@ -462,6 +597,8 @@ int arizona_dev_init(struct arizona *arizona)
        dev_set_drvdata(arizona->dev, arizona);
        mutex_init(&arizona->clk_lock);
 
+       arizona_of_get_core_pdata(arizona);
+
        if (dev_get_platdata(arizona->dev))
                memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
                       sizeof(arizona->pdata));
@@ -536,51 +673,22 @@ int arizona_dev_init(struct arizona *arizona)
 
        regcache_cache_only(arizona->regmap, false);
 
+       /* Verify that this is a chip we know about */
        ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
        if (ret != 0) {
                dev_err(dev, "Failed to read ID register: %d\n", ret);
                goto err_reset;
        }
 
-       ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
-                         &arizona->rev);
-       if (ret != 0) {
-               dev_err(dev, "Failed to read revision register: %d\n", ret);
-               goto err_reset;
-       }
-       arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
-
        switch (reg) {
-#ifdef CONFIG_MFD_WM5102
        case 0x5102:
-               type_name = "WM5102";
-               if (arizona->type != WM5102) {
-                       dev_err(arizona->dev, "WM5102 registered as %d\n",
-                               arizona->type);
-                       arizona->type = WM5102;
-               }
-               apply_patch = wm5102_patch;
-               arizona->rev &= 0x7;
-               break;
-#endif
-#ifdef CONFIG_MFD_WM5110
        case 0x5110:
-               type_name = "WM5110";
-               if (arizona->type != WM5110) {
-                       dev_err(arizona->dev, "WM5110 registered as %d\n",
-                               arizona->type);
-                       arizona->type = WM5110;
-               }
-               apply_patch = wm5110_patch;
                break;
-#endif
        default:
-               dev_err(arizona->dev, "Unknown device ID %x\n", reg);
+               dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
                goto err_reset;
        }
 
-       dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
-
        /* If we have a /RESET GPIO we'll already be reset */
        if (!arizona->pdata.reset) {
                regcache_mark_dirty(arizona->regmap);
@@ -600,6 +708,7 @@ int arizona_dev_init(struct arizona *arizona)
                }
        }
 
+       /* Ensure device startup is complete */
        switch (arizona->type) {
        case WM5102:
                ret = regmap_read(arizona->regmap, 0x19, &val);
@@ -620,6 +729,52 @@ int arizona_dev_init(struct arizona *arizona)
                break;
        }
 
+       /* Read the device ID information & do device specific stuff */
+       ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read ID register: %d\n", ret);
+               goto err_reset;
+       }
+
+       ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
+                         &arizona->rev);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read revision register: %d\n", ret);
+               goto err_reset;
+       }
+       arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
+
+       switch (reg) {
+#ifdef CONFIG_MFD_WM5102
+       case 0x5102:
+               type_name = "WM5102";
+               if (arizona->type != WM5102) {
+                       dev_err(arizona->dev, "WM5102 registered as %d\n",
+                               arizona->type);
+                       arizona->type = WM5102;
+               }
+               apply_patch = wm5102_patch;
+               arizona->rev &= 0x7;
+               break;
+#endif
+#ifdef CONFIG_MFD_WM5110
+       case 0x5110:
+               type_name = "WM5110";
+               if (arizona->type != WM5110) {
+                       dev_err(arizona->dev, "WM5110 registered as %d\n",
+                               arizona->type);
+                       arizona->type = WM5110;
+               }
+               apply_patch = wm5110_patch;
+               break;
+#endif
+       default:
+               dev_err(arizona->dev, "Unknown device ID %x\n", reg);
+               goto err_reset;
+       }
+
+       dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
+
        if (apply_patch) {
                ret = apply_patch(arizona);
                if (ret != 0) {
@@ -651,6 +806,14 @@ int arizona_dev_init(struct arizona *arizona)
                             arizona->pdata.gpio_defaults[i]);
        }
 
+       /*
+        * LDO1 can only be used to supply DCVDD so if it has no
+        * consumers then DCVDD is supplied externally.
+        */
+       if (arizona->pdata.ldo1 &&
+           arizona->pdata.ldo1->num_consumer_supplies == 0)
+               arizona->external_dcvdd = true;
+
        pm_runtime_set_autosuspend_delay(arizona->dev, 100);
        pm_runtime_use_autosuspend(arizona->dev);
        pm_runtime_enable(arizona->dev);
@@ -697,7 +860,7 @@ int arizona_dev_init(struct arizona *arizona)
                if (arizona->pdata.micbias[i].discharge)
                        val |= ARIZONA_MICB1_DISCH;
 
-               if (arizona->pdata.micbias[i].fast_start)
+               if (arizona->pdata.micbias[i].soft_start)
                        val |= ARIZONA_MICB1_RATE;
 
                if (arizona->pdata.micbias[i].bypass)
@@ -809,6 +972,11 @@ int arizona_dev_exit(struct arizona *arizona)
        arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona);
        pm_runtime_disable(arizona->dev);
        arizona_irq_exit(arizona);
+       if (arizona->pdata.reset)
+               gpio_set_value_cansleep(arizona->pdata.reset, 0);
+       regulator_disable(arizona->dcvdd);
+       regulator_bulk_disable(ARRAY_SIZE(arizona->core_supplies),
+                              arizona->core_supplies);
        return 0;
 }
 EXPORT_SYMBOL_GPL(arizona_dev_exit);
index 44a1bb96984185e3757f31330a37d50266fdbbed..deb267ebf84e3cdff73619d1f8dbe1c6f44b4e8a 100644 (file)
@@ -27,9 +27,14 @@ static int arizona_i2c_probe(struct i2c_client *i2c,
 {
        struct arizona *arizona;
        const struct regmap_config *regmap_config;
-       int ret;
+       int ret, type;
 
-       switch (id->driver_data) {
+       if (i2c->dev.of_node)
+               type = arizona_of_get_type(&i2c->dev);
+       else
+               type = id->driver_data;
+
+       switch (type) {
 #ifdef CONFIG_MFD_WM5102
        case WM5102:
                regmap_config = &wm5102_i2c_regmap;
@@ -84,6 +89,7 @@ static struct i2c_driver arizona_i2c_driver = {
                .name   = "arizona",
                .owner  = THIS_MODULE,
                .pm     = &arizona_pm_ops,
+               .of_match_table = of_match_ptr(arizona_of_match),
        },
        .probe          = arizona_i2c_probe,
        .remove         = arizona_i2c_remove,
index b57e642d2b4a3eedaad99e65822e728ab6ff0ae6..47be7b35b5c5b09c9e17c4ef0cb7dae32b0c2855 100644 (file)
@@ -27,9 +27,14 @@ static int arizona_spi_probe(struct spi_device *spi)
        const struct spi_device_id *id = spi_get_device_id(spi);
        struct arizona *arizona;
        const struct regmap_config *regmap_config;
-       int ret;
+       int ret, type;
 
-       switch (id->driver_data) {
+       if (spi->dev.of_node)
+               type = arizona_of_get_type(&spi->dev);
+       else
+               type = id->driver_data;
+
+       switch (type) {
 #ifdef CONFIG_MFD_WM5102
        case WM5102:
                regmap_config = &wm5102_spi_regmap;
@@ -84,6 +89,7 @@ static struct spi_driver arizona_spi_driver = {
                .name   = "arizona",
                .owner  = THIS_MODULE,
                .pm     = &arizona_pm_ops,
+               .of_match_table = of_match_ptr(arizona_of_match),
        },
        .probe          = arizona_spi_probe,
        .remove         = arizona_spi_remove,
index 9798ae5da67be2b72f2d52101266c825d0e47a19..db55d9854a5587cb1d87fd46bb3d1eee6c085c00 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef _WM5102_H
 #define _WM5102_H
 
+#include <linux/of.h>
 #include <linux/regmap.h>
 #include <linux/pm.h>
 
@@ -26,6 +27,8 @@ extern const struct regmap_config wm5110_spi_regmap;
 
 extern const struct dev_pm_ops arizona_pm_ops;
 
+extern const struct of_device_id arizona_of_match[];
+
 extern const struct regmap_irq_chip wm5102_aod;
 extern const struct regmap_irq_chip wm5102_irq;
 
@@ -37,4 +40,13 @@ int arizona_dev_exit(struct arizona *arizona);
 int arizona_irq_init(struct arizona *arizona);
 int arizona_irq_exit(struct arizona *arizona);
 
+#ifdef CONFIG_OF
+int arizona_of_get_type(struct device *dev);
+#else
+static inline int arizona_of_get_type(struct device *dev)
+{
+       return 0;
+}
+#endif
+
 #endif
index 66f80973596bd8833557d13c1bfc5426a6b1290d..3c157faee645805f398cc2047d5f7b035555aacc 100644 (file)
@@ -480,6 +480,7 @@ struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
        CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true),
        CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true),
        CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true),
+       CLK_MGT_ENTRY(BML8580CLK, PLL_DIV, true),
        CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true),
        CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true),
        CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true),
@@ -1724,9 +1725,9 @@ static long round_clock_rate(u8 clock, unsigned long rate)
 
 /* CPU FREQ table, may be changed due to if MAX_OPP is supported. */
 static struct cpufreq_frequency_table db8500_cpufreq_table[] = {
-       { .frequency = 200000, .index = ARM_EXTCLK,},
-       { .frequency = 400000, .index = ARM_50_OPP,},
-       { .frequency = 800000, .index = ARM_100_OPP,},
+       { .frequency = 200000, .driver_data = ARM_EXTCLK,},
+       { .frequency = 400000, .driver_data = ARM_50_OPP,},
+       { .frequency = 800000, .driver_data = ARM_100_OPP,},
        { .frequency = CPUFREQ_TABLE_END,}, /* To be used for MAX_OPP. */
        { .frequency = CPUFREQ_TABLE_END,},
 };
@@ -1901,7 +1902,7 @@ static int set_armss_rate(unsigned long rate)
                return -EINVAL;
 
        /* Set the new arm opp. */
-       return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].index);
+       return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].driver_data);
 }
 
 static int set_plldsi_rate(unsigned long rate)
@@ -3105,7 +3106,7 @@ static void db8500_prcmu_update_cpufreq(void)
 {
        if (prcmu_has_arm_maxopp()) {
                db8500_cpufreq_table[3].frequency = 1000000;
-               db8500_cpufreq_table[3].index = ARM_MAX_OPP;
+               db8500_cpufreq_table[3].driver_data = ARM_MAX_OPP;
        }
 }
 
index d14836ed2114590ee4ad4b5b4c1971bb8d022cfc..ca355dd423a653445ac4247c10b4c181e29a9ff8 100644 (file)
@@ -32,6 +32,7 @@
 #define PRCM_PER7CLK_MGT       (0x040)
 #define PRCM_LCDCLK_MGT                (0x044)
 #define PRCM_BMLCLK_MGT                (0x04C)
+#define PRCM_BML8580CLK_MGT    (0x108)
 #define PRCM_HSITXCLK_MGT      (0x050)
 #define PRCM_HSIRXCLK_MGT      (0x054)
 #define PRCM_HDMICLK_MGT       (0x058)
index bbccd514d3ec8835a47acafb1e669af0dfd0954c..5d5e6f90424aa981653e0e3a609845d4de5a935f 100644 (file)
@@ -1208,8 +1208,7 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum)
                }
                stmpe->variant = stmpe_noirq_variant_info[stmpe->partnum];
        } else if (pdata->irq_trigger == IRQF_TRIGGER_NONE) {
-               pdata->irq_trigger =
-                       irqd_get_trigger_type(irq_get_irq_data(stmpe->irq));
+               pdata->irq_trigger = irq_get_trigger_type(stmpe->irq);
        }
 
        ret = stmpe_chip_init(stmpe);
index 59e0ee247e868c2da1f8d309fb60ac5d7c3a594b..0c1fcbc23d045652ba224a0871a05f1769d2114a 100644 (file)
@@ -145,7 +145,6 @@ static struct spi_board_info timberdale_spi_8bit_board_info[] = {
 
 static struct xspi_platform_data timberdale_xspi_platform_data = {
        .num_chipselect = 3,
-       .little_endian = true,
        /* bits per word and devices will be filled in runtime depending
         * on the HW config
         */
index a5f9888aa19c9679856143d8a231aed02bfa51ab..9d2d1bad67800e3d64d02ae46c4f9aeb4980b5e4 100644 (file)
@@ -537,16 +537,13 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data)
                /* Modify only the bits we know must change */
                while (edge_change) {
                        int             i = fls(edge_change) - 1;
-                       struct irq_data *idata;
                        int             byte = i >> 2;
                        int             off = (i & 0x3) * 2;
                        unsigned int    type;
 
-                       idata = irq_get_irq_data(i + agent->irq_base);
-
                        bytes[byte] &= ~(0x03 << off);
 
-                       type = irqd_get_trigger_type(idata);
+                       type = irq_get_trigger_type(i + agent->irq_base);
                        if (type & IRQ_TYPE_EDGE_RISING)
                                bytes[byte] |= BIT(off + 1);
                        if (type & IRQ_TYPE_EDGE_FALLING)
index 155c4a1a6a99e55f733f6d4ed7b38cd2d0634a2b..802dd3cb18cf06a2504941e0c21e5fd37ec9e7b4 100644 (file)
@@ -65,7 +65,8 @@ static const struct reg_default wm5102_revb_patch[] = {
        { 0x418, 0xa080 },
        { 0x420, 0xa080 },
        { 0x428, 0xe000 },
-       { 0x443, 0xDC1A },
+       { 0x442, 0x3F0A },
+       { 0x443, 0xDC1F },
        { 0x4B0, 0x0066 },
        { 0x458, 0x000b },
        { 0x212, 0x0000 },
@@ -424,6 +425,9 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000435, 0x0180 },   /* R1077  - DAC Digital Volume 5R */ 
        { 0x00000436, 0x0081 },   /* R1078  - DAC Volume Limit 5R */
        { 0x00000437, 0x0200 },   /* R1079  - Noise Gate Select 5R */
+       { 0x00000440, 0x8FFF },   /* R1088  - DRE Enable */
+       { 0x00000442, 0x3F0A },   /* R1090  - DRE Control 2 */
+       { 0x00000443, 0xDC1F },   /* R1090  - DRE Control 3 */
        { 0x00000450, 0x0000 },   /* R1104  - DAC AEC Control 1 */ 
        { 0x00000458, 0x000B },   /* R1112  - Noise Gate Control */
        { 0x00000490, 0x0069 },   /* R1168  - PDM SPK1 CTRL 1 */ 
@@ -1197,6 +1201,9 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_DAC_DIGITAL_VOLUME_5R:
        case ARIZONA_DAC_VOLUME_LIMIT_5R:
        case ARIZONA_NOISE_GATE_SELECT_5R:
+       case ARIZONA_DRE_ENABLE:
+       case ARIZONA_DRE_CONTROL_2:
+       case ARIZONA_DRE_CONTROL_3:
        case ARIZONA_DAC_AEC_CONTROL_1:
        case ARIZONA_NOISE_GATE_CONTROL:
        case ARIZONA_PDM_SPK1_CTRL_1:
index c41599815299ddb043654f1008864329c1d21ca0..2a7972349159fb91f27e802addf7790be81c341a 100644 (file)
@@ -2273,18 +2273,22 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP1_CLOCKING_1:
        case ARIZONA_DSP1_STATUS_1:
        case ARIZONA_DSP1_STATUS_2:
+       case ARIZONA_DSP1_STATUS_3:
        case ARIZONA_DSP2_CONTROL_1:
        case ARIZONA_DSP2_CLOCKING_1:
        case ARIZONA_DSP2_STATUS_1:
        case ARIZONA_DSP2_STATUS_2:
+       case ARIZONA_DSP2_STATUS_3:
        case ARIZONA_DSP3_CONTROL_1:
        case ARIZONA_DSP3_CLOCKING_1:
        case ARIZONA_DSP3_STATUS_1:
        case ARIZONA_DSP3_STATUS_2:
+       case ARIZONA_DSP3_STATUS_3:
        case ARIZONA_DSP4_CONTROL_1:
        case ARIZONA_DSP4_CLOCKING_1:
        case ARIZONA_DSP4_STATUS_1:
        case ARIZONA_DSP4_STATUS_2:
+       case ARIZONA_DSP4_STATUS_3:
                return true;
        default:
                return false;
@@ -2334,12 +2338,16 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP1_CLOCKING_1:
        case ARIZONA_DSP1_STATUS_1:
        case ARIZONA_DSP1_STATUS_2:
+       case ARIZONA_DSP1_STATUS_3:
        case ARIZONA_DSP2_STATUS_1:
        case ARIZONA_DSP2_STATUS_2:
+       case ARIZONA_DSP2_STATUS_3:
        case ARIZONA_DSP3_STATUS_1:
        case ARIZONA_DSP3_STATUS_2:
+       case ARIZONA_DSP3_STATUS_3:
        case ARIZONA_DSP4_STATUS_1:
        case ARIZONA_DSP4_STATUS_2:
+       case ARIZONA_DSP4_STATUS_3:
                return true;
        default:
                return false;
index 1abd5ad599251cc655672f656c2718bf65c49aa2..f7b90661e3213668310274b445f51d972ef4b9a5 100644 (file)
@@ -58,7 +58,7 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
        ssc->user++;
        spin_unlock(&user_lock);
 
-       clk_enable(ssc->clk);
+       clk_prepare_enable(ssc->clk);
 
        return ssc;
 }
@@ -69,7 +69,7 @@ void ssc_free(struct ssc_device *ssc)
        spin_lock(&user_lock);
        if (ssc->user) {
                ssc->user--;
-               clk_disable(ssc->clk);
+               clk_disable_unprepare(ssc->clk);
        } else {
                dev_dbg(&ssc->pdev->dev, "device already free\n");
        }
@@ -167,10 +167,10 @@ static int ssc_probe(struct platform_device *pdev)
        }
 
        /* disable all interrupts */
-       clk_enable(ssc->clk);
+       clk_prepare_enable(ssc->clk);
        ssc_writel(ssc->regs, IDR, -1);
        ssc_readl(ssc->regs, SR);
-       clk_disable(ssc->clk);
+       clk_disable_unprepare(ssc->clk);
 
        ssc->irq = platform_get_irq(pdev, 0);
        if (!ssc->irq) {
index c4acac74725c4de50ef0954a258a851c05a03930..f74fc0ca2ef9b86fbb85807ebcc9a9e3bae433fb 100644 (file)
@@ -876,8 +876,9 @@ int gru_set_context_option(unsigned long arg)
        switch (req.op) {
        case sco_blade_chiplet:
                /* Select blade/chiplet for GRU context */
-               if (req.val1 < -1 || req.val1 >= GRU_MAX_BLADES || !gru_base[req.val1] ||
-                   req.val0 < -1 || req.val0 >= GRU_CHIPLETS_PER_HUB) {
+               if (req.val0 < -1 || req.val0 >= GRU_CHIPLETS_PER_HUB ||
+                   req.val1 < -1 || req.val1 >= GRU_MAX_BLADES ||
+                   (req.val1 >= 0 && !gru_base[req.val1])) {
                        ret = -EINVAL;
                } else {
                        gts->ts_user_blade_id = req.val1;
index e219c97a02a416e2439f6640093ac29de4e5d371..9d5c7112557640623b839029498aba8fc47c4f7c 100644 (file)
@@ -164,7 +164,7 @@ static int mmc_runtime_resume(struct device *dev)
 
 static int mmc_runtime_idle(struct device *dev)
 {
-       return pm_runtime_suspend(dev);
+       return 0;
 }
 
 #endif /* !CONFIG_PM_RUNTIME */
index 546c67c2bbbf14aacfe6c3a2d3a8d66037705c1d..6d67492a9247b14f0ed07c2c2f9373bf0be7cdcd 100644 (file)
@@ -211,7 +211,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
        SET_RUNTIME_PM_OPS(
                pm_generic_runtime_suspend,
                pm_generic_runtime_resume,
-               pm_generic_runtime_idle
+               NULL
        )
 };
 
index f4f3038c1df08e2d5934014875abe38782f67db6..c3785edc0e92c851d3c36a0481a1b2936f92fc63 100644 (file)
@@ -61,6 +61,7 @@ static unsigned int fmax = 515633;
  * @pwrreg_powerup: power up value for MMCIPOWER register
  * @signal_direction: input/out direction of bus signals can be indicated
  * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
+ * @busy_detect: true if busy detection on dat0 is supported
  */
 struct variant_data {
        unsigned int            clkreg;
@@ -74,6 +75,7 @@ struct variant_data {
        u32                     pwrreg_powerup;
        bool                    signal_direction;
        bool                    pwrreg_clkgate;
+       bool                    busy_detect;
 };
 
 static struct variant_data variant_arm = {
@@ -132,6 +134,7 @@ static struct variant_data variant_ux500 = {
        .pwrreg_powerup         = MCI_PWR_ON,
        .signal_direction       = true,
        .pwrreg_clkgate         = true,
+       .busy_detect            = true,
 };
 
 static struct variant_data variant_ux500v2 = {
@@ -146,8 +149,28 @@ static struct variant_data variant_ux500v2 = {
        .pwrreg_powerup         = MCI_PWR_ON,
        .signal_direction       = true,
        .pwrreg_clkgate         = true,
+       .busy_detect            = true,
 };
 
+static int mmci_card_busy(struct mmc_host *mmc)
+{
+       struct mmci_host *host = mmc_priv(mmc);
+       unsigned long flags;
+       int busy = 0;
+
+       pm_runtime_get_sync(mmc_dev(mmc));
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY)
+               busy = 1;
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       pm_runtime_mark_last_busy(mmc_dev(mmc));
+       pm_runtime_put_autosuspend(mmc_dev(mmc));
+
+       return busy;
+}
+
 /*
  * Validate mmc prerequisites
  */
@@ -188,6 +211,20 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
        }
 }
 
+/*
+ * This must be called with host->lock held
+ */
+static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
+{
+       /* Keep ST Micro busy mode if enabled */
+       datactrl |= host->datactrl_reg & MCI_ST_DPSM_BUSYMODE;
+
+       if (host->datactrl_reg != datactrl) {
+               host->datactrl_reg = datactrl;
+               writel(datactrl, host->base + MMCIDATACTRL);
+       }
+}
+
 /*
  * This must be called with host->lock held
  */
@@ -196,6 +233,9 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
        struct variant_data *variant = host->variant;
        u32 clk = variant->clkreg;
 
+       /* Make sure cclk reflects the current calculated clock */
+       host->cclk = 0;
+
        if (desired) {
                if (desired >= host->mclk) {
                        clk = MCI_CLK_BYPASS;
@@ -230,6 +270,9 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
                /* clk |= MCI_CLK_PWRSAVE; */
        }
 
+       /* Set actual clock for debug */
+       host->mmc->actual_clock = host->cclk;
+
        if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4)
                clk |= MCI_4BIT_BUS;
        if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
@@ -275,7 +318,7 @@ static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
 
 static void mmci_stop_data(struct mmci_host *host)
 {
-       writel(0, host->base + MMCIDATACTRL);
+       mmci_write_datactrlreg(host, 0);
        mmci_set_mask1(host, 0);
        host->data = NULL;
 }
@@ -304,10 +347,8 @@ static void mmci_dma_setup(struct mmci_host *host)
        const char *rxname, *txname;
        dma_cap_mask_t mask;
 
-       if (!plat || !plat->dma_filter) {
-               dev_info(mmc_dev(host->mmc), "no DMA platform data\n");
-               return;
-       }
+       host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
+       host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
 
        /* initialize pre request cookie */
        host->next_data.cookie = 1;
@@ -316,30 +357,33 @@ static void mmci_dma_setup(struct mmci_host *host)
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
-       /*
-        * If only an RX channel is specified, the driver will
-        * attempt to use it bidirectionally, however if it is
-        * is specified but cannot be located, DMA will be disabled.
-        */
-       if (plat->dma_rx_param) {
-               host->dma_rx_channel = dma_request_channel(mask,
+       if (plat && plat->dma_filter) {
+               if (!host->dma_rx_channel && plat->dma_rx_param) {
+                       host->dma_rx_channel = dma_request_channel(mask,
                                                           plat->dma_filter,
                                                           plat->dma_rx_param);
-               /* E.g if no DMA hardware is present */
-               if (!host->dma_rx_channel)
-                       dev_err(mmc_dev(host->mmc), "no RX DMA channel\n");
-       }
+                       /* E.g if no DMA hardware is present */
+                       if (!host->dma_rx_channel)
+                               dev_err(mmc_dev(host->mmc), "no RX DMA channel\n");
+               }
 
-       if (plat->dma_tx_param) {
-               host->dma_tx_channel = dma_request_channel(mask,
+               if (!host->dma_tx_channel && plat->dma_tx_param) {
+                       host->dma_tx_channel = dma_request_channel(mask,
                                                           plat->dma_filter,
                                                           plat->dma_tx_param);
-               if (!host->dma_tx_channel)
-                       dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n");
-       } else {
-               host->dma_tx_channel = host->dma_rx_channel;
+                       if (!host->dma_tx_channel)
+                               dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n");
+               }
        }
 
+       /*
+        * If only an RX channel is specified, the driver will
+        * attempt to use it bidirectionally, however if it is
+        * is specified but cannot be located, DMA will be disabled.
+        */
+       if (host->dma_rx_channel && !host->dma_tx_channel)
+               host->dma_tx_channel = host->dma_rx_channel;
+
        if (host->dma_rx_channel)
                rxname = dma_chan_name(host->dma_rx_channel);
        else
@@ -552,7 +596,7 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
        datactrl |= MCI_DPSM_DMAENABLE;
 
        /* Trigger the DMA transfer */
-       writel(datactrl, host->base + MMCIDATACTRL);
+       mmci_write_datactrlreg(host, datactrl);
 
        /*
         * Let the MMCI say when the data is ended and it's time
@@ -750,7 +794,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
                irqmask = MCI_TXFIFOHALFEMPTYMASK;
        }
 
-       writel(datactrl, base + MMCIDATACTRL);
+       mmci_write_datactrlreg(host, datactrl);
        writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
        mmci_set_mask1(host, irqmask);
 }
@@ -842,7 +886,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
                        /* The error clause is handled above, success! */
                        data->bytes_xfered = data->blksz * data->blocks;
 
-               if (!data->stop) {
+               if (!data->stop || host->mrq->sbc) {
                        mmci_request_end(host, data->mrq);
                } else {
                        mmci_start_command(host, data->stop, 0);
@@ -855,6 +899,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
             unsigned int status)
 {
        void __iomem *base = host->base;
+       bool sbc = (cmd == host->mrq->sbc);
 
        host->cmd = NULL;
 
@@ -869,7 +914,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
                cmd->resp[3] = readl(base + MMCIRESPONSE3);
        }
 
-       if (!cmd->data || cmd->error) {
+       if ((!sbc && !cmd->data) || cmd->error) {
                if (host->data) {
                        /* Terminate the DMA transfer */
                        if (dma_inprogress(host)) {
@@ -878,7 +923,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
                        }
                        mmci_stop_data(host);
                }
-               mmci_request_end(host, cmd->mrq);
+               mmci_request_end(host, host->mrq);
+       } else if (sbc) {
+               mmci_start_command(host, host->mrq->cmd, 0);
        } else if (!(cmd->data->flags & MMC_DATA_READ)) {
                mmci_start_data(host, cmd->data);
        }
@@ -1119,7 +1166,10 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        if (mrq->data && mrq->data->flags & MMC_DATA_READ)
                mmci_start_data(host, mrq->data);
 
-       mmci_start_command(host, mrq->cmd, 0);
+       if (mrq->sbc)
+               mmci_start_command(host, mrq->sbc, 0);
+       else
+               mmci_start_command(host, mrq->cmd, 0);
 
        spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -1143,9 +1193,10 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if (!IS_ERR(mmc->supply.vmmc))
                        mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
 
-               if (!IS_ERR(mmc->supply.vqmmc) &&
-                   regulator_is_enabled(mmc->supply.vqmmc))
+               if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) {
                        regulator_disable(mmc->supply.vqmmc);
+                       host->vqmmc_enabled = false;
+               }
 
                break;
        case MMC_POWER_UP:
@@ -1161,12 +1212,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
                break;
        case MMC_POWER_ON:
-               if (!IS_ERR(mmc->supply.vqmmc) &&
-                   !regulator_is_enabled(mmc->supply.vqmmc)) {
+               if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) {
                        ret = regulator_enable(mmc->supply.vqmmc);
                        if (ret < 0)
                                dev_err(mmc_dev(mmc),
                                        "failed to enable vqmmc regulator\n");
+                       else
+                               host->vqmmc_enabled = true;
                }
 
                pwr |= MCI_PWR_ON;
@@ -1251,6 +1303,39 @@ static int mmci_get_cd(struct mmc_host *mmc)
        return status;
 }
 
+static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       int ret = 0;
+
+       if (!IS_ERR(mmc->supply.vqmmc)) {
+
+               pm_runtime_get_sync(mmc_dev(mmc));
+
+               switch (ios->signal_voltage) {
+               case MMC_SIGNAL_VOLTAGE_330:
+                       ret = regulator_set_voltage(mmc->supply.vqmmc,
+                                               2700000, 3600000);
+                       break;
+               case MMC_SIGNAL_VOLTAGE_180:
+                       ret = regulator_set_voltage(mmc->supply.vqmmc,
+                                               1700000, 1950000);
+                       break;
+               case MMC_SIGNAL_VOLTAGE_120:
+                       ret = regulator_set_voltage(mmc->supply.vqmmc,
+                                               1100000, 1300000);
+                       break;
+               }
+
+               if (ret)
+                       dev_warn(mmc_dev(mmc), "Voltage switch failed\n");
+
+               pm_runtime_mark_last_busy(mmc_dev(mmc));
+               pm_runtime_put_autosuspend(mmc_dev(mmc));
+       }
+
+       return ret;
+}
+
 static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
 {
        struct mmci_host *host = dev_id;
@@ -1260,13 +1345,14 @@ static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static const struct mmc_host_ops mmci_ops = {
+static struct mmc_host_ops mmci_ops = {
        .request        = mmci_request,
        .pre_req        = mmci_pre_request,
        .post_req       = mmci_post_request,
        .set_ios        = mmci_set_ios,
        .get_ro         = mmci_get_ro,
        .get_cd         = mmci_get_cd,
+       .start_signal_voltage_switch = mmci_sig_volt_switch,
 };
 
 #ifdef CONFIG_OF
@@ -1362,16 +1448,15 @@ static int mmci_probe(struct amba_device *dev,
        dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
        dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);
 
-       host->clk = clk_get(&dev->dev, NULL);
+       host->clk = devm_clk_get(&dev->dev, NULL);
        if (IS_ERR(host->clk)) {
                ret = PTR_ERR(host->clk);
-               host->clk = NULL;
                goto host_free;
        }
 
        ret = clk_prepare_enable(host->clk);
        if (ret)
-               goto clk_free;
+               goto host_free;
 
        host->plat = plat;
        host->variant = variant;
@@ -1396,6 +1481,11 @@ static int mmci_probe(struct amba_device *dev,
                goto clk_disable;
        }
 
+       if (variant->busy_detect) {
+               mmci_ops.card_busy = mmci_card_busy;
+               mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
+       }
+
        mmc->ops = &mmci_ops;
        /*
         * The ARM and ST versions of the block have slightly different
@@ -1576,8 +1666,6 @@ static int mmci_probe(struct amba_device *dev,
        iounmap(host->base);
  clk_disable:
        clk_disable_unprepare(host->clk);
- clk_free:
-       clk_put(host->clk);
  host_free:
        mmc_free_host(mmc);
  rel_regions:
@@ -1623,7 +1711,6 @@ static int mmci_remove(struct amba_device *dev)
 
                iounmap(host->base);
                clk_disable_unprepare(host->clk);
-               clk_put(host->clk);
 
                mmc_free_host(mmc);
 
index 1f33ad5333a081508f9e76e7cb727822cf234907..69080fab637520af2a9ea8b4a6ba49ae52b0344f 100644 (file)
@@ -94,6 +94,7 @@
 /* Extended status bits for the ST Micro variants */
 #define MCI_ST_SDIOIT          (1 << 22)
 #define MCI_ST_CEATAEND                (1 << 23)
+#define MCI_ST_CARDBUSY                (1 << 24)
 
 #define MMCICLEAR              0x038
 #define MCI_CMDCRCFAILCLR      (1 << 0)
 /* Extended status bits for the ST Micro variants */
 #define MCI_ST_SDIOITC         (1 << 22)
 #define MCI_ST_CEATAENDC       (1 << 23)
+#define MCI_ST_BUSYENDC                (1 << 24)
 
 #define MMCIMASK0              0x03c
 #define MCI_CMDCRCFAILMASK     (1 << 0)
@@ -183,6 +185,8 @@ struct mmci_host {
        unsigned int            cclk;
        u32                     pwr_reg;
        u32                     clk_reg;
+       u32                     datactrl_reg;
+       bool                    vqmmc_enabled;
        struct mmci_platform_data *plat;
        struct variant_data     *variant;
 
index c719879284bd7b9921a254a70831a39bae644a7d..684bfa39e4ee4892f901874c52c699fa71fd572a 100644 (file)
@@ -55,25 +55,7 @@ struct mtd_file_info {
 static loff_t mtdchar_lseek(struct file *file, loff_t offset, int orig)
 {
        struct mtd_file_info *mfi = file->private_data;
-       struct mtd_info *mtd = mfi->mtd;
-
-       switch (orig) {
-       case SEEK_SET:
-               break;
-       case SEEK_CUR:
-               offset += file->f_pos;
-               break;
-       case SEEK_END:
-               offset += mtd->size;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (offset >= 0 && offset <= mtd->size)
-               return file->f_pos = offset;
-
-       return -EINVAL;
+       return fixed_size_llseek(file, offset, orig, mfi->mtd->size);
 }
 
 static int count;
index c400c57c394aaddb26147bfe2b1955c6716f74d5..048c823f5c51397df8c5e6ef023ba287ab65b02f 100644 (file)
@@ -1151,7 +1151,7 @@ static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name)
 
        ret = bdi_init(bdi);
        if (!ret)
-               ret = bdi_register(bdi, NULL, name);
+               ret = bdi_register(bdi, NULL, "%s", name);
 
        if (ret)
                bdi_destroy(bdi);
index a56133585e924048a297041115336a58f3d6d709..0aaece9107c76f7f46dd4b4a0f8be3a90167b948 100644 (file)
@@ -1005,7 +1005,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
        if (err)
                goto out_uif;
 
-       ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
+       ubi->bgt_thread = kthread_create(ubi_thread, ubi, "%s", ubi->bgt_name);
        if (IS_ERR(ubi->bgt_thread)) {
                err = PTR_ERR(ubi->bgt_thread);
                ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
index 4f02848bb2bc5d843900d6762b10edec23e3dd84..8ca49f2043e4b8a7fe41109129de5760995b59d4 100644 (file)
@@ -155,7 +155,6 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
 {
        struct ubi_volume_desc *desc = file->private_data;
        struct ubi_volume *vol = desc->vol;
-       loff_t new_offset;
 
        if (vol->updating) {
                /* Update is in progress, seeking is prohibited */
@@ -163,30 +162,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
                return -EBUSY;
        }
 
-       switch (origin) {
-       case 0: /* SEEK_SET */
-               new_offset = offset;
-               break;
-       case 1: /* SEEK_CUR */
-               new_offset = file->f_pos + offset;
-               break;
-       case 2: /* SEEK_END */
-               new_offset = vol->used_bytes + offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (new_offset < 0 || new_offset > vol->used_bytes) {
-               ubi_err("bad seek %lld", new_offset);
-               return -EINVAL;
-       }
-
-       dbg_gen("seek volume %d, offset %lld, origin %d, new offset %lld",
-               vol->vol_id, offset, origin, new_offset);
-
-       file->f_pos = new_offset;
-       return new_offset;
+       return fixed_size_llseek(file, offset, origin, vol->used_bytes);
 }
 
 static int vol_cdev_fsync(struct file *file, loff_t start, loff_t end,
index 94d957d203a6466b9b809d49962f6630ed2bc7cb..7d6aa8c87df84747bea056019a89517846817b21 100644 (file)
@@ -230,32 +230,12 @@ bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file)
 static loff_t
 bnad_debugfs_lseek(struct file *file, loff_t offset, int orig)
 {
-       loff_t pos = file->f_pos;
        struct bnad_debug_info *debug = file->private_data;
 
        if (!debug)
                return -EINVAL;
 
-       switch (orig) {
-       case 0:
-               file->f_pos = offset;
-               break;
-       case 1:
-               file->f_pos += offset;
-               break;
-       case 2:
-               file->f_pos = debug->buffer_len + offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
-               file->f_pos = pos;
-               return -EINVAL;
-       }
-
-       return file->f_pos;
+       return fixed_size_llseek(file, offset, orig, debug->buffer_len);
 }
 
 static ssize_t
index d1a769f35f9d284f852e1001c87434ae9e96180a..da4415d9dee6cbb8bfdc7667793765f175dd669d 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/if_vlan.h>
 
 #include <linux/platform_data/cpsw.h>
+#include <linux/pinctrl/consumer.h>
 
 #include "cpsw_ale.h"
 #include "cpts.h"
@@ -1689,6 +1690,9 @@ static int cpsw_probe(struct platform_device *pdev)
         */
        pm_runtime_enable(&pdev->dev);
 
+       /* Select default pin state */
+       pinctrl_pm_select_default_state(&pdev->dev);
+
        if (cpsw_probe_dt(&priv->data, pdev)) {
                pr_err("cpsw: platform data missing\n");
                ret = -ENODEV;
@@ -1981,6 +1985,9 @@ static int cpsw_suspend(struct device *dev)
        soft_reset("sliver 1", &priv->slaves[1].sliver->soft_reset);
        pm_runtime_put_sync(&pdev->dev);
 
+       /* Select sleep pin state */
+       pinctrl_pm_select_sleep_state(&pdev->dev);
+
        return 0;
 }
 
@@ -1990,6 +1997,10 @@ static int cpsw_resume(struct device *dev)
        struct net_device       *ndev = platform_get_drvdata(pdev);
 
        pm_runtime_get_sync(&pdev->dev);
+
+       /* Select default pin state */
+       pinctrl_pm_select_default_state(&pdev->dev);
+
        if (netif_running(ndev))
                cpsw_ndo_open(ndev);
        return 0;
index c47f0dbcebb513d7a33c49c92725350e13d73c6e..ce7c4991e41c6473fe0e05b18759127482416920 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/davinci_emac.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
 
 /*
  * This timeout definition is a worst-case ultra defensive measure against
@@ -347,6 +348,9 @@ static int davinci_mdio_probe(struct platform_device *pdev)
        data->bus->parent       = dev;
        data->bus->priv         = data;
 
+       /* Select default pin state */
+       pinctrl_pm_select_default_state(&pdev->dev);
+
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
        data->clk = clk_get(&pdev->dev, "fck");
@@ -453,6 +457,9 @@ static int davinci_mdio_suspend(struct device *dev)
        spin_unlock(&data->lock);
        pm_runtime_put_sync(data->dev);
 
+       /* Select sleep pin state */
+       pinctrl_pm_select_sleep_state(dev);
+
        return 0;
 }
 
@@ -460,6 +467,9 @@ static int davinci_mdio_resume(struct device *dev)
 {
        struct davinci_mdio_data *data = dev_get_drvdata(dev);
 
+       /* Select default pin state */
+       pinctrl_pm_select_default_state(dev);
+
        pm_runtime_get_sync(data->dev);
 
        spin_lock(&data->lock);
index 38f0b312ff85e339bc742c8472ef244bb9c50a40..663d2d0448b759117896b4f765261ec02f7e6f9c 100644 (file)
@@ -439,7 +439,7 @@ void phy_start_machine(struct phy_device *phydev,
 {
        phydev->adjust_state = handler;
 
-       schedule_delayed_work(&phydev->state_queue, HZ);
+       queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, HZ);
 }
 
 /**
@@ -500,7 +500,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
        disable_irq_nosync(irq);
        atomic_inc(&phydev->irq_disable);
 
-       schedule_work(&phydev->phy_queue);
+       queue_work(system_power_efficient_wq, &phydev->phy_queue);
 
        return IRQ_HANDLED;
 }
@@ -655,7 +655,7 @@ static void phy_change(struct work_struct *work)
 
        /* reschedule state queue work to run as soon as possible */
        cancel_delayed_work_sync(&phydev->state_queue);
-       schedule_delayed_work(&phydev->state_queue, 0);
+       queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0);
 
        return;
 
@@ -918,7 +918,8 @@ void phy_state_machine(struct work_struct *work)
        if (err < 0)
                phy_error(phydev);
 
-       schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ);
+       queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,
+                       PHY_STATE_TIME * HZ);
 }
 
 static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad,
index f433b594388e170b28b1aa57a92485625d897cb6..6d1f6ed3113fc1a0604e2db595989bd48c386c3a 100644 (file)
@@ -208,6 +208,17 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                if (nets[rnet->mport->id].active[destid])
                        rionet_queue_tx_msg(skb, ndev,
                                        nets[rnet->mport->id].active[destid]);
+               else {
+                       /*
+                        * If the target device was removed from the list of
+                        * active peers but we still have TX packets targeting
+                        * it just report sending a packet to the target
+                        * (without actual packet transfer).
+                        */
+                       dev_kfree_skb_any(skb);
+                       ndev->stats.tx_packets++;
+                       ndev->stats.tx_bytes += skb->len;
+               }
        }
 
        spin_unlock_irqrestore(&rnet->tx_lock, flags);
@@ -385,24 +396,28 @@ static int rionet_close(struct net_device *ndev)
        return 0;
 }
 
-static void rionet_remove(struct rio_dev *rdev)
+static int rionet_remove_dev(struct device *dev, struct subsys_interface *sif)
 {
-       struct net_device *ndev = rio_get_drvdata(rdev);
+       struct rio_dev *rdev = to_rio_dev(dev);
        unsigned char netid = rdev->net->hport->id;
        struct rionet_peer *peer, *tmp;
 
-       unregister_netdev(ndev);
-
-       free_pages((unsigned long)nets[netid].active, get_order(sizeof(void *) *
-                       RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size)));
-       nets[netid].active = NULL;
+       if (dev_rionet_capable(rdev)) {
+               list_for_each_entry_safe(peer, tmp, &nets[netid].peers, node) {
+                       if (peer->rdev == rdev) {
+                               if (nets[netid].active[rdev->destid]) {
+                                       nets[netid].active[rdev->destid] = NULL;
+                                       nets[netid].nact--;
+                               }
 
-       list_for_each_entry_safe(peer, tmp, &nets[netid].peers, node) {
-               list_del(&peer->node);
-               kfree(peer);
+                               list_del(&peer->node);
+                               kfree(peer);
+                               break;
+                       }
+               }
        }
 
-       free_netdev(ndev);
+       return 0;
 }
 
 static void rionet_get_drvinfo(struct net_device *ndev,
@@ -503,12 +518,13 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
 
 static unsigned long net_table[RIONET_MAX_NETS/sizeof(unsigned long) + 1];
 
-static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
+static int rionet_add_dev(struct device *dev, struct subsys_interface *sif)
 {
        int rc = -ENODEV;
        u32 lsrc_ops, ldst_ops;
        struct rionet_peer *peer;
        struct net_device *ndev = NULL;
+       struct rio_dev *rdev = to_rio_dev(dev);
        unsigned char netid = rdev->net->hport->id;
        int oldnet;
 
@@ -518,8 +534,9 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
        oldnet = test_and_set_bit(netid, net_table);
 
        /*
-        * First time through, make sure local device is rionet
-        * capable, setup netdev (will be skipped on later probes)
+        * If first time through this net, make sure local device is rionet
+        * capable and setup netdev (this step will be skipped in later probes
+        * on the same net).
         */
        if (!oldnet) {
                rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
@@ -541,6 +558,12 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
                }
                nets[netid].ndev = ndev;
                rc = rionet_setup_netdev(rdev->net->hport, ndev);
+               if (rc) {
+                       printk(KERN_ERR "%s: failed to setup netdev (rc=%d)\n",
+                              DRV_NAME, rc);
+                       goto out;
+               }
+
                INIT_LIST_HEAD(&nets[netid].peers);
                nets[netid].nact = 0;
        } else if (nets[netid].ndev == NULL)
@@ -559,31 +582,61 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
                list_add_tail(&peer->node, &nets[netid].peers);
        }
 
-       rio_set_drvdata(rdev, nets[netid].ndev);
-
-      out:
+       return 0;
+out:
        return rc;
 }
 
+#ifdef MODULE
 static struct rio_device_id rionet_id_table[] = {
-       {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)}
+       {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)},
+       { 0, }  /* terminate list */
 };
 
-static struct rio_driver rionet_driver = {
-       .name = "rionet",
-       .id_table = rionet_id_table,
-       .probe = rionet_probe,
-       .remove = rionet_remove,
+MODULE_DEVICE_TABLE(rapidio, rionet_id_table);
+#endif
+
+static struct subsys_interface rionet_interface = {
+       .name           = "rionet",
+       .subsys         = &rio_bus_type,
+       .add_dev        = rionet_add_dev,
+       .remove_dev     = rionet_remove_dev,
 };
 
 static int __init rionet_init(void)
 {
-       return rio_register_driver(&rionet_driver);
+       return subsys_interface_register(&rionet_interface);
 }
 
 static void __exit rionet_exit(void)
 {
-       rio_unregister_driver(&rionet_driver);
+       struct rionet_private *rnet;
+       struct net_device *ndev;
+       struct rionet_peer *peer, *tmp;
+       int i;
+
+       for (i = 0; i < RIONET_MAX_NETS; i++) {
+               if (nets[i].ndev != NULL) {
+                       ndev = nets[i].ndev;
+                       rnet = netdev_priv(ndev);
+                       unregister_netdev(ndev);
+
+                       list_for_each_entry_safe(peer,
+                                                tmp, &nets[i].peers, node) {
+                               list_del(&peer->node);
+                               kfree(peer);
+                       }
+
+                       free_pages((unsigned long)nets[i].active,
+                                get_order(sizeof(void *) *
+                                RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size)));
+                       nets[i].active = NULL;
+
+                       free_netdev(ndev);
+               }
+       }
+
+       subsys_interface_unregister(&rionet_interface);
 }
 
 late_initcall(rionet_init);
index 6125adb520a3ee08a20acb2c6c43ef97418b11b9..d0adbaf86186fe7ff9c7d96feaa308aff75a525f 100644 (file)
@@ -1893,7 +1893,8 @@ static int airo_open(struct net_device *dev) {
 
        if (ai->wifidev != dev) {
                clear_bit(JOB_DIE, &ai->jobs);
-               ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
+               ai->airo_thread_task = kthread_run(airo_thread, dev, "%s",
+                                                  dev->name);
                if (IS_ERR(ai->airo_thread_task))
                        return (int)PTR_ERR(ai->airo_thread_task);
 
index d96257b79a84a90c4f0c14ff8273f4e53dc86057..4ed5e45ca1e2f2849bfebabc580036d309f3890d 100644 (file)
@@ -8256,7 +8256,7 @@ static  int is_duplicate_packet(struct ipw_priv *priv,
                        u8 *mac = header->addr2;
                        int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE;
 
-                       __list_for_each(p, &priv->ibss_mac_hash[index]) {
+                       list_for_each(p, &priv->ibss_mac_hash[index]) {
                                entry =
                                    list_entry(p, struct ipw_ibss_seq, list);
                                if (!memcmp(entry->mac, mac, ETH_ALEN))
index 90dc14336980c2bcc344a4c5e97d8e4033fa9d95..c8b9ef0c21f826bd0247d0e145424ac3722d6470 100644 (file)
@@ -1321,7 +1321,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
         * Initialize work.
         */
        rt2x00dev->workqueue =
-           alloc_ordered_workqueue(wiphy_name(rt2x00dev->hw->wiphy), 0);
+           alloc_ordered_workqueue("%s", 0, wiphy_name(rt2x00dev->hw->wiphy));
        if (!rt2x00dev->workqueue) {
                retval = -ENOMEM;
                goto exit;
index af59dd5718e1b90eab623b8b04bf94b0332fce45..a5f223145b0f707b92923f107c45cfcb732468a9 100644 (file)
@@ -380,7 +380,7 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
 
        /* <2> work queue */
        rtlpriv->works.hw = hw;
-       rtlpriv->works.rtl_wq = alloc_workqueue(rtlpriv->cfg->name, 0, 0);
+       rtlpriv->works.rtl_wq = alloc_workqueue("%s", 0, 0, rtlpriv->cfg->name);
        INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq,
                          (void *)rtl_watchdog_wq_callback);
        INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
index c3e1f79c785697d95dfc9ccfac1e49410f263d8f..e17630c2a84948d40bb5d0f2c05f4ce1e8ccea2c 100644 (file)
@@ -1056,7 +1056,7 @@ static ssize_t dev_mem_read(struct file *file,
                return -EINVAL;
 
        memset(&part, 0, sizeof(part));
-       part.mem.start = file->f_pos;
+       part.mem.start = *ppos;
        part.mem.size = bytes;
 
        buf = kmalloc(bytes, GFP_KERNEL);
@@ -1137,7 +1137,7 @@ static ssize_t dev_mem_write(struct file *file, const char __user *user_buf,
                return -EINVAL;
 
        memset(&part, 0, sizeof(part));
-       part.mem.start = file->f_pos;
+       part.mem.start = *ppos;
        part.mem.size = bytes;
 
        buf = kmalloc(bytes, GFP_KERNEL);
index af212c6a615840e7bf777fb931ff2770d490fb5d..783906fe659a2824987fe4b5cc9397c866ba91f7 100644 (file)
 
 #define        EISA_EEPROM_MINOR 241
 
-static loff_t eisa_eeprom_llseek(struct file *file, loff_t offset, int origin )
+static loff_t eisa_eeprom_llseek(struct file *file, loff_t offset, int origin)
 {
-       switch (origin) {
-         case 0:
-               /* nothing to do */
-               break;
-         case 1:
-               offset += file->f_pos;
-               break;
-         case 2:
-               offset += HPEE_MAX_LENGTH;
-               break;
-       }
-       return (offset >= 0 && offset < HPEE_MAX_LENGTH) ? (file->f_pos = offset) : -EINVAL;
+       return fixed_size_llseek(file, offset, origin, HPEE_MAX_LENGTH);
 }
 
 static ssize_t eisa_eeprom_read(struct file * file,
index a50576081b34dd998fbbd8aca4fd0c154df5420e..dc82ef096f3ba61267484057b083caed92748d5b 100644 (file)
@@ -36,7 +36,9 @@ if PARPORT
 config PARPORT_PC
        tristate "PC-style hardware"
        depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && !S390 && \
-               (!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && !XTENSA
+               (!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && \
+               !XTENSA && !CRIS
+
        ---help---
          You should say Y here if you have a PC-style parallel port. All
          IBM PC compatible computers and some Alphas have PC-style
index a848e02e6be3d4537b5dd94c7017ec799cf7becb..6a83ee1e9178c118dabb6f318e40c447aa7d3d6d 100644 (file)
@@ -282,14 +282,13 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
        int device;
        char *name;
 
-       tmp = kmalloc(sizeof(struct parport), GFP_KERNEL);
+       tmp = kzalloc(sizeof(struct parport), GFP_KERNEL);
        if (!tmp) {
                printk(KERN_WARNING "parport: memory squeeze\n");
                return NULL;
        }
 
        /* Init our structure */
-       memset(tmp, 0, sizeof(struct parport));
        tmp->base = base;
        tmp->irq = irq;
        tmp->dma = dma;
index 32e66a6f12d98084f77f493ed1d202084ad3329e..b1ff02ab4f131fbda7edd9971342b9ae91bf4149 100644 (file)
@@ -283,6 +283,21 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
 }
 EXPORT_SYMBOL_GPL(pci_walk_bus);
 
+struct pci_bus *pci_bus_get(struct pci_bus *bus)
+{
+       if (bus)
+               get_device(&bus->dev);
+       return bus;
+}
+EXPORT_SYMBOL(pci_bus_get);
+
+void pci_bus_put(struct pci_bus *bus)
+{
+       if (bus)
+               put_device(&bus->dev);
+}
+EXPORT_SYMBOL(pci_bus_put);
+
 EXPORT_SYMBOL(pci_bus_alloc_resource);
 EXPORT_SYMBOL_GPL(pci_bus_add_device);
 EXPORT_SYMBOL(pci_bus_add_devices);
index 4cb30447a4860cf684155f18c79faad88f3989c6..17c1f36315d191b46bf81734efa69fff344bfa84 100644 (file)
@@ -167,26 +167,8 @@ exit:
 
 static loff_t lseek(struct file *file, loff_t off, int whence)
 {
-       struct ctrl_dbg *dbg;
-       loff_t new = -1;
-
-       mutex_lock(&cpqphp_mutex);
-       dbg = file->private_data;
-
-       switch (whence) {
-       case 0:
-               new = off;
-               break;
-       case 1:
-               new = file->f_pos + off;
-               break;
-       }
-       if (new < 0 || new > dbg->size) {
-               mutex_unlock(&cpqphp_mutex);
-               return -EINVAL;
-       }
-       mutex_unlock(&cpqphp_mutex);
-       return (file->f_pos = new);
+       struct ctrl_dbg *dbg = file->private_data;
+       return fixed_size_llseek(file, off, whence, dbg->size);
 }
 
 static ssize_t read(struct file *file, char __user *buf,
index 5127f3f418211496ddf44b335ccc5ab44fbac856..b2255736ac81fa819e651f40deb17a6102c4240a 100644 (file)
@@ -773,14 +773,12 @@ static void pcie_shutdown_notification(struct controller *ctrl)
 static int pcie_init_slot(struct controller *ctrl)
 {
        struct slot *slot;
-       char name[32];
 
        slot = kzalloc(sizeof(*slot), GFP_KERNEL);
        if (!slot)
                return -ENOMEM;
 
-       snprintf(name, sizeof(name), "pciehp-%u", PSN(ctrl));
-       slot->wq = alloc_workqueue(name, 0, 0);
+       slot->wq = alloc_workqueue("pciehp-%u", 0, 0, PSN(ctrl));
        if (!slot->wq)
                goto abort;
 
index 46a7b738f61f14200d726b02d6ed25784b6b0b08..ea3fa90d020a94548c8b1dd30ba8bccd606888b3 100644 (file)
@@ -41,6 +41,28 @@ struct slot {
        struct zpci_dev *zdev;
 };
 
+static inline int slot_configure(struct slot *slot)
+{
+       int ret = sclp_pci_configure(slot->zdev->fid);
+
+       zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, ret);
+       if (!ret)
+               slot->zdev->state = ZPCI_FN_STATE_CONFIGURED;
+
+       return ret;
+}
+
+static inline int slot_deconfigure(struct slot *slot)
+{
+       int ret = sclp_pci_deconfigure(slot->zdev->fid);
+
+       zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, ret);
+       if (!ret)
+               slot->zdev->state = ZPCI_FN_STATE_STANDBY;
+
+       return ret;
+}
+
 static int enable_slot(struct hotplug_slot *hotplug_slot)
 {
        struct slot *slot = hotplug_slot->private;
@@ -49,14 +71,23 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
        if (slot->zdev->state != ZPCI_FN_STATE_STANDBY)
                return -EIO;
 
-       rc = sclp_pci_configure(slot->zdev->fid);
-       zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, rc);
-       if (!rc) {
-               slot->zdev->state = ZPCI_FN_STATE_CONFIGURED;
-               /* automatically scan the device after is was configured */
-               zpci_enable_device(slot->zdev);
-               zpci_scan_device(slot->zdev);
-       }
+       rc = slot_configure(slot);
+       if (rc)
+               return rc;
+
+       rc = zpci_enable_device(slot->zdev);
+       if (rc)
+               goto out_deconfigure;
+
+       slot->zdev->state = ZPCI_FN_STATE_ONLINE;
+
+       pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN);
+       pci_bus_add_devices(slot->zdev->bus);
+
+       return rc;
+
+out_deconfigure:
+       slot_deconfigure(slot);
        return rc;
 }
 
@@ -68,17 +99,14 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
        if (!zpci_fn_configured(slot->zdev->state))
                return -EIO;
 
+       if (slot->zdev->pdev)
+               pci_stop_and_remove_bus_device(slot->zdev->pdev);
+
        rc = zpci_disable_device(slot->zdev);
        if (rc)
                return rc;
-       /* TODO: we rely on the user to unbind/remove the device, is that plausible
-        *       or do we need to trigger that here?
-        */
-       rc = sclp_pci_deconfigure(slot->zdev->fid);
-       zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, rc);
-       if (!rc)
-               slot->zdev->state = ZPCI_FN_STATE_STANDBY;
-       return rc;
+
+       return slot_deconfigure(slot);
 }
 
 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
index 3100c52c837cfceccc7314646898f30846c96b39..d3f757df691c9c6bf46cbb26caca51ff59fb51e6 100644 (file)
@@ -128,8 +128,7 @@ static int init_slots(struct controller *ctrl)
                slot->hpc_ops = ctrl->hpc_ops;
                slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i);
 
-               snprintf(name, sizeof(name), "shpchp-%d", slot->number);
-               slot->wq = alloc_workqueue(name, 0, 0);
+               slot->wq = alloc_workqueue("shpchp-%d", 0, 0, slot->number);
                if (!slot->wq) {
                        retval = -ENOMEM;
                        goto error_info;
index 3c6bbdd059a459614ab2710f377d3f9796ccd3aa..1b90579b233ae8c2d7db5efe00cc022c42fbb73a 100644 (file)
@@ -113,17 +113,6 @@ static struct pci_driver ioapic_driver = {
        .remove         = ioapic_remove,
 };
 
-static int __init ioapic_init(void)
-{
-       return pci_register_driver(&ioapic_driver);
-}
-
-static void __exit ioapic_exit(void)
-{
-       pci_unregister_driver(&ioapic_driver);
-}
-
-module_init(ioapic_init);
-module_exit(ioapic_exit);
+module_pci_driver(ioapic_driver);
 
 MODULE_LICENSE("GPL");
index c93071d428f5d6d6cb038d5cb614e4117c5fd8aa..de8ffacf9c9b27cd1f758065e5b3f8158bab89b9 100644 (file)
@@ -47,51 +47,43 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
                return NULL;
 
        pci_bus_insert_busn_res(child, busnr, busnr);
-       bus->is_added = 1;
 
        return child;
 }
 
-static void virtfn_remove_bus(struct pci_bus *bus, int busnr)
+static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus)
 {
-       struct pci_bus *child;
-
-       if (bus->number == busnr)
-               return;
-
-       child = pci_find_bus(pci_domain_nr(bus), busnr);
-       BUG_ON(!child);
-
-       if (list_empty(&child->devices))
-               pci_remove_bus(child);
+       if (physbus != virtbus && list_empty(&virtbus->devices))
+               pci_remove_bus(virtbus);
 }
 
 static int virtfn_add(struct pci_dev *dev, int id, int reset)
 {
        int i;
-       int rc;
+       int rc = -ENOMEM;
        u64 size;
        char buf[VIRTFN_ID_LEN];
        struct pci_dev *virtfn;
        struct resource *res;
        struct pci_sriov *iov = dev->sriov;
+       struct pci_bus *bus;
 
-       virtfn = alloc_pci_dev();
+       mutex_lock(&iov->dev->sriov->lock);
+       bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id));
+       if (!bus)
+               goto failed;
+
+       virtfn = pci_alloc_dev(bus);
        if (!virtfn)
-               return -ENOMEM;
+               goto failed0;
 
-       mutex_lock(&iov->dev->sriov->lock);
-       virtfn->bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id));
-       if (!virtfn->bus) {
-               kfree(virtfn);
-               mutex_unlock(&iov->dev->sriov->lock);
-               return -ENOMEM;
-       }
        virtfn->devfn = virtfn_devfn(dev, id);
        virtfn->vendor = dev->vendor;
        pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device);
        pci_setup_device(virtfn);
        virtfn->dev.parent = dev->dev.parent;
+       virtfn->physfn = pci_dev_get(dev);
+       virtfn->is_virtfn = 1;
 
        for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
                res = dev->resource + PCI_IOV_RESOURCES + i;
@@ -113,9 +105,6 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
        pci_device_add(virtfn, virtfn->bus);
        mutex_unlock(&iov->dev->sriov->lock);
 
-       virtfn->physfn = pci_dev_get(dev);
-       virtfn->is_virtfn = 1;
-
        rc = pci_bus_add_device(virtfn);
        sprintf(buf, "virtfn%u", id);
        rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
@@ -135,7 +124,9 @@ failed1:
        pci_dev_put(dev);
        mutex_lock(&iov->dev->sriov->lock);
        pci_stop_and_remove_bus_device(virtfn);
-       virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
+failed0:
+       virtfn_remove_bus(dev->bus, bus);
+failed:
        mutex_unlock(&iov->dev->sriov->lock);
 
        return rc;
@@ -144,20 +135,15 @@ failed1:
 static void virtfn_remove(struct pci_dev *dev, int id, int reset)
 {
        char buf[VIRTFN_ID_LEN];
-       struct pci_bus *bus;
        struct pci_dev *virtfn;
        struct pci_sriov *iov = dev->sriov;
 
-       bus = pci_find_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id));
-       if (!bus)
-               return;
-
-       virtfn = pci_get_slot(bus, virtfn_devfn(dev, id));
+       virtfn = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus),
+                                            virtfn_bus(dev, id),
+                                            virtfn_devfn(dev, id));
        if (!virtfn)
                return;
 
-       pci_dev_put(virtfn);
-
        if (reset) {
                device_release_driver(&virtfn->dev);
                __pci_reset_function(virtfn);
@@ -175,9 +161,11 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
 
        mutex_lock(&iov->dev->sriov->lock);
        pci_stop_and_remove_bus_device(virtfn);
-       virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
+       virtfn_remove_bus(dev->bus, virtfn->bus);
        mutex_unlock(&iov->dev->sriov->lock);
 
+       /* balance pci_get_domain_bus_and_slot() */
+       pci_dev_put(virtfn);
        pci_dev_put(dev);
 }
 
@@ -334,13 +322,14 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
                if (!pdev)
                        return -ENODEV;
 
-               pci_dev_put(pdev);
-
-               if (!pdev->is_physfn)
+               if (!pdev->is_physfn) {
+                       pci_dev_put(pdev);
                        return -ENODEV;
+               }
 
                rc = sysfs_create_link(&dev->dev.kobj,
                                        &pdev->dev.kobj, "dep_link");
+               pci_dev_put(pdev);
                if (rc)
                        return rc;
        }
index 2c1075213beceac6bb0eb75be6aeef7adc8f34d7..aca7578b05e56205d854c6f76a5aac88c77d326e 100644 (file)
@@ -81,7 +81,10 @@ void default_teardown_msi_irqs(struct pci_dev *dev)
                int i, nvec;
                if (entry->irq == 0)
                        continue;
-               nvec = 1 << entry->msi_attrib.multiple;
+               if (entry->nvec_used)
+                       nvec = entry->nvec_used;
+               else
+                       nvec = 1 << entry->msi_attrib.multiple;
                for (i = 0; i < nvec; i++)
                        arch_teardown_msi_irq(entry->irq + i);
        }
@@ -336,7 +339,10 @@ static void free_msi_irqs(struct pci_dev *dev)
                int i, nvec;
                if (!entry->irq)
                        continue;
-               nvec = 1 << entry->msi_attrib.multiple;
+               if (entry->nvec_used)
+                       nvec = entry->nvec_used;
+               else
+                       nvec = 1 << entry->msi_attrib.multiple;
 #ifdef CONFIG_GENERIC_HARDIRQS
                for (i = 0; i < nvec; i++)
                        BUG_ON(irq_has_action(entry->irq + i));
index e4b1fb2c0f5d83029e0a62ffa4aaef36f4559da3..dbdc5f7e2b294fad4adfe3ae676e258c5af6abbe 100644 (file)
@@ -186,8 +186,8 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
                [PCI_D0] = ACPI_STATE_D0,
                [PCI_D1] = ACPI_STATE_D1,
                [PCI_D2] = ACPI_STATE_D2,
-               [PCI_D3hot] = ACPI_STATE_D3,
-               [PCI_D3cold] = ACPI_STATE_D3
+               [PCI_D3hot] = ACPI_STATE_D3_COLD,
+               [PCI_D3cold] = ACPI_STATE_D3_COLD,
        };
        int error = -EINVAL;
 
@@ -211,7 +211,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 
        if (!error)
                dev_info(&dev->dev, "power state changed by ACPI to %s\n",
-                        pci_power_name(state));
+                        acpi_power_state_string(state_conv[state]));
 
        return error;
 }
@@ -376,12 +376,12 @@ static int __init acpi_pci_init(void)
        int ret;
 
        if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) {
-               printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n");
+               pr_info("ACPI FADT declares the system doesn't support MSI, so disable it\n");
                pci_no_msi();
        }
 
        if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
-               printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
+               pr_info("ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
                pcie_no_aspm();
        }
 
index 79277fb36c6bf7a85b4634df28ff13d1905d703d..e6515e21afa3d7fdccd9edb1cbe68ea97253255c 100644 (file)
@@ -1050,26 +1050,22 @@ static int pci_pm_runtime_idle(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       int ret = 0;
 
        /*
         * If pci_dev->driver is not set (unbound), the device should
         * always remain in D0 regardless of the runtime PM status
         */
        if (!pci_dev->driver)
-               goto out;
+               return 0;
 
        if (!pm)
                return -ENOSYS;
 
-       if (pm->runtime_idle) {
-               int ret = pm->runtime_idle(dev);
-               if (ret)
-                       return ret;
-       }
+       if (pm->runtime_idle)
+               ret = pm->runtime_idle(dev);
 
-out:
-       pm_runtime_suspend(dev);
-       return 0;
+       return ret;
 }
 
 #else /* !CONFIG_PM_RUNTIME */
index 5b4a9d9cd200dd5a6ee32c3d343bbae0cf2ff8ac..c0dbe1f61362aa058db84ffb971671a6ce35e8cd 100644 (file)
@@ -66,7 +66,7 @@ static ssize_t broken_parity_status_store(struct device *dev,
        struct pci_dev *pdev = to_pci_dev(dev);
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val) < 0)
+       if (kstrtoul(buf, 0, &val) < 0)
                return -EINVAL;
 
        pdev->broken_parity_status = !!val;
@@ -188,7 +188,7 @@ static ssize_t is_enabled_store(struct device *dev,
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        unsigned long val;
-       ssize_t result = strict_strtoul(buf, 0, &val);
+       ssize_t result = kstrtoul(buf, 0, &val);
 
        if (result < 0)
                return result;
@@ -259,7 +259,7 @@ msi_bus_store(struct device *dev, struct device_attribute *attr,
        struct pci_dev *pdev = to_pci_dev(dev);
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val) < 0)
+       if (kstrtoul(buf, 0, &val) < 0)
                return -EINVAL;
 
        /* bad things may happen if the no_msi flag is changed
@@ -291,7 +291,7 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
        unsigned long val;
        struct pci_bus *b = NULL;
 
-       if (strict_strtoul(buf, 0, &val) < 0)
+       if (kstrtoul(buf, 0, &val) < 0)
                return -EINVAL;
 
        if (val) {
@@ -315,7 +315,7 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr,
        unsigned long val;
        struct pci_dev *pdev = to_pci_dev(dev);
 
-       if (strict_strtoul(buf, 0, &val) < 0)
+       if (kstrtoul(buf, 0, &val) < 0)
                return -EINVAL;
 
        if (val) {
@@ -325,6 +325,8 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr,
        }
        return count;
 }
+struct device_attribute dev_rescan_attr = __ATTR(rescan, (S_IWUSR|S_IWGRP),
+                                                NULL, dev_rescan_store);
 
 static void remove_callback(struct device *dev)
 {
@@ -342,7 +344,7 @@ remove_store(struct device *dev, struct device_attribute *dummy,
        int ret = 0;
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val) < 0)
+       if (kstrtoul(buf, 0, &val) < 0)
                return -EINVAL;
 
        /* An attribute cannot be unregistered by one of its own methods,
@@ -354,6 +356,8 @@ remove_store(struct device *dev, struct device_attribute *dummy,
                count = ret;
        return count;
 }
+struct device_attribute dev_remove_attr = __ATTR(remove, (S_IWUSR|S_IWGRP),
+                                                NULL, remove_store);
 
 static ssize_t
 dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
@@ -362,7 +366,7 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
        unsigned long val;
        struct pci_bus *bus = to_pci_bus(dev);
 
-       if (strict_strtoul(buf, 0, &val) < 0)
+       if (kstrtoul(buf, 0, &val) < 0)
                return -EINVAL;
 
        if (val) {
@@ -384,7 +388,7 @@ static ssize_t d3cold_allowed_store(struct device *dev,
        struct pci_dev *pdev = to_pci_dev(dev);
        unsigned long val;
 
-       if (strict_strtoul(buf, 0, &val) < 0)
+       if (kstrtoul(buf, 0, &val) < 0)
                return -EINVAL;
 
        pdev->d3cold_allowed = !!val;
@@ -504,8 +508,6 @@ struct device_attribute pci_dev_attrs[] = {
        __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
                broken_parity_status_show,broken_parity_status_store),
        __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
-       __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store),
-       __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store),
 #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
        __ATTR(d3cold_allowed, 0644, d3cold_allowed_show, d3cold_allowed_store),
 #endif
@@ -1236,7 +1238,7 @@ static ssize_t reset_store(struct device *dev,
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        unsigned long val;
-       ssize_t result = strict_strtoul(buf, 0, &val);
+       ssize_t result = kstrtoul(buf, 0, &val);
 
        if (result < 0)
                return result;
@@ -1463,6 +1465,29 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj,
        return a->mode;
 }
 
+static struct attribute *pci_dev_hp_attrs[] = {
+       &dev_remove_attr.attr,
+       &dev_rescan_attr.attr,
+       NULL,
+};
+
+static umode_t pci_dev_hp_attrs_are_visible(struct kobject *kobj,
+                                               struct attribute *a, int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct pci_dev *pdev = to_pci_dev(dev);
+
+       if (pdev->is_virtfn)
+               return 0;
+
+       return a->mode;
+}
+
+static struct attribute_group pci_dev_hp_attr_group = {
+       .attrs = pci_dev_hp_attrs,
+       .is_visible = pci_dev_hp_attrs_are_visible,
+};
+
 #ifdef CONFIG_PCI_IOV
 static struct attribute *sriov_dev_attrs[] = {
        &sriov_totalvfs_attr.attr,
@@ -1494,6 +1519,7 @@ static struct attribute_group pci_dev_attr_group = {
 
 static const struct attribute_group *pci_dev_attr_groups[] = {
        &pci_dev_attr_group,
+       &pci_dev_hp_attr_group,
 #ifdef CONFIG_PCI_IOV
        &sriov_dev_attr_group,
 #endif
index a899d8bb190d897e014f605eec53b496152a0cea..e37fea6e178d2dab00d3334848d231117d525013 100644 (file)
@@ -805,7 +805,7 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
 {
        pci_power_t ret;
 
-       if (!pci_find_capability(dev, PCI_CAP_ID_PM))
+       if (!dev->pm_cap)
                return PCI_D0;
 
        ret = platform_pci_choose_state(dev);
@@ -1334,6 +1334,16 @@ int __weak pcibios_add_device (struct pci_dev *dev)
        return 0;
 }
 
+/**
+ * pcibios_release_device - provide arch specific hooks when releasing device dev
+ * @dev: the PCI device being released
+ *
+ * Permits the platform to provide architecture specific functionality when
+ * devices are released. This is the default implementation. Architecture
+ * implementations can override this.
+ */
+void __weak pcibios_release_device(struct pci_dev *dev) {}
+
 /**
  * pcibios_disable_device - disable arch specific PCI resources for device dev
  * @dev: the PCI device to disable
@@ -2421,7 +2431,7 @@ bool pci_acs_path_enabled(struct pci_dev *start,
 /**
  * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
  * @dev: the PCI device
- * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
+ * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)
  *
  * Perform INTx swizzling for a device behind one level of bridge.  This is
  * required by section 9.1 of the PCI-to-PCI bridge specification for devices
index d12c77cd6991f75c8b62008dc4ce160d6ffec36f..90ea3e88041f74c25f3339d77cf8d4929784edfb 100644 (file)
 #include <linux/aer.h>
 #include <linux/interrupt.h>
 
-#define AER_NONFATAL                   0
-#define AER_FATAL                      1
-#define AER_CORRECTABLE                        2
-
 #define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE|   \
                                        PCI_EXP_RTCTL_SENFEE|   \
                                        PCI_EXP_RTCTL_SEFEE)
index 5194a7d41730ab4ab1d60d26b836ce84af839b10..cf611ab2193a618880e94303d9bdbe93cd1fdf7e 100644 (file)
@@ -29,6 +29,22 @@ static inline int hest_match_pci(struct acpi_hest_aer_common *p,
                 p->function == PCI_FUNC(pci->devfn));
 }
 
+static inline bool hest_match_type(struct acpi_hest_header *hest_hdr,
+                               struct pci_dev *dev)
+{
+       u16 hest_type = hest_hdr->type;
+       u8 pcie_type = pci_pcie_type(dev);
+
+       if ((hest_type == ACPI_HEST_TYPE_AER_ROOT_PORT &&
+               pcie_type == PCI_EXP_TYPE_ROOT_PORT) ||
+           (hest_type == ACPI_HEST_TYPE_AER_ENDPOINT &&
+               pcie_type == PCI_EXP_TYPE_ENDPOINT) ||
+           (hest_type == ACPI_HEST_TYPE_AER_BRIDGE &&
+               (dev->class >> 16) == PCI_BASE_CLASS_BRIDGE))
+               return true;
+       return false;
+}
+
 struct aer_hest_parse_info {
        struct pci_dev *pci_dev;
        int firmware_first;
@@ -38,34 +54,16 @@ static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
 {
        struct aer_hest_parse_info *info = data;
        struct acpi_hest_aer_common *p;
-       u8 pcie_type = 0;
-       u8 bridge = 0;
-       int ff = 0;
-
-       switch (hest_hdr->type) {
-       case ACPI_HEST_TYPE_AER_ROOT_PORT:
-               pcie_type = PCI_EXP_TYPE_ROOT_PORT;
-               break;
-       case ACPI_HEST_TYPE_AER_ENDPOINT:
-               pcie_type = PCI_EXP_TYPE_ENDPOINT;
-               break;
-       case ACPI_HEST_TYPE_AER_BRIDGE:
-               if ((info->pci_dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
-                       bridge = 1;
-               break;
-       default:
-               return 0;
-       }
+       int ff;
 
        p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
+       ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
        if (p->flags & ACPI_HEST_GLOBAL) {
-               if ((pci_is_pcie(info->pci_dev) &&
-                    pci_pcie_type(info->pci_dev) == pcie_type) || bridge)
-                       ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
+               if (hest_match_type(hest_hdr, info->pci_dev))
+                       info->firmware_first = ff;
        } else
                if (hest_match_pci(p, info->pci_dev))
-                       ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
-       info->firmware_first = ff;
+                       info->firmware_first = ff;
 
        return 0;
 }
@@ -89,6 +87,9 @@ static void aer_set_firmware_first(struct pci_dev *pci_dev)
 
 int pcie_aer_get_firmware_first(struct pci_dev *dev)
 {
+       if (!pci_is_pcie(dev))
+               return 0;
+
        if (!dev->__aer_firmware_first_valid)
                aer_set_firmware_first(dev);
        return dev->__aer_firmware_first;
index 0f4554e48cc5f52850d766078dff76f8c1cdc4d0..8b68ae59b7b6446f6405291ac868df18fdccee7c 100644 (file)
@@ -400,16 +400,16 @@ void aer_do_secondary_bus_reset(struct pci_dev *dev)
 }
 
 /**
- * default_downstream_reset_link - default reset function for Downstream Port
- * @dev: pointer to downstream port's pci_dev data structure
+ * default_reset_link - default reset function
+ * @dev: pointer to pci_dev data structure
  *
- * Invoked when performing link reset at Downstream Port w/ no aer driver.
+ * Invoked when performing link reset on a Downstream Port or a
+ * Root Port with no aer driver.
  */
-static pci_ers_result_t default_downstream_reset_link(struct pci_dev *dev)
+static pci_ers_result_t default_reset_link(struct pci_dev *dev)
 {
        aer_do_secondary_bus_reset(dev);
-       dev_printk(KERN_DEBUG, &dev->dev,
-               "Downstream Port link has been reset\n");
+       dev_printk(KERN_DEBUG, &dev->dev, "downstream link has been reset\n");
        return PCI_ERS_RESULT_RECOVERED;
 }
 
@@ -458,8 +458,9 @@ static pci_ers_result_t reset_link(struct pci_dev *dev)
 
        if (driver && driver->reset_link) {
                status = driver->reset_link(udev);
-       } else if (pci_pcie_type(udev) == PCI_EXP_TYPE_DOWNSTREAM) {
-               status = default_downstream_reset_link(udev);
+       } else if (pci_pcie_type(udev) == PCI_EXP_TYPE_DOWNSTREAM ||
+               pci_pcie_type(udev) == PCI_EXP_TYPE_ROOT_PORT) {
+               status = default_reset_link(udev);
        } else {
                dev_printk(KERN_DEBUG, &dev->dev,
                        "no link-reset support at upstream device %s\n",
index d320df6375a2c807f8a45a8badc247bf16a956bf..403a44374ed5e160cbd0f6a0a865a5ab35de139c 100644 (file)
@@ -714,19 +714,12 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
        up_read(&pci_bus_sem);
 }
 
-/*
- * pci_disable_link_state - disable pci device's link state, so the link will
- * never enter specific states
- */
 static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem,
                                     bool force)
 {
        struct pci_dev *parent = pdev->bus->self;
        struct pcie_link_state *link;
 
-       if (aspm_disabled && !force)
-               return;
-
        if (!pci_is_pcie(pdev))
                return;
 
@@ -736,6 +729,19 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem,
        if (!parent || !parent->link_state)
                return;
 
+       /*
+        * A driver requested that ASPM be disabled on this device, but
+        * if we don't have permission to manage ASPM (e.g., on ACPI
+        * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and
+        * the _OSC method), we can't honor that request.  Windows has
+        * a similar mechanism using "PciASPMOptOut", which is also
+        * ignored in this situation.
+        */
+       if (aspm_disabled && !force) {
+               dev_warn(&pdev->dev, "can't disable ASPM; OS doesn't have ASPM control\n");
+               return;
+       }
+
        if (sem)
                down_read(&pci_bus_sem);
        mutex_lock(&aspm_lock);
@@ -761,6 +767,15 @@ void pci_disable_link_state_locked(struct pci_dev *pdev, int state)
 }
 EXPORT_SYMBOL(pci_disable_link_state_locked);
 
+/**
+ * pci_disable_link_state - Disable device's link state, so the link will
+ * never enter specific states.  Note that if the BIOS didn't grant ASPM
+ * control to the OS, this does nothing because we can't touch the LNKCTL
+ * register.
+ *
+ * @pdev: PCI device
+ * @state: ASPM link state to disable
+ */
 void pci_disable_link_state(struct pci_dev *pdev, int state)
 {
        __pci_disable_link_state(pdev, state, true, false);
index 795db1f9d50c695893419b766697850c17511752..e56e594ce112fd2f8f15696d9036054e03aa9f63 100644 (file)
@@ -408,7 +408,7 @@ static int pcie_pme_resume(struct pcie_device *srv)
 
 /**
  * pcie_pme_remove - Prepare PCIe PME service device for removal.
- * @srv - PCIe service device to resume.
+ * @srv - PCIe service device to remove.
  */
 static void pcie_pme_remove(struct pcie_device *srv)
 {
index 70f10fa3c1b216ab88e04471c171d8404f107770..46ada5c098ebed710f24a7deb426720149b219fd 100644 (file)
@@ -170,7 +170,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
 {
        u32 l, sz, mask;
        u16 orig_cmd;
-       struct pci_bus_region region;
+       struct pci_bus_region region, inverted_region;
        bool bar_too_big = false, bar_disabled = false;
 
        mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
@@ -250,12 +250,10 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                        pci_write_config_dword(dev, pos + 4, 0);
                        region.start = 0;
                        region.end = sz64;
-                       pcibios_bus_to_resource(dev, res, &region);
                        bar_disabled = true;
                } else {
                        region.start = l64;
                        region.end = l64 + sz64;
-                       pcibios_bus_to_resource(dev, res, &region);
                }
        } else {
                sz = pci_size(l, sz, mask);
@@ -265,7 +263,28 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
 
                region.start = l;
                region.end = l + sz;
-               pcibios_bus_to_resource(dev, res, &region);
+       }
+
+       pcibios_bus_to_resource(dev, res, &region);
+       pcibios_resource_to_bus(dev, &inverted_region, res);
+
+       /*
+        * If "A" is a BAR value (a bus address), "bus_to_resource(A)" is
+        * the corresponding resource address (the physical address used by
+        * the CPU.  Converting that resource address back to a bus address
+        * should yield the original BAR value:
+        *
+        *     resource_to_bus(bus_to_resource(A)) == A
+        *
+        * If it doesn't, CPU accesses to "bus_to_resource(A)" will not
+        * be claimed by the device.
+        */
+       if (inverted_region.start != region.start) {
+               dev_info(&dev->dev, "reg 0x%x: initial BAR value %pa invalid; forcing reassignment\n",
+                        pos, &region.start);
+               res->flags |= IORESOURCE_UNSET;
+               res->end -= res->start;
+               res->start = 0;
        }
 
        goto out;
@@ -278,9 +297,9 @@ out:
                pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
 
        if (bar_too_big)
-               dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", pos);
+               dev_err(&dev->dev, "reg 0x%x: can't handle 64-bit BAR\n", pos);
        if (res->flags && !bar_disabled)
-               dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res);
+               dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res);
 
        return (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
 }
@@ -451,33 +470,46 @@ void pci_read_bridge_bases(struct pci_bus *child)
        }
 }
 
-static struct pci_bus * pci_alloc_bus(void)
+static struct pci_bus *pci_alloc_bus(void)
 {
        struct pci_bus *b;
 
        b = kzalloc(sizeof(*b), GFP_KERNEL);
-       if (b) {
-               INIT_LIST_HEAD(&b->node);
-               INIT_LIST_HEAD(&b->children);
-               INIT_LIST_HEAD(&b->devices);
-               INIT_LIST_HEAD(&b->slots);
-               INIT_LIST_HEAD(&b->resources);
-               b->max_bus_speed = PCI_SPEED_UNKNOWN;
-               b->cur_bus_speed = PCI_SPEED_UNKNOWN;
-       }
+       if (!b)
+               return NULL;
+
+       INIT_LIST_HEAD(&b->node);
+       INIT_LIST_HEAD(&b->children);
+       INIT_LIST_HEAD(&b->devices);
+       INIT_LIST_HEAD(&b->slots);
+       INIT_LIST_HEAD(&b->resources);
+       b->max_bus_speed = PCI_SPEED_UNKNOWN;
+       b->cur_bus_speed = PCI_SPEED_UNKNOWN;
        return b;
 }
 
+static void pci_release_host_bridge_dev(struct device *dev)
+{
+       struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
+
+       if (bridge->release_fn)
+               bridge->release_fn(bridge);
+
+       pci_free_resource_list(&bridge->windows);
+
+       kfree(bridge);
+}
+
 static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
 {
        struct pci_host_bridge *bridge;
 
        bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
-       if (bridge) {
-               INIT_LIST_HEAD(&bridge->windows);
-               bridge->bus = b;
-       }
+       if (!bridge)
+               return NULL;
 
+       INIT_LIST_HEAD(&bridge->windows);
+       bridge->bus = b;
        return bridge;
 }
 
@@ -1132,6 +1164,8 @@ static void pci_release_dev(struct device *dev)
        pci_dev = to_pci_dev(dev);
        pci_release_capabilities(pci_dev);
        pci_release_of_node(pci_dev);
+       pcibios_release_device(pci_dev);
+       pci_bus_put(pci_dev->bus);
        kfree(pci_dev);
 }
 
@@ -1188,19 +1222,7 @@ int pci_cfg_space_size(struct pci_dev *dev)
        return PCI_CFG_SPACE_SIZE;
 }
 
-static void pci_release_bus_bridge_dev(struct device *dev)
-{
-       struct pci_host_bridge *bridge = to_pci_host_bridge(dev);
-
-       if (bridge->release_fn)
-               bridge->release_fn(bridge);
-
-       pci_free_resource_list(&bridge->windows);
-
-       kfree(bridge);
-}
-
-struct pci_dev *alloc_pci_dev(void)
+struct pci_dev *pci_alloc_dev(struct pci_bus *bus)
 {
        struct pci_dev *dev;
 
@@ -1210,9 +1232,16 @@ struct pci_dev *alloc_pci_dev(void)
 
        INIT_LIST_HEAD(&dev->bus_list);
        dev->dev.type = &pci_dev_type;
+       dev->bus = pci_bus_get(bus);
 
        return dev;
 }
+EXPORT_SYMBOL(pci_alloc_dev);
+
+struct pci_dev *alloc_pci_dev(void)
+{
+       return pci_alloc_dev(NULL);
+}
 EXPORT_SYMBOL(alloc_pci_dev);
 
 bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
@@ -1263,11 +1292,10 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
        if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000))
                return NULL;
 
-       dev = alloc_pci_dev();
+       dev = pci_alloc_dev(bus);
        if (!dev)
                return NULL;
 
-       dev->bus = bus;
        dev->devfn = devfn;
        dev->vendor = l & 0xffff;
        dev->device = (l >> 16) & 0xffff;
@@ -1275,6 +1303,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
        pci_set_of_node(dev);
 
        if (pci_setup_device(dev)) {
+               pci_bus_put(dev->bus);
                kfree(dev);
                return NULL;
        }
@@ -1700,15 +1729,19 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
                goto err_out;
 
        bridge->dev.parent = parent;
-       bridge->dev.release = pci_release_bus_bridge_dev;
+       bridge->dev.release = pci_release_host_bridge_dev;
        dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
        error = pcibios_root_bridge_prepare(bridge);
-       if (error)
-               goto bridge_dev_reg_err;
+       if (error) {
+               kfree(bridge);
+               goto err_out;
+       }
 
        error = device_register(&bridge->dev);
-       if (error)
-               goto bridge_dev_reg_err;
+       if (error) {
+               put_device(&bridge->dev);
+               goto err_out;
+       }
        b->bridge = get_device(&bridge->dev);
        device_enable_async_suspend(b->bridge);
        pci_set_bus_of_node(b);
@@ -1764,8 +1797,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 class_dev_reg_err:
        put_device(&bridge->dev);
        device_unregister(&bridge->dev);
-bridge_dev_reg_err:
-       kfree(bridge);
 err_out:
        kfree(b);
        return NULL;
index 08126087ec3125c29de84c5b9e5f68d45d2b0328..cdc7836d7e3de3ab710341b3feef63c1ff3b3a47 100644 (file)
@@ -20,27 +20,8 @@ static int proc_initialized; /* = 0 */
 static loff_t
 proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
 {
-       loff_t new = -1;
-       struct inode *inode = file_inode(file);
-
-       mutex_lock(&inode->i_mutex);
-       switch (whence) {
-       case 0:
-               new = off;
-               break;
-       case 1:
-               new = file->f_pos + off;
-               break;
-       case 2:
-               new = inode->i_size + off;
-               break;
-       }
-       if (new < 0 || new > inode->i_size)
-               new = -EINVAL;
-       else
-               file->f_pos = new;
-       mutex_unlock(&inode->i_mutex);
-       return new;
+       struct pci_dev *dev = PDE_DATA(file_inode(file));
+       return fixed_size_llseek(file, off, whence, dev->cfg_size);
 }
 
 static ssize_t
index 7d68aeebf56b1a53d447bd0e152643d85d06ea44..e85d23044ae0dcd43b20d0b840a71e551286a310 100644 (file)
@@ -1022,6 +1022,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk
 DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE, quirk_amd_ide_mode);
 DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE, quirk_amd_ide_mode);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x7900, quirk_amd_ide_mode);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, 0x7900, quirk_amd_ide_mode);
 
 /*
  *     Serverworks CSB5 IDE does not fully support native mode
@@ -1832,7 +1834,6 @@ static void quirk_e100_interrupt(struct pci_dev *dev)
        u16 command, pmcsr;
        u8 __iomem *csr;
        u8 cmd_hi;
-       int pm;
 
        switch (dev->device) {
        /* PCI IDs taken from drivers/net/e100.c */
@@ -1870,9 +1871,8 @@ static void quirk_e100_interrupt(struct pci_dev *dev)
         * Check that the device is in the D0 power state. If it's not,
         * there is no point to look any further.
         */
-       pm = pci_find_capability(dev, PCI_CAP_ID_PM);
-       if (pm) {
-               pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+       if (dev->pm_cap) {
+               pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
                if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0)
                        return;
        }
@@ -2865,6 +2865,31 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
 
 
+/*
+ * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum.  To
+ * work around this, query the size it should be configured to by the device and
+ * modify the resource end to correspond to this new size.
+ */
+static void quirk_intel_ntb(struct pci_dev *dev)
+{
+       int rc;
+       u8 val;
+
+       rc = pci_read_config_byte(dev, 0x00D0, &val);
+       if (rc)
+               return;
+
+       dev->resource[2].end = dev->resource[2].start + ((u64) 1 << val) - 1;
+
+       rc = pci_read_config_byte(dev, 0x00D1, &val);
+       if (rc)
+               return;
+
+       dev->resource[4].end = dev->resource[4].start + ((u64) 1 << val) - 1;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb);
+
 static ktime_t fixup_debug_start(struct pci_dev *dev,
                                 void (*fn)(struct pci_dev *dev))
 {
index 966abc6054d7b625c18a5eeb854dc065b40d43c1..f7197a790341a0c1de8b4a7dfa2c22377cfdf5c5 100644 (file)
@@ -678,10 +678,9 @@ static int pcifront_connect_and_init_dma(struct pcifront_device *pdev)
        if (!pcifront_dev) {
                dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
                pcifront_dev = pdev;
-       } else {
-               dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
+       } else
                err = -EEXIST;
-       }
+
        spin_unlock(&pcifront_dev_lock);
 
        if (!err && !swiotlb_nr_tbl()) {
@@ -848,7 +847,7 @@ static int pcifront_try_connect(struct pcifront_device *pdev)
                goto out;
 
        err = pcifront_connect_and_init_dma(pdev);
-       if (err) {
+       if (err && err != -EEXIST) {
                xenbus_dev_fatal(pdev->xdev, err,
                                 "Error setting up PCI Frontend");
                goto out;
index 901a388dbea7d4b21a98522fe64e7e5dab5f4dab..5a8ad513931253766e976eb4dafff02480167b3c 100644 (file)
@@ -58,6 +58,18 @@ config PINCTRL_AT91
        help
          Say Y here to enable the at91 pinctrl driver
 
+config PINCTRL_BAYTRAIL
+       bool "Intel Baytrail GPIO pin control"
+       depends on GPIOLIB && ACPI && X86
+        select IRQ_DOMAIN
+       help
+         driver for memory mapped GPIO functionality on Intel Baytrail
+         platforms. Supports 3 banks with 102, 28 and 44 gpios.
+         Most pins are usually muxed to some other functionality by firmware,
+         so only a small amount is available for gpio use.
+
+         Requires ACPI device enumeration code to set up a platform device.
+
 config PINCTRL_BCM2835
        bool
        select PINMUX
@@ -108,6 +120,14 @@ config PINCTRL_IMX6SL
        help
          Say Y here to enable the imx6sl pinctrl driver
 
+config PINCTRL_VF610
+       bool "Freescale Vybrid VF610 pinctrl driver"
+       depends on OF
+       depends on SOC_VF610
+       select PINCTRL_IMX
+       help
+         Say Y here to enable the Freescale Vybrid VF610 pinctrl driver
+
 config PINCTRL_LANTIQ
        bool
        depends on LANTIQ
@@ -150,6 +170,12 @@ config PINCTRL_DB8540
        bool "DB8540 pin controller driver"
        depends on PINCTRL_NOMADIK && ARCH_U8500
 
+config PINCTRL_ROCKCHIP
+       bool
+       select PINMUX
+       select GENERIC_PINCONF
+       select GENERIC_IRQ_CHIP
+
 config PINCTRL_SINGLE
        tristate "One-register-per-pin type device tree based pinctrl driver"
        depends on OF
@@ -169,6 +195,12 @@ config PINCTRL_SUNXI
        select PINMUX
        select GENERIC_PINCONF
 
+config PINCTRL_ST
+       bool
+       depends on OF
+       select PINMUX
+       select PINCONF
+
 config PINCTRL_TEGRA
        bool
        select PINMUX
@@ -186,6 +218,18 @@ config PINCTRL_TEGRA114
        bool
        select PINCTRL_TEGRA
 
+config PINCTRL_TZ1090
+       bool "Toumaz Xenif TZ1090 pin control driver"
+       depends on SOC_TZ1090
+       select PINMUX
+       select GENERIC_PINCONF
+
+config PINCTRL_TZ1090_PDC
+       bool "Toumaz Xenif TZ1090 PDC pin control driver"
+       depends on SOC_TZ1090
+       select PINMUX
+       select PINCONF
+
 config PINCTRL_U300
        bool "U300 pin controller driver"
        depends on ARCH_U300
index f90b645fb601027465a6c66bcd8e845971536f87..d64563bf6fb4d83c12ff8f01ad566b72700c3092 100644 (file)
@@ -16,12 +16,14 @@ obj-$(CONFIG_PINCTRL_AB9540)        += pinctrl-ab9540.o
 obj-$(CONFIG_PINCTRL_AB8505)   += pinctrl-ab8505.o
 obj-$(CONFIG_PINCTRL_AT91)     += pinctrl-at91.o
 obj-$(CONFIG_PINCTRL_BCM2835)  += pinctrl-bcm2835.o
+obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o
 obj-$(CONFIG_PINCTRL_IMX)      += pinctrl-imx.o
 obj-$(CONFIG_PINCTRL_IMX35)    += pinctrl-imx35.o
 obj-$(CONFIG_PINCTRL_IMX51)    += pinctrl-imx51.o
 obj-$(CONFIG_PINCTRL_IMX53)    += pinctrl-imx53.o
 obj-$(CONFIG_PINCTRL_IMX6Q)    += pinctrl-imx6q.o
 obj-$(CONFIG_PINCTRL_IMX6Q)    += pinctrl-imx6dl.o
+obj-$(CONFIG_PINCTRL_IMX6SL)   += pinctrl-imx6sl.o
 obj-$(CONFIG_PINCTRL_FALCON)   += pinctrl-falcon.o
 obj-$(CONFIG_PINCTRL_MXS)      += pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_IMX23)    += pinctrl-imx23.o
@@ -30,13 +32,16 @@ obj-$(CONFIG_PINCTRL_NOMADIK)       += pinctrl-nomadik.o
 obj-$(CONFIG_PINCTRL_STN8815)  += pinctrl-nomadik-stn8815.o
 obj-$(CONFIG_PINCTRL_DB8500)   += pinctrl-nomadik-db8500.o
 obj-$(CONFIG_PINCTRL_DB8540)   += pinctrl-nomadik-db8540.o
+obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
 obj-$(CONFIG_PINCTRL_SINGLE)   += pinctrl-single.o
-obj-$(CONFIG_PINCTRL_SIRF)     += pinctrl-sirf.o
+obj-$(CONFIG_PINCTRL_SIRF)     += sirf/
 obj-$(CONFIG_PINCTRL_SUNXI)    += pinctrl-sunxi.o
 obj-$(CONFIG_PINCTRL_TEGRA)    += pinctrl-tegra.o
 obj-$(CONFIG_PINCTRL_TEGRA20)  += pinctrl-tegra20.o
 obj-$(CONFIG_PINCTRL_TEGRA30)  += pinctrl-tegra30.o
 obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o
+obj-$(CONFIG_PINCTRL_TZ1090)   += pinctrl-tz1090.o
+obj-$(CONFIG_PINCTRL_TZ1090_PDC)       += pinctrl-tz1090-pdc.o
 obj-$(CONFIG_PINCTRL_U300)     += pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_COH901)   += pinctrl-coh901.o
 obj-$(CONFIG_PINCTRL_SAMSUNG)  += pinctrl-samsung.o
@@ -46,6 +51,8 @@ obj-$(CONFIG_PINCTRL_S3C24XX) += pinctrl-s3c24xx.o
 obj-$(CONFIG_PINCTRL_S3C64XX)  += pinctrl-s3c64xx.o
 obj-$(CONFIG_PINCTRL_XWAY)     += pinctrl-xway.o
 obj-$(CONFIG_PINCTRL_LANTIQ)   += pinctrl-lantiq.o
+obj-$(CONFIG_PINCTRL_ST)       += pinctrl-st.o
+obj-$(CONFIG_PINCTRL_VF610)    += pinctrl-vf610.o
 
 obj-$(CONFIG_PLAT_ORION)        += mvebu/
 obj-$(CONFIG_ARCH_SHMOBILE)    += sh-pfc/
index 5327f35d9b5cd6d12147faf7fd93556157c1c6f4..5b272bfd261d6803fad6eaac61a3fa28dab4e767 100644 (file)
 static bool pinctrl_dummy_state;
 
 /* Mutex taken to protect pinctrl_list */
-DEFINE_MUTEX(pinctrl_list_mutex);
+static DEFINE_MUTEX(pinctrl_list_mutex);
 
 /* Mutex taken to protect pinctrl_maps */
 DEFINE_MUTEX(pinctrl_maps_mutex);
 
 /* Mutex taken to protect pinctrldev_list */
-DEFINE_MUTEX(pinctrldev_list_mutex);
+static DEFINE_MUTEX(pinctrldev_list_mutex);
 
 /* Global list of pin control devices (struct pinctrl_dev) */
 static LIST_HEAD(pinctrldev_list);
@@ -101,20 +101,23 @@ EXPORT_SYMBOL_GPL(pinctrl_dev_get_drvdata);
 struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname)
 {
        struct pinctrl_dev *pctldev = NULL;
-       bool found = false;
 
        if (!devname)
                return NULL;
 
+       mutex_lock(&pinctrldev_list_mutex);
+
        list_for_each_entry(pctldev, &pinctrldev_list, node) {
                if (!strcmp(dev_name(pctldev->dev), devname)) {
                        /* Matched on device name */
-                       found = true;
-                       break;
+                       mutex_unlock(&pinctrldev_list_mutex);
+                       return pctldev;
                }
        }
 
-       return found ? pctldev : NULL;
+       mutex_unlock(&pinctrldev_list_mutex);
+
+       return NULL;
 }
 
 struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np)
@@ -279,6 +282,29 @@ static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
        return 0;
 }
 
+/**
+ * gpio_to_pin() - GPIO range GPIO number to pin number translation
+ * @range: GPIO range used for the translation
+ * @gpio: gpio pin to translate to a pin number
+ *
+ * Finds the pin number for a given GPIO using the specified GPIO range
+ * as a base for translation. The distinction between linear GPIO ranges
+ * and pin list based GPIO ranges is managed correctly by this function.
+ *
+ * This function assumes the gpio is part of the specified GPIO range, use
+ * only after making sure this is the case (e.g. by calling it on the
+ * result of successful pinctrl_get_device_gpio_range calls)!
+ */
+static inline int gpio_to_pin(struct pinctrl_gpio_range *range,
+                               unsigned int gpio)
+{
+       unsigned int offset = gpio - range->base;
+       if (range->pins)
+               return range->pins[offset];
+       else
+               return range->pin_base + offset;
+}
+
 /**
  * pinctrl_match_gpio_range() - check if a certain GPIO pin is in range
  * @pctldev: pin controller device to check
@@ -326,6 +352,8 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio)
        struct pinctrl_gpio_range *range = NULL;
        struct gpio_chip *chip = gpio_to_chip(gpio);
 
+       mutex_lock(&pinctrldev_list_mutex);
+
        /* Loop over the pin controllers */
        list_for_each_entry(pctldev, &pinctrldev_list, node) {
                /* Loop over the ranges */
@@ -334,9 +362,13 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio)
                        if (range->base + range->npins - 1 < chip->base ||
                            range->base > chip->base + chip->ngpio - 1)
                                continue;
+                       mutex_unlock(&pinctrldev_list_mutex);
                        return true;
                }
        }
+
+       mutex_unlock(&pinctrldev_list_mutex);
+
        return false;
 }
 #else
@@ -408,8 +440,6 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
 {
        struct pinctrl_dev *pctldev;
 
-       mutex_lock(&pinctrldev_list_mutex);
-
        pctldev = get_pinctrl_dev_from_devname(devname);
 
        /*
@@ -418,13 +448,10 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
         * range need to defer probing.
         */
        if (!pctldev) {
-               mutex_unlock(&pinctrldev_list_mutex);
                return ERR_PTR(-EPROBE_DEFER);
        }
        pinctrl_add_gpio_range(pctldev, range);
 
-       mutex_unlock(&pinctrldev_list_mutex);
-
        return pctldev;
 }
 EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range);
@@ -438,21 +465,26 @@ struct pinctrl_gpio_range *
 pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
                                 unsigned int pin)
 {
-       struct pinctrl_gpio_range *range = NULL;
+       struct pinctrl_gpio_range *range;
 
        mutex_lock(&pctldev->mutex);
        /* Loop over the ranges */
        list_for_each_entry(range, &pctldev->gpio_ranges, node) {
                /* Check if we're in the valid range */
-               if (pin >= range->pin_base &&
-                   pin < range->pin_base + range->npins) {
-                       mutex_unlock(&pctldev->mutex);
-                       return range;
-               }
+               if (range->pins) {
+                       int a;
+                       for (a = 0; a < range->npins; a++) {
+                               if (range->pins[a] == pin)
+                                       goto out;
+                       }
+               } else if (pin >= range->pin_base &&
+                          pin < range->pin_base + range->npins)
+                       goto out;
        }
+       range = NULL;
+out:
        mutex_unlock(&pctldev->mutex);
-
-       return NULL;
+       return range;
 }
 EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin);
 
@@ -517,22 +549,18 @@ int pinctrl_request_gpio(unsigned gpio)
        int ret;
        int pin;
 
-       mutex_lock(&pinctrldev_list_mutex);
-
        ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
        if (ret) {
                if (pinctrl_ready_for_gpio_range(gpio))
                        ret = 0;
-               mutex_unlock(&pinctrldev_list_mutex);
                return ret;
        }
 
        /* Convert to the pin controllers number space */
-       pin = gpio - range->base + range->pin_base;
+       pin = gpio_to_pin(range, gpio);
 
        ret = pinmux_request_gpio(pctldev, range, pin, gpio);
 
-       mutex_unlock(&pinctrldev_list_mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(pinctrl_request_gpio);
@@ -552,22 +580,18 @@ void pinctrl_free_gpio(unsigned gpio)
        int ret;
        int pin;
 
-       mutex_lock(&pinctrldev_list_mutex);
-
        ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
        if (ret) {
-               mutex_unlock(&pinctrldev_list_mutex);
                return;
        }
        mutex_lock(&pctldev->mutex);
 
        /* Convert to the pin controllers number space */
-       pin = gpio - range->base + range->pin_base;
+       pin = gpio_to_pin(range, gpio);
 
        pinmux_free_gpio(pctldev, pin, range);
 
        mutex_unlock(&pctldev->mutex);
-       mutex_unlock(&pinctrldev_list_mutex);
 }
 EXPORT_SYMBOL_GPL(pinctrl_free_gpio);
 
@@ -578,22 +602,18 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)
        int ret;
        int pin;
 
-       mutex_lock(&pinctrldev_list_mutex);
-
        ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
        if (ret) {
-               mutex_unlock(&pinctrldev_list_mutex);
                return ret;
        }
 
        mutex_lock(&pctldev->mutex);
 
        /* Convert to the pin controllers number space */
-       pin = gpio - range->base + range->pin_base;
+       pin = gpio_to_pin(range, gpio);
        ret = pinmux_gpio_direction(pctldev, range, pin, input);
 
        mutex_unlock(&pctldev->mutex);
-       mutex_unlock(&pinctrldev_list_mutex);
 
        return ret;
 }
@@ -1204,6 +1224,69 @@ int pinctrl_force_default(struct pinctrl_dev *pctldev)
 }
 EXPORT_SYMBOL_GPL(pinctrl_force_default);
 
+#ifdef CONFIG_PM
+
+/**
+ * pinctrl_pm_select_default_state() - select default pinctrl state for PM
+ * @dev: device to select default state for
+ */
+int pinctrl_pm_select_default_state(struct device *dev)
+{
+       struct dev_pin_info *pins = dev->pins;
+       int ret;
+
+       if (!pins)
+               return 0;
+       if (IS_ERR(pins->default_state))
+               return 0; /* No default state */
+       ret = pinctrl_select_state(pins->p, pins->default_state);
+       if (ret)
+               dev_err(dev, "failed to activate default pinctrl state\n");
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_pm_select_default_state);
+
+/**
+ * pinctrl_pm_select_sleep_state() - select sleep pinctrl state for PM
+ * @dev: device to select sleep state for
+ */
+int pinctrl_pm_select_sleep_state(struct device *dev)
+{
+       struct dev_pin_info *pins = dev->pins;
+       int ret;
+
+       if (!pins)
+               return 0;
+       if (IS_ERR(pins->sleep_state))
+               return 0; /* No sleep state */
+       ret = pinctrl_select_state(pins->p, pins->sleep_state);
+       if (ret)
+               dev_err(dev, "failed to activate pinctrl sleep state\n");
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_pm_select_sleep_state);
+
+/**
+ * pinctrl_pm_select_idle_state() - select idle pinctrl state for PM
+ * @dev: device to select idle state for
+ */
+int pinctrl_pm_select_idle_state(struct device *dev)
+{
+       struct dev_pin_info *pins = dev->pins;
+       int ret;
+
+       if (!pins)
+               return 0;
+       if (IS_ERR(pins->idle_state))
+               return 0; /* No idle state */
+       ret = pinctrl_select_state(pins->p, pins->idle_state);
+       if (ret)
+               dev_err(dev, "failed to activate pinctrl idle state\n");
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_pm_select_idle_state);
+#endif
+
 #ifdef CONFIG_DEBUG_FS
 
 static int pinctrl_pins_show(struct seq_file *s, void *what)
@@ -1296,11 +1379,21 @@ static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
 
        /* Loop over the ranges */
        list_for_each_entry(range, &pctldev->gpio_ranges, node) {
-               seq_printf(s, "%u: %s GPIOS [%u - %u] PINS [%u - %u]\n",
-                          range->id, range->name,
-                          range->base, (range->base + range->npins - 1),
-                          range->pin_base,
-                          (range->pin_base + range->npins - 1));
+               if (range->pins) {
+                       int a;
+                       seq_printf(s, "%u: %s GPIOS [%u - %u] PINS {",
+                               range->id, range->name,
+                               range->base, (range->base + range->npins - 1));
+                       for (a = 0; a < range->npins - 1; a++)
+                               seq_printf(s, "%u, ", range->pins[a]);
+                       seq_printf(s, "%u}\n", range->pins[a]);
+               }
+               else
+                       seq_printf(s, "%u: %s GPIOS [%u - %u] PINS [%u - %u]\n",
+                               range->id, range->name,
+                               range->base, (range->base + range->npins - 1),
+                               range->pin_base,
+                               (range->pin_base + range->npins - 1));
        }
 
        mutex_unlock(&pctldev->mutex);
index 428ea96a94d356a3caee8b971a1df51d8c9564c3..048ae80adabde3ef2f01dfd3f2cf7cf83f3235d5 100644 (file)
@@ -26,6 +26,9 @@
 #define DOVE_MPP_VIRT_BASE             (DOVE_SB_REGS_VIRT_BASE + 0xd0200)
 #define DOVE_PMU_MPP_GENERAL_CTRL      (DOVE_MPP_VIRT_BASE + 0x10)
 #define  DOVE_AU0_AC97_SEL             BIT(16)
+#define DOVE_PMU_SIGNAL_SELECT_0       (DOVE_SB_REGS_VIRT_BASE + 0xd802C)
+#define DOVE_PMU_SIGNAL_SELECT_1       (DOVE_SB_REGS_VIRT_BASE + 0xd8030)
+#define DOVE_GLOBAL_CONFIG_1           (DOVE_SB_REGS_VIRT_BASE + 0xe802C)
 #define DOVE_GLOBAL_CONFIG_1           (DOVE_SB_REGS_VIRT_BASE + 0xe802C)
 #define  DOVE_TWSI_ENABLE_OPTION1      BIT(7)
 #define DOVE_GLOBAL_CONFIG_2           (DOVE_SB_REGS_VIRT_BASE + 0xe8030)
@@ -58,12 +61,16 @@ static int dove_pmu_mpp_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
        unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS;
        unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS;
        unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
-       unsigned long mpp = readl(DOVE_MPP_VIRT_BASE + off);
-
-       if (pmu & (1 << ctrl->pid))
-               *config = CONFIG_PMU;
-       else
-               *config = (mpp >> shift) & MPP_MASK;
+       unsigned long func;
+
+       if (pmu & (1 << ctrl->pid)) {
+               func = readl(DOVE_PMU_SIGNAL_SELECT_0 + off);
+               *config = (func >> shift) & MPP_MASK;
+               *config |= CONFIG_PMU;
+       } else {
+               func = readl(DOVE_MPP_VIRT_BASE + off);
+               *config = (func >> shift) & MPP_MASK;
+       }
        return 0;
 }
 
@@ -73,15 +80,20 @@ static int dove_pmu_mpp_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
        unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS;
        unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS;
        unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
-       unsigned long mpp = readl(DOVE_MPP_VIRT_BASE + off);
+       unsigned long func;
 
-       if (config == CONFIG_PMU)
+       if (config & CONFIG_PMU) {
                writel(pmu | (1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
-       else {
+               func = readl(DOVE_PMU_SIGNAL_SELECT_0 + off);
+               func &= ~(MPP_MASK << shift);
+               func |= (config & MPP_MASK) << shift;
+               writel(func, DOVE_PMU_SIGNAL_SELECT_0 + off);
+       } else {
                writel(pmu & ~(1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
-               mpp &= ~(MPP_MASK << shift);
-               mpp |= config << shift;
-               writel(mpp, DOVE_MPP_VIRT_BASE + off);
+               func = readl(DOVE_MPP_VIRT_BASE + off);
+               func &= ~(MPP_MASK << shift);
+               func |= (config & MPP_MASK) << shift;
+               writel(func, DOVE_MPP_VIRT_BASE + off);
        }
        return 0;
 }
@@ -378,20 +390,53 @@ static struct mvebu_mpp_mode dove_mpp_modes[] = {
                MPP_FUNCTION(0x02, "uart2", "rts"),
                MPP_FUNCTION(0x03, "sdio0", "cd"),
                MPP_FUNCTION(0x0f, "lcd0", "pwm"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(1,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x02, "uart2", "cts"),
                MPP_FUNCTION(0x03, "sdio0", "wp"),
                MPP_FUNCTION(0x0f, "lcd1", "pwm"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(2,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x01, "sata", "prsnt"),
                MPP_FUNCTION(0x02, "uart2", "txd"),
                MPP_FUNCTION(0x03, "sdio0", "buspwr"),
                MPP_FUNCTION(0x04, "uart1", "rts"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(3,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x01, "sata", "act"),
@@ -399,43 +444,131 @@ static struct mvebu_mpp_mode dove_mpp_modes[] = {
                MPP_FUNCTION(0x03, "sdio0", "ledctrl"),
                MPP_FUNCTION(0x04, "uart1", "cts"),
                MPP_FUNCTION(0x0f, "lcd-spi", "cs1"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(4,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x02, "uart3", "rts"),
                MPP_FUNCTION(0x03, "sdio1", "cd"),
                MPP_FUNCTION(0x04, "spi1", "miso"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(5,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x02, "uart3", "cts"),
                MPP_FUNCTION(0x03, "sdio1", "wp"),
                MPP_FUNCTION(0x04, "spi1", "cs"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(6,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x02, "uart3", "txd"),
                MPP_FUNCTION(0x03, "sdio1", "buspwr"),
                MPP_FUNCTION(0x04, "spi1", "mosi"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(7,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x02, "uart3", "rxd"),
                MPP_FUNCTION(0x03, "sdio1", "ledctrl"),
                MPP_FUNCTION(0x04, "spi1", "sck"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(8,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x01, "watchdog", "rstout"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(9,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x05, "pex1", "clkreq"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(10,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x05, "ssp", "sclk"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(11,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x01, "sata", "prsnt"),
@@ -443,33 +576,88 @@ static struct mvebu_mpp_mode dove_mpp_modes[] = {
                MPP_FUNCTION(0x03, "sdio0", "ledctrl"),
                MPP_FUNCTION(0x04, "sdio1", "ledctrl"),
                MPP_FUNCTION(0x05, "pex0", "clkreq"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(12,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x01, "sata", "act"),
                MPP_FUNCTION(0x02, "uart2", "rts"),
                MPP_FUNCTION(0x03, "audio0", "extclk"),
                MPP_FUNCTION(0x04, "sdio1", "cd"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(13,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x02, "uart2", "cts"),
                MPP_FUNCTION(0x03, "audio1", "extclk"),
                MPP_FUNCTION(0x04, "sdio1", "wp"),
                MPP_FUNCTION(0x05, "ssp", "extclk"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(14,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x02, "uart2", "txd"),
                MPP_FUNCTION(0x04, "sdio1", "buspwr"),
                MPP_FUNCTION(0x05, "ssp", "rxd"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(15,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x02, "uart2", "rxd"),
                MPP_FUNCTION(0x04, "sdio1", "ledctrl"),
                MPP_FUNCTION(0x05, "ssp", "sfrm"),
-               MPP_FUNCTION(0x10, "pmu", NULL)),
+               MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
+               MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
+               MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
        MPP_MODE(16,
                MPP_FUNCTION(0x00, "gpio", NULL),
                MPP_FUNCTION(0x02, "uart3", "rts"),
index 2ad5a8d337b55447007d08ef55d675450bdeaf81..8594f033ac21b02898c917069cb0c44667fe650b 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
+#include <linux/of.h>
 #include "core.h"
 #include "pinconf.h"
 
@@ -37,14 +38,18 @@ struct pin_config_item {
 static struct pin_config_item conf_items[] = {
        PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL),
        PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL),
+       PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL),
        PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL),
        PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL),
+       PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT,
+                               "input bias pull to pin specific state", NULL),
        PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
        PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
        PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
+       PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"),
        PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL),
        PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
-       PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"),
+       PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec"),
        PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"),
        PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL),
        PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"),
@@ -135,3 +140,100 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
 }
 EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
 #endif
+
+#ifdef CONFIG_OF
+struct pinconf_generic_dt_params {
+       const char * const property;
+       enum pin_config_param param;
+       u32 default_value;
+};
+
+static struct pinconf_generic_dt_params dt_params[] = {
+       { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+       { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
+       { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
+       { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+       { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+       { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
+       { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
+       { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
+       { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
+       { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+       { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
+       { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
+       { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
+       { "low-power-enable", PIN_CONFIG_LOW_POWER_MODE, 1 },
+       { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 },
+       { "output-low", PIN_CONFIG_OUTPUT, 0, },
+       { "output-high", PIN_CONFIG_OUTPUT, 1, },
+};
+
+/**
+ * pinconf_generic_parse_dt_config()
+ * parse the config properties into generic pinconfig values.
+ * @np: node containing the pinconfig properties
+ * @configs: array with nconfigs entries containing the generic pinconf values
+ * @nconfigs: umber of configurations
+ */
+int pinconf_generic_parse_dt_config(struct device_node *np,
+                                   unsigned long **configs,
+                                   unsigned int *nconfigs)
+{
+       unsigned long *cfg;
+       unsigned int ncfg = 0;
+       int ret;
+       int i;
+       u32 val;
+
+       if (!np)
+               return -EINVAL;
+
+       /* allocate a temporary array big enough to hold one of each option */
+       cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL);
+       if (!cfg)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
+               struct pinconf_generic_dt_params *par = &dt_params[i];
+               ret = of_property_read_u32(np, par->property, &val);
+
+               /* property not found */
+               if (ret == -EINVAL)
+                       continue;
+
+               /* use default value, when no value is specified */
+               if (ret)
+                       val = par->default_value;
+
+               pr_debug("found %s with value %u\n", par->property, val);
+               cfg[ncfg] = pinconf_to_config_packed(par->param, val);
+               ncfg++;
+       }
+
+       ret = 0;
+
+       /* no configs found at all */
+       if (ncfg == 0) {
+               *configs = NULL;
+               *nconfigs = 0;
+               goto out;
+       }
+
+       /*
+        * Now limit the number of configs to the real number of
+        * found properties.
+        */
+       *configs = kzalloc(ncfg * sizeof(unsigned long), GFP_KERNEL);
+       if (!*configs) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       memcpy(*configs, cfg, ncfg * sizeof(unsigned long));
+       *nconfigs = ncfg;
+
+out:
+       kfree(cfg);
+       return ret;
+}
+#endif
index 694c3ace45204c11eeed4518f82b901c92489b59..e875f21a5908a7aca89ca13fa75c4dcab5e7b0d3 100644 (file)
@@ -75,98 +75,6 @@ int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
        return ops->pin_config_get(pctldev, pin, config);
 }
 
-/**
- * pin_config_get() - get the configuration of a single pin parameter
- * @dev_name: name of the pin controller device for this pin
- * @name: name of the pin to get the config for
- * @config: the config pointed to by this argument will be filled in with the
- *     current pin state, it can be used directly by drivers as a numeral, or
- *     it can be dereferenced to any struct.
- */
-int pin_config_get(const char *dev_name, const char *name,
-                         unsigned long *config)
-{
-       struct pinctrl_dev *pctldev;
-       int pin;
-
-       pctldev = get_pinctrl_dev_from_devname(dev_name);
-       if (!pctldev) {
-               pin = -EINVAL;
-               return pin;
-       }
-
-       mutex_lock(&pctldev->mutex);
-
-       pin = pin_get_from_name(pctldev, name);
-       if (pin < 0)
-               goto unlock;
-
-       pin = pin_config_get_for_pin(pctldev, pin, config);
-
-unlock:
-       mutex_unlock(&pctldev->mutex);
-       return pin;
-}
-EXPORT_SYMBOL(pin_config_get);
-
-static int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
-                          unsigned long config)
-{
-       const struct pinconf_ops *ops = pctldev->desc->confops;
-       int ret;
-
-       if (!ops || !ops->pin_config_set) {
-               dev_err(pctldev->dev, "cannot configure pin, missing "
-                       "config function in driver\n");
-               return -EINVAL;
-       }
-
-       ret = ops->pin_config_set(pctldev, pin, config);
-       if (ret) {
-               dev_err(pctldev->dev,
-                       "unable to set pin configuration on pin %d\n", pin);
-               return ret;
-       }
-
-       return 0;
-}
-
-/**
- * pin_config_set() - set the configuration of a single pin parameter
- * @dev_name: name of pin controller device for this pin
- * @name: name of the pin to set the config for
- * @config: the config in this argument will contain the desired pin state, it
- *     can be used directly by drivers as a numeral, or it can be dereferenced
- *     to any struct.
- */
-int pin_config_set(const char *dev_name, const char *name,
-                  unsigned long config)
-{
-       struct pinctrl_dev *pctldev;
-       int pin, ret;
-
-       pctldev = get_pinctrl_dev_from_devname(dev_name);
-       if (!pctldev) {
-               ret = -EINVAL;
-               return ret;
-       }
-
-       mutex_lock(&pctldev->mutex);
-
-       pin = pin_get_from_name(pctldev, name);
-       if (pin < 0) {
-               ret = pin;
-               goto unlock;
-       }
-
-       ret = pin_config_set_for_pin(pctldev, pin, config);
-
-unlock:
-       mutex_unlock(&pctldev->mutex);
-       return ret;
-}
-EXPORT_SYMBOL(pin_config_set);
-
 int pin_config_group_get(const char *dev_name, const char *pin_group,
                         unsigned long *config)
 {
@@ -204,88 +112,6 @@ unlock:
        mutex_unlock(&pctldev->mutex);
        return ret;
 }
-EXPORT_SYMBOL(pin_config_group_get);
-
-int pin_config_group_set(const char *dev_name, const char *pin_group,
-                        unsigned long config)
-{
-       struct pinctrl_dev *pctldev;
-       const struct pinconf_ops *ops;
-       const struct pinctrl_ops *pctlops;
-       int selector;
-       const unsigned *pins;
-       unsigned num_pins;
-       int ret;
-       int i;
-
-       pctldev = get_pinctrl_dev_from_devname(dev_name);
-       if (!pctldev) {
-               ret = -EINVAL;
-               return ret;
-       }
-
-       mutex_lock(&pctldev->mutex);
-
-       ops = pctldev->desc->confops;
-       pctlops = pctldev->desc->pctlops;
-
-       if (!ops || (!ops->pin_config_group_set && !ops->pin_config_set)) {
-               dev_err(pctldev->dev, "cannot configure pin group, missing "
-                       "config function in driver\n");
-               ret = -EINVAL;
-               goto unlock;
-       }
-
-       selector = pinctrl_get_group_selector(pctldev, pin_group);
-       if (selector < 0) {
-               ret = selector;
-               goto unlock;
-       }
-
-       ret = pctlops->get_group_pins(pctldev, selector, &pins, &num_pins);
-       if (ret) {
-               dev_err(pctldev->dev, "cannot configure pin group, error "
-                       "getting pins\n");
-               goto unlock;
-       }
-
-       /*
-        * If the pin controller supports handling entire groups we use that
-        * capability.
-        */
-       if (ops->pin_config_group_set) {
-               ret = ops->pin_config_group_set(pctldev, selector, config);
-               /*
-                * If the pin controller prefer that a certain group be handled
-                * pin-by-pin as well, it returns -EAGAIN.
-                */
-               if (ret != -EAGAIN)
-                       goto unlock;
-       }
-
-       /*
-        * If the controller cannot handle entire groups, we configure each pin
-        * individually.
-        */
-       if (!ops->pin_config_set) {
-               ret = 0;
-               goto unlock;
-       }
-
-       for (i = 0; i < num_pins; i++) {
-               ret = ops->pin_config_set(pctldev, pins[i], config);
-               if (ret < 0)
-                       goto unlock;
-       }
-
-       ret = 0;
-
-unlock:
-       mutex_unlock(&pctldev->mutex);
-
-       return ret;
-}
-EXPORT_SYMBOL(pin_config_group_set);
 
 int pinconf_map_to_setting(struct pinctrl_map const *map,
                          struct pinctrl_setting *setting)
index 92c7267244d25dbf79715bed0a89713380dc1a4c..a4a5417e1413d738b1151865a1b70d8b5fdb2957 100644 (file)
@@ -123,3 +123,9 @@ static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
        return;
 }
 #endif
+
+#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF)
+int pinconf_generic_parse_dt_config(struct device_node *np,
+                                   unsigned long **configs,
+                                   unsigned int *nconfigs);
+#endif
index 6d4532702f809b5cc52629fbdc7ad238412153f3..1d3f988c2c8bff0cfff3e5fdebba241deaaff9d4 100644 (file)
 #include <linux/pinctrl/pinmux.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/machine.h>
 
 #include "pinctrl-abx500.h"
+#include "core.h"
+#include "pinconf.h"
 
 /*
  * The AB9540 and AB8540 GPIO support are extended versions
 #define AB8540_GPIOX_VBAT_START        51
 #define AB8540_GPIOX_VBAT_END  54
 
+#define ABX500_GPIO_INPUT      0
+#define ABX500_GPIO_OUTPUT     1
+
 struct abx500_pinctrl {
        struct device *dev;
        struct pinctrl_dev *pctldev;
        struct abx500_pinctrl_soc_data *soc;
        struct gpio_chip chip;
        struct ab8500 *parent;
-       struct mutex lock;
        struct abx500_gpio_irq_cluster *irq_cluster;
        int irq_cluster_size;
 };
@@ -129,8 +134,8 @@ static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
 
        if (ret < 0)
                dev_err(pct->dev,
-                       "%s read reg =%x, offset=%x failed\n",
-                       __func__, reg, offset);
+                       "%s read reg =%x, offset=%x failed (%d)\n",
+                       __func__, reg, offset, ret);
 
        return ret;
 }
@@ -146,7 +151,8 @@ static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
        ret = abx500_mask_and_set_register_interruptible(pct->dev,
                                AB8500_MISC, reg, BIT(pos), val << pos);
        if (ret < 0)
-               dev_err(pct->dev, "%s write failed\n", __func__);
+               dev_err(pct->dev, "%s write reg, %x offset %x failed (%d)\n",
+                               __func__, reg, offset, ret);
 
        return ret;
 }
@@ -160,12 +166,24 @@ static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
        bool bit;
+       bool is_out;
+       u8 gpio_offset = offset - 1;
        int ret;
 
-       ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG,
-                                 offset, &bit);
+       ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG,
+                       gpio_offset, &is_out);
+       if (ret < 0)
+               goto out;
+
+       if (is_out)
+               ret = abx500_gpio_get_bit(chip, AB8500_GPIO_OUT1_REG,
+                               gpio_offset, &bit);
+       else
+               ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG,
+                               gpio_offset, &bit);
+out:
        if (ret < 0) {
-               dev_err(pct->dev, "%s failed\n", __func__);
+               dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
                return ret;
        }
 
@@ -179,13 +197,14 @@ static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 
        ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
        if (ret < 0)
-               dev_err(pct->dev, "%s write failed\n", __func__);
+               dev_err(pct->dev, "%s write failed (%d)\n", __func__, ret);
 }
 
-static int abx500_config_pull_updown(struct abx500_pinctrl *pct,
-                                    int offset, enum abx500_gpio_pull_updown val)
+static int abx500_get_pull_updown(struct abx500_pinctrl *pct, int offset,
+                                 enum abx500_gpio_pull_updown *pull_updown)
 {
        u8 pos;
+       u8 val;
        int ret;
        struct pullud *pullud;
 
@@ -204,7 +223,41 @@ static int abx500_config_pull_updown(struct abx500_pinctrl *pct,
                goto out;
        }
 
-       pos = offset << 1;
+       ret = abx500_get_register_interruptible(pct->dev,
+                       AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG, &val);
+
+       pos = (offset - pullud->first_pin) << 1;
+       *pull_updown = (val >> pos) & AB8540_GPIO_PULL_UPDOWN_MASK;
+
+out:
+       if (ret < 0)
+               dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+
+       return ret;
+}
+
+static int abx500_set_pull_updown(struct abx500_pinctrl *pct,
+                                 int offset, enum abx500_gpio_pull_updown val)
+{
+       u8 pos;
+       int ret;
+       struct pullud *pullud;
+
+       if (!pct->soc->pullud) {
+               dev_err(pct->dev, "%s AB chip doesn't support pull up/down feature",
+                               __func__);
+               ret = -EPERM;
+               goto out;
+       }
+
+       pullud = pct->soc->pullud;
+
+       if ((offset < pullud->first_pin)
+               || (offset > pullud->last_pin)) {
+               ret = -EINVAL;
+               goto out;
+       }
+       pos = (offset - pullud->first_pin) << 1;
 
        ret = abx500_mask_and_set_register_interruptible(pct->dev,
                        AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG,
@@ -217,33 +270,51 @@ out:
        return ret;
 }
 
+static bool abx500_pullud_supported(struct gpio_chip *chip, unsigned gpio)
+{
+       struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+       struct pullud *pullud = pct->soc->pullud;
+
+       return (pullud &&
+               gpio >= pullud->first_pin &&
+               gpio <= pullud->last_pin);
+}
+
 static int abx500_gpio_direction_output(struct gpio_chip *chip,
                                        unsigned offset,
                                        int val)
 {
        struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
-       struct pullud *pullud = pct->soc->pullud;
        unsigned gpio;
        int ret;
 
        /* set direction as output */
-       ret = abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
+       ret = abx500_gpio_set_bits(chip,
+                               AB8500_GPIO_DIR1_REG,
+                               offset,
+                               ABX500_GPIO_OUTPUT);
        if (ret < 0)
-               return ret;
+               goto out;
 
        /* disable pull down */
-       ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
+       ret = abx500_gpio_set_bits(chip,
+                               AB8500_GPIO_PUD1_REG,
+                               offset,
+                               ABX500_GPIO_PULL_NONE);
        if (ret < 0)
-               return ret;
+               goto out;
 
        /* if supported, disable both pull down and pull up */
        gpio = offset + 1;
-       if (pullud && gpio >= pullud->first_pin && gpio <= pullud->last_pin) {
-               ret = abx500_config_pull_updown(pct,
+       if (abx500_pullud_supported(chip, gpio)) {
+               ret = abx500_set_pull_updown(pct,
                                gpio,
                                ABX500_GPIO_PULL_NONE);
-               if (ret < 0)
-                       return ret;
+       }
+out:
+       if (ret < 0) {
+               dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+               return ret;
        }
 
        /* set the output as 1 or 0 */
@@ -253,7 +324,10 @@ static int abx500_gpio_direction_output(struct gpio_chip *chip,
 static int abx500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        /* set the register as input */
-       return abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
+       return abx500_gpio_set_bits(chip,
+                               AB8500_GPIO_DIR1_REG,
+                               offset,
+                               ABX500_GPIO_INPUT);
 }
 
 static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -338,10 +412,16 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
                if (af.alt_bit1 != UNUSED) {
                        ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
                                        offset, 0);
+                       if (ret < 0)
+                               goto out;
+
                        ret = abx500_gpio_set_bits(chip,
                                        AB8500_GPIO_ALTFUN_REG,
                                        af.alt_bit1,
                                        !!(af.alta_val && BIT(0)));
+                       if (ret < 0)
+                               goto out;
+
                        if (af.alt_bit2 != UNUSED)
                                ret = abx500_gpio_set_bits(chip,
                                        AB8500_GPIO_ALTFUN_REG,
@@ -355,8 +435,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
        case ABX500_ALT_B:
                ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
                                offset, 0);
+               if (ret < 0)
+                       goto out;
+
                ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
                                af.alt_bit1, !!(af.altb_val && BIT(0)));
+               if (ret < 0)
+                       goto out;
+
                if (af.alt_bit2 != UNUSED)
                        ret = abx500_gpio_set_bits(chip,
                                        AB8500_GPIO_ALTFUN_REG,
@@ -367,8 +453,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
        case ABX500_ALT_C:
                ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
                                offset, 0);
+               if (ret < 0)
+                       goto out;
+
                ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
                                af.alt_bit2, !!(af.altc_val && BIT(0)));
+               if (ret < 0)
+                       goto out;
+
                ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
                                af.alt_bit2, !!(af.altc_val && BIT(1)));
                break;
@@ -378,11 +470,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
 
                return -EINVAL;
        }
+out:
+       if (ret < 0)
+               dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
 
        return ret;
 }
 
-static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+static int abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
                          unsigned gpio)
 {
        u8 mode;
@@ -393,6 +488,7 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
        struct alternate_functions af = pct->soc->alternate_functions[gpio];
        /* on ABx5xx, there is no GPIO0, so adjust the offset */
        unsigned offset = gpio - 1;
+       int ret;
 
        /*
         * if gpiosel_bit is set to unused,
@@ -402,8 +498,11 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
                return ABX500_DEFAULT;
 
        /* read GpioSelx register */
-       abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8),
+       ret = abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8),
                        af.gpiosel_bit, &bit_mode);
+       if (ret < 0)
+               goto out;
+
        mode = bit_mode;
 
        /* sanity check */
@@ -435,14 +534,19 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
         * pin use the AlternatFunction register
         * read alt_bit1 value
         */
-       abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
+       ret = abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
                            af.alt_bit1, &alt_bit1);
+       if (ret < 0)
+               goto out;
 
-       if (af.alt_bit2 != UNUSED)
+       if (af.alt_bit2 != UNUSED) {
                /* read alt_bit2 value */
-               abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit2,
+               ret = abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
+                               af.alt_bit2,
                                &alt_bit2);
-       else
+               if (ret < 0)
+                       goto out;
+       } else
                alt_bit2 = 0;
 
        mode = (alt_bit2 << 1) + alt_bit1;
@@ -452,6 +556,10 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
                return ABX500_ALT_B;
        else
                return ABX500_ALT_C;
+
+out:
+       dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+       return ret;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -463,11 +571,14 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,
                                     struct gpio_chip *chip,
                                     unsigned offset, unsigned gpio)
 {
+       struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
        const char *label = gpiochip_is_requested(chip, offset - 1);
        u8 gpio_offset = offset - 1;
        int mode = -1;
        bool is_out;
-       bool pull;
+       bool pd;
+       enum abx500_gpio_pull_updown pud = 0;
+       int ret;
 
        const char *modes[] = {
                [ABX500_DEFAULT]        = "default",
@@ -476,21 +587,48 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,
                [ABX500_ALT_C]          = "altC",
        };
 
-       abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, gpio_offset, &is_out);
-       abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG, gpio_offset, &pull);
+       const char *pull_up_down[] = {
+               [ABX500_GPIO_PULL_DOWN]         = "pull down",
+               [ABX500_GPIO_PULL_NONE]         = "pull none",
+               [ABX500_GPIO_PULL_NONE + 1]     = "pull none",
+               [ABX500_GPIO_PULL_UP]           = "pull up",
+       };
+
+       ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG,
+                       gpio_offset, &is_out);
+       if (ret < 0)
+               goto out;
+
+       seq_printf(s, " gpio-%-3d (%-20.20s) %-3s",
+                  gpio, label ?: "(none)",
+                  is_out ? "out" : "in ");
+
+       if (!is_out) {
+               if (abx500_pullud_supported(chip, offset)) {
+                       ret = abx500_get_pull_updown(pct, offset, &pud);
+                       if (ret < 0)
+                               goto out;
+
+                       seq_printf(s, " %-9s", pull_up_down[pud]);
+               } else {
+                       ret = abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG,
+                                       gpio_offset, &pd);
+                       if (ret < 0)
+                               goto out;
+
+                       seq_printf(s, " %-9s", pull_up_down[pd]);
+               }
+       } else
+               seq_printf(s, " %-9s", chip->get(chip, offset) ? "hi" : "lo");
 
        if (pctldev)
                mode = abx500_get_mode(pctldev, chip, offset);
 
-       seq_printf(s, " gpio-%-3d (%-20.20s) %-3s %-9s %s",
-                  gpio, label ?: "(none)",
-                  is_out ? "out" : "in ",
-                  is_out ?
-                  (chip->get
-                  ? (chip->get(chip, offset) ? "hi" : "lo")
-                  : "?  ")
-                  : (pull ? "pull up" : "pull down"),
-                  (mode < 0) ? "unknown" : modes[mode]);
+       seq_printf(s, " %s", (mode < 0) ? "unknown" : modes[mode]);
+
+out:
+       if (ret < 0)
+               dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
 }
 
 static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
@@ -594,6 +732,9 @@ static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
                ret = abx500_set_mode(pctldev, chip, g->pins[i], g->altsetting);
        }
 
+       if (ret < 0)
+               dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+
        return ret;
 }
 
@@ -642,10 +783,8 @@ static int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
 
        ret = abx500_set_mode(pct->pctldev, &pct->chip,
                              offset, p->altfunc);
-       if (ret < 0) {
+       if (ret < 0)
                dev_err(pct->dev, "%s setting altfunc failed\n", __func__);
-               return ret;
-       }
 
        return ret;
 }
@@ -704,11 +843,193 @@ static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev,
                                 chip->base + offset - 1);
 }
 
+static void abx500_dt_free_map(struct pinctrl_dev *pctldev,
+               struct pinctrl_map *map, unsigned num_maps)
+{
+       int i;
+
+       for (i = 0; i < num_maps; i++)
+               if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+                       kfree(map[i].data.configs.configs);
+       kfree(map);
+}
+
+static int abx500_dt_reserve_map(struct pinctrl_map **map,
+               unsigned *reserved_maps,
+               unsigned *num_maps,
+               unsigned reserve)
+{
+       unsigned old_num = *reserved_maps;
+       unsigned new_num = *num_maps + reserve;
+       struct pinctrl_map *new_map;
+
+       if (old_num >= new_num)
+               return 0;
+
+       new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
+       if (!new_map)
+               return -ENOMEM;
+
+       memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
+
+       *map = new_map;
+       *reserved_maps = new_num;
+
+       return 0;
+}
+
+static int abx500_dt_add_map_mux(struct pinctrl_map **map,
+               unsigned *reserved_maps,
+               unsigned *num_maps, const char *group,
+               const char *function)
+{
+       if (*num_maps == *reserved_maps)
+               return -ENOSPC;
+
+       (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+       (*map)[*num_maps].data.mux.group = group;
+       (*map)[*num_maps].data.mux.function = function;
+       (*num_maps)++;
+
+       return 0;
+}
+
+static int abx500_dt_add_map_configs(struct pinctrl_map **map,
+               unsigned *reserved_maps,
+               unsigned *num_maps, const char *group,
+               unsigned long *configs, unsigned num_configs)
+{
+       unsigned long *dup_configs;
+
+       if (*num_maps == *reserved_maps)
+               return -ENOSPC;
+
+       dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
+                             GFP_KERNEL);
+       if (!dup_configs)
+               return -ENOMEM;
+
+       (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_PIN;
+
+       (*map)[*num_maps].data.configs.group_or_pin = group;
+       (*map)[*num_maps].data.configs.configs = dup_configs;
+       (*map)[*num_maps].data.configs.num_configs = num_configs;
+       (*num_maps)++;
+
+       return 0;
+}
+
+static const char *abx500_find_pin_name(struct pinctrl_dev *pctldev,
+                                       const char *pin_name)
+{
+       int i, pin_number;
+       struct abx500_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+       if (sscanf((char *)pin_name, "GPIO%d", &pin_number) == 1)
+               for (i = 0; i < npct->soc->npins; i++)
+                       if (npct->soc->pins[i].number == pin_number)
+                               return npct->soc->pins[i].name;
+       return NULL;
+}
+
+static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+               struct device_node *np,
+               struct pinctrl_map **map,
+               unsigned *reserved_maps,
+               unsigned *num_maps)
+{
+       int ret;
+       const char *function = NULL;
+       unsigned long *configs;
+       unsigned int nconfigs = 0;
+       bool has_config = 0;
+       unsigned reserve = 0;
+       struct property *prop;
+       const char *group, *gpio_name;
+       struct device_node *np_config;
+
+       ret = of_property_read_string(np, "ste,function", &function);
+       if (ret >= 0)
+               reserve = 1;
+
+       ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs);
+       if (nconfigs)
+               has_config = 1;
+
+       np_config = of_parse_phandle(np, "ste,config", 0);
+       if (np_config) {
+               ret = pinconf_generic_parse_dt_config(np_config, &configs,
+                               &nconfigs);
+               if (ret)
+                       goto exit;
+               has_config |= nconfigs;
+       }
+
+       ret = of_property_count_strings(np, "ste,pins");
+       if (ret < 0)
+               goto exit;
+
+       if (has_config)
+               reserve++;
+
+       reserve *= ret;
+
+       ret = abx500_dt_reserve_map(map, reserved_maps, num_maps, reserve);
+       if (ret < 0)
+               goto exit;
+
+       of_property_for_each_string(np, "ste,pins", prop, group) {
+               if (function) {
+                       ret = abx500_dt_add_map_mux(map, reserved_maps,
+                                       num_maps, group, function);
+                       if (ret < 0)
+                               goto exit;
+               }
+               if (has_config) {
+                       gpio_name = abx500_find_pin_name(pctldev, group);
+
+                       ret = abx500_dt_add_map_configs(map, reserved_maps,
+                                       num_maps, gpio_name, configs, 1);
+                       if (ret < 0)
+                               goto exit;
+               }
+
+       }
+exit:
+       return ret;
+}
+
+static int abx500_dt_node_to_map(struct pinctrl_dev *pctldev,
+                                struct device_node *np_config,
+                                struct pinctrl_map **map, unsigned *num_maps)
+{
+       unsigned reserved_maps;
+       struct device_node *np;
+       int ret;
+
+       reserved_maps = 0;
+       *map = NULL;
+       *num_maps = 0;
+
+       for_each_child_of_node(np_config, np) {
+               ret = abx500_dt_subnode_to_map(pctldev, np, map,
+                               &reserved_maps, num_maps);
+               if (ret < 0) {
+                       abx500_dt_free_map(pctldev, *map, *num_maps);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static const struct pinctrl_ops abx500_pinctrl_ops = {
        .get_groups_count = abx500_get_groups_cnt,
        .get_group_name = abx500_get_group_name,
        .get_group_pins = abx500_get_group_pins,
        .pin_dbg_show = abx500_pin_dbg_show,
+       .dt_node_to_map = abx500_dt_node_to_map,
+       .dt_free_map = abx500_dt_free_map,
 };
 
 static int abx500_pin_config_get(struct pinctrl_dev *pctldev,
@@ -723,10 +1044,9 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
                          unsigned long config)
 {
        struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
-       struct pullud *pullud = pct->soc->pullud;
        struct gpio_chip *chip = &pct->chip;
        unsigned offset;
-       int ret;
+       int ret = -EINVAL;
        enum pin_config_param param = pinconf_to_config_param(config);
        enum pin_config_param argument = pinconf_to_config_argument(config);
 
@@ -739,41 +1059,83 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
        offset = pin - 1;
 
        switch (param) {
-       case PIN_CONFIG_BIAS_PULL_DOWN:
+       case PIN_CONFIG_BIAS_DISABLE:
+               ret = abx500_gpio_direction_input(chip, offset);
+               if (ret < 0)
+                       goto out;
                /*
-                * if argument = 1 set the pull down
-                * else clear the pull down
+                * Some chips only support pull down, while some actually
+                * support both pull up and pull down. Such chips have
+                * a "pullud" range specified for the pins that support
+                * both features. If the pin is not within that range, we
+                * fall back to the old bit set that only support pull down.
                 */
+               if (abx500_pullud_supported(chip, pin))
+                       ret = abx500_set_pull_updown(pct,
+                               pin,
+                               ABX500_GPIO_PULL_NONE);
+               else
+                       /* Chip only supports pull down */
+                       ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
+                               offset, ABX500_GPIO_PULL_NONE);
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_DOWN:
                ret = abx500_gpio_direction_input(chip, offset);
+               if (ret < 0)
+                       goto out;
                /*
+                * if argument = 1 set the pull down
+                * else clear the pull down
                 * Some chips only support pull down, while some actually
                 * support both pull up and pull down. Such chips have
                 * a "pullud" range specified for the pins that support
                 * both features. If the pin is not within that range, we
                 * fall back to the old bit set that only support pull down.
                 */
-               if (pullud &&
-                   pin >= pullud->first_pin &&
-                   pin <= pullud->last_pin)
-                       ret = abx500_config_pull_updown(pct,
+               if (abx500_pullud_supported(chip, pin))
+                       ret = abx500_set_pull_updown(pct,
                                pin,
                                argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
                else
                        /* Chip only supports pull down */
                        ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
-                               offset, argument ? 0 : 1);
+                               offset,
+                               argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
+               break;
+
+       case PIN_CONFIG_BIAS_PULL_UP:
+               ret = abx500_gpio_direction_input(chip, offset);
+               if (ret < 0)
+                       goto out;
+               /*
+                * if argument = 1 set the pull up
+                * else clear the pull up
+                */
+               ret = abx500_gpio_direction_input(chip, offset);
+               /*
+                * Some chips only support pull down, while some actually
+                * support both pull up and pull down. Such chips have
+                * a "pullud" range specified for the pins that support
+                * both features. If the pin is not within that range, do
+                * nothing
+                */
+               if (abx500_pullud_supported(chip, pin))
+                       ret = abx500_set_pull_updown(pct,
+                               pin,
+                               argument ? ABX500_GPIO_PULL_UP : ABX500_GPIO_PULL_NONE);
                break;
 
        case PIN_CONFIG_OUTPUT:
                ret = abx500_gpio_direction_output(chip, offset, argument);
-
                break;
 
        default:
                dev_err(chip->dev, "illegal configuration requested\n");
-
-               return -EINVAL;
        }
+out:
+       if (ret < 0)
+               dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
 
        return ret;
 }
@@ -881,9 +1243,6 @@ static int abx500_gpio_probe(struct platform_device *pdev)
                        id = (unsigned long)match->data;
        }
 
-       /* initialize the lock */
-       mutex_init(&pct->lock);
-
        /* Poke in other ASIC variants here */
        switch (id) {
        case PINCTRL_AB8500:
@@ -900,13 +1259,11 @@ static int abx500_gpio_probe(struct platform_device *pdev)
                break;
        default:
                dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n", id);
-               mutex_destroy(&pct->lock);
                return -EINVAL;
        }
 
        if (!pct->soc) {
                dev_err(&pdev->dev, "Invalid SOC data\n");
-               mutex_destroy(&pct->lock);
                return -EINVAL;
        }
 
@@ -917,7 +1274,6 @@ static int abx500_gpio_probe(struct platform_device *pdev)
        ret = gpiochip_add(&pct->chip);
        if (ret) {
                dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
-               mutex_destroy(&pct->lock);
                return ret;
        }
        dev_info(&pdev->dev, "added gpiochip\n");
@@ -954,7 +1310,6 @@ out_rem_chip:
        if (err)
                dev_info(&pdev->dev, "failed to remove gpiochip\n");
 
-       mutex_destroy(&pct->lock);
        return ret;
 }
 
@@ -974,8 +1329,6 @@ static int abx500_gpio_remove(struct platform_device *pdev)
                return ret;
        }
 
-       mutex_destroy(&pct->lock);
-
        return 0;
 }
 
index 5d7529ed5392d843cb80371cd47b45fb32e9a7b2..b90a3a0ac53432af15a64849a115823de0fedd9b 100644 (file)
@@ -1543,12 +1543,6 @@ static int at91_gpio_probe(struct platform_device *pdev)
                goto err;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENOENT;
-               goto err;
-       }
-
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                ret = irq;
@@ -1561,6 +1555,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
                goto err;
        }
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        at91_chip->regbase = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(at91_chip->regbase)) {
                ret = PTR_ERR(at91_chip->regbase);
diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c
new file mode 100644 (file)
index 0000000..e9d735d
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * Pinctrl GPIO driver for Intel Baytrail
+ * Copyright (c) 2012-2013, Intel Corporation.
+ *
+ * Author: Mathias Nyman <mathias.nyman@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/irqdomain.h>
+#include <linux/acpi.h>
+#include <linux/acpi_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/pinctrl/pinctrl.h>
+
+/* memory mapped register offsets */
+#define BYT_CONF0_REG          0x000
+#define BYT_CONF1_REG          0x004
+#define BYT_VAL_REG            0x008
+#define BYT_DFT_REG            0x00c
+#define BYT_INT_STAT_REG       0x800
+
+/* BYT_CONF0_REG register bits */
+#define BYT_TRIG_NEG           BIT(26)
+#define BYT_TRIG_POS           BIT(25)
+#define BYT_TRIG_LVL           BIT(24)
+#define BYT_PIN_MUX            0x07
+
+/* BYT_VAL_REG register bits */
+#define BYT_INPUT_EN           BIT(2)  /* 0: input enabled (active low)*/
+#define BYT_OUTPUT_EN          BIT(1)  /* 0: output enabled (active low)*/
+#define BYT_LEVEL              BIT(0)
+
+#define BYT_DIR_MASK           (BIT(1) | BIT(2))
+#define BYT_TRIG_MASK          (BIT(26) | BIT(25) | BIT(24))
+
+#define BYT_NGPIO_SCORE                102
+#define BYT_NGPIO_NCORE                28
+#define BYT_NGPIO_SUS          44
+
+/*
+ * Baytrail gpio controller consist of three separate sub-controllers called
+ * SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID.
+ *
+ * GPIO numbering is _not_ ordered meaning that gpio # 0 in ACPI namespace does
+ * _not_ correspond to the first gpio register at controller's gpio base.
+ * There is no logic or pattern in mapping gpio numbers to registers (pads) so
+ * each sub-controller needs to have its own mapping table
+ */
+
+/* score_pins[gpio_nr] = pad_nr */
+
+static unsigned const score_pins[BYT_NGPIO_SCORE] = {
+       85, 89, 93, 96, 99, 102, 98, 101, 34, 37,
+       36, 38, 39, 35, 40, 84, 62, 61, 64, 59,
+       54, 56, 60, 55, 63, 57, 51, 50, 53, 47,
+       52, 49, 48, 43, 46, 41, 45, 42, 58, 44,
+       95, 105, 70, 68, 67, 66, 69, 71, 65, 72,
+       86, 90, 88, 92, 103, 77, 79, 83, 78, 81,
+       80, 82, 13, 12, 15, 14, 17, 18, 19, 16,
+       2, 1, 0, 4, 6, 7, 9, 8, 33, 32,
+       31, 30, 29, 27, 25, 28, 26, 23, 21, 20,
+       24, 22, 5, 3, 10, 11, 106, 87, 91, 104,
+       97, 100,
+};
+
+static unsigned const ncore_pins[BYT_NGPIO_NCORE] = {
+       19, 18, 17, 20, 21, 22, 24, 25, 23, 16,
+       14, 15, 12, 26, 27, 1, 4, 8, 11, 0,
+       3, 6, 10, 13, 2, 5, 9, 7,
+};
+
+static unsigned const sus_pins[BYT_NGPIO_SUS] = {
+       29, 33, 30, 31, 32, 34, 36, 35, 38, 37,
+       18, 7, 11, 20, 17, 1, 8, 10, 19, 12,
+       0, 2, 23, 39, 28, 27, 22, 21, 24, 25,
+       26, 51, 56, 54, 49, 55, 48, 57, 50, 58,
+       52, 53, 59, 40,
+};
+
+static struct pinctrl_gpio_range byt_ranges[] = {
+       {
+               .name = "1", /* match with acpi _UID in probe */
+               .npins = BYT_NGPIO_SCORE,
+               .pins = score_pins,
+       },
+       {
+               .name = "2",
+               .npins = BYT_NGPIO_NCORE,
+               .pins = ncore_pins,
+       },
+       {
+               .name = "3",
+               .npins = BYT_NGPIO_SUS,
+               .pins = sus_pins,
+       },
+       {
+       },
+};
+
+struct byt_gpio {
+       struct gpio_chip                chip;
+       struct irq_domain               *domain;
+       struct platform_device          *pdev;
+       spinlock_t                      lock;
+       void __iomem                    *reg_base;
+       struct pinctrl_gpio_range       *range;
+};
+
+static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
+                                int reg)
+{
+       struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+       u32 reg_offset;
+       void __iomem *ptr;
+
+       if (reg == BYT_INT_STAT_REG)
+               reg_offset = (offset / 32) * 4;
+       else
+               reg_offset = vg->range->pins[offset] * 16;
+
+       ptr = (void __iomem *) (vg->reg_base + reg_offset + reg);
+       return ptr;
+}
+
+static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+
+       pm_runtime_get(&vg->pdev->dev);
+
+       return 0;
+}
+
+static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+       void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+       u32 value;
+
+       /* clear interrupt triggering */
+       value = readl(reg);
+       value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
+       writel(value, reg);
+
+       pm_runtime_put(&vg->pdev->dev);
+}
+
+static int byt_irq_type(struct irq_data *d, unsigned type)
+{
+       struct byt_gpio *vg = irq_data_get_irq_chip_data(d);
+       u32 offset = irqd_to_hwirq(d);
+       u32 value;
+       unsigned long flags;
+       void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
+
+       if (offset >= vg->chip.ngpio)
+               return -EINVAL;
+
+       spin_lock_irqsave(&vg->lock, flags);
+       value = readl(reg);
+
+       /* For level trigges the BYT_TRIG_POS and BYT_TRIG_NEG bits
+        * are used to indicate high and low level triggering
+        */
+       value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
+
+       switch (type) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               value |= BYT_TRIG_LVL;
+       case IRQ_TYPE_EDGE_RISING:
+               value |= BYT_TRIG_POS;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               value |= BYT_TRIG_LVL;
+       case IRQ_TYPE_EDGE_FALLING:
+               value |= BYT_TRIG_NEG;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
+               break;
+       }
+       writel(value, reg);
+
+       spin_unlock_irqrestore(&vg->lock, flags);
+
+       return 0;
+}
+
+static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
+       return readl(reg) & BYT_LEVEL;
+}
+
+static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+       void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
+       unsigned long flags;
+       u32 old_val;
+
+       spin_lock_irqsave(&vg->lock, flags);
+
+       old_val = readl(reg);
+
+       if (value)
+               writel(old_val | BYT_LEVEL, reg);
+       else
+               writel(old_val & ~BYT_LEVEL, reg);
+
+       spin_unlock_irqrestore(&vg->lock, flags);
+}
+
+static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+       void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
+       unsigned long flags;
+       u32 value;
+
+       spin_lock_irqsave(&vg->lock, flags);
+
+       value = readl(reg) | BYT_DIR_MASK;
+       value = value & (~BYT_INPUT_EN); /* active low */
+       writel(value, reg);
+
+       spin_unlock_irqrestore(&vg->lock, flags);
+
+       return 0;
+}
+
+static int byt_gpio_direction_output(struct gpio_chip *chip,
+                                    unsigned gpio, int value)
+{
+       struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+       void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG);
+       unsigned long flags;
+       u32 reg_val;
+
+       spin_lock_irqsave(&vg->lock, flags);
+
+       reg_val = readl(reg) | (BYT_DIR_MASK | !!value);
+       reg_val &= ~(BYT_OUTPUT_EN | !value);
+       writel(reg_val, reg);
+
+       spin_unlock_irqrestore(&vg->lock, flags);
+
+       return 0;
+}
+
+static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+       struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+       int i;
+       unsigned long flags;
+       u32 conf0, val, offs;
+
+       spin_lock_irqsave(&vg->lock, flags);
+
+       for (i = 0; i < vg->chip.ngpio; i++) {
+               offs = vg->range->pins[i] * 16;
+               conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG);
+               val = readl(vg->reg_base + offs + BYT_VAL_REG);
+
+               seq_printf(s,
+                          " gpio-%-3d %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s\n",
+                          i,
+                          val & BYT_INPUT_EN ? "  " : "in",
+                          val & BYT_OUTPUT_EN ? "   " : "out",
+                          val & BYT_LEVEL ? "hi" : "lo",
+                          vg->range->pins[i], offs,
+                          conf0 & 0x7,
+                          conf0 & BYT_TRIG_NEG ? "fall " : "",
+                          conf0 & BYT_TRIG_POS ? "rise " : "",
+                          conf0 & BYT_TRIG_LVL ? "lvl " : "");
+       }
+       spin_unlock_irqrestore(&vg->lock, flags);
+}
+
+static int byt_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+       return irq_create_mapping(vg->domain, offset);
+}
+
+static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+       struct irq_data *data = irq_desc_get_irq_data(desc);
+       struct byt_gpio *vg = irq_data_get_irq_handler_data(data);
+       struct irq_chip *chip = irq_data_get_irq_chip(data);
+       u32 base, pin, mask;
+       void __iomem *reg;
+       u32 pending;
+       unsigned virq;
+       int looplimit = 0;
+
+       /* check from GPIO controller which pin triggered the interrupt */
+       for (base = 0; base < vg->chip.ngpio; base += 32) {
+
+               reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
+
+               while ((pending = readl(reg))) {
+                       pin = __ffs(pending);
+                       mask = BIT(pin);
+                       /* Clear before handling so we can't lose an edge */
+                       writel(mask, reg);
+
+                       virq = irq_find_mapping(vg->domain, base + pin);
+                       generic_handle_irq(virq);
+
+                       /* In case bios or user sets triggering incorretly a pin
+                        * might remain in "interrupt triggered" state.
+                        */
+                       if (looplimit++ > 32) {
+                               dev_err(&vg->pdev->dev,
+                                       "Gpio %d interrupt flood, disabling\n",
+                                       base + pin);
+
+                               reg = byt_gpio_reg(&vg->chip, base + pin,
+                                                  BYT_CONF0_REG);
+                               mask = readl(reg);
+                               mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS |
+                                         BYT_TRIG_LVL);
+                               writel(mask, reg);
+                               mask = readl(reg); /* flush */
+                               break;
+                       }
+               }
+       }
+       chip->irq_eoi(data);
+}
+
+static void byt_irq_unmask(struct irq_data *d)
+{
+}
+
+static void byt_irq_mask(struct irq_data *d)
+{
+}
+
+static struct irq_chip byt_irqchip = {
+       .name = "BYT-GPIO",
+       .irq_mask = byt_irq_mask,
+       .irq_unmask = byt_irq_unmask,
+       .irq_set_type = byt_irq_type,
+};
+
+static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
+{
+       void __iomem *reg;
+       u32 base, value;
+
+       /* clear interrupt status trigger registers */
+       for (base = 0; base < vg->chip.ngpio; base += 32) {
+               reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
+               writel(0xffffffff, reg);
+               /* make sure trigger bits are cleared, if not then a pin
+                  might be misconfigured in bios */
+               value = readl(reg);
+               if (value)
+                       dev_err(&vg->pdev->dev,
+                               "GPIO interrupt error, pins misconfigured\n");
+       }
+}
+
+static int byt_gpio_irq_map(struct irq_domain *d, unsigned int virq,
+                           irq_hw_number_t hw)
+{
+       struct byt_gpio *vg = d->host_data;
+
+       irq_set_chip_and_handler_name(virq, &byt_irqchip, handle_simple_irq,
+                                     "demux");
+       irq_set_chip_data(virq, vg);
+       irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+       return 0;
+}
+
+static const struct irq_domain_ops byt_gpio_irq_ops = {
+       .map = byt_gpio_irq_map,
+};
+
+static int byt_gpio_probe(struct platform_device *pdev)
+{
+       struct byt_gpio *vg;
+       struct gpio_chip *gc;
+       struct resource *mem_rc, *irq_rc;
+       struct device *dev = &pdev->dev;
+       struct acpi_device *acpi_dev;
+       struct pinctrl_gpio_range *range;
+       acpi_handle handle = ACPI_HANDLE(dev);
+       unsigned hwirq;
+       int ret;
+
+       if (acpi_bus_get_device(handle, &acpi_dev))
+               return -ENODEV;
+
+       vg = devm_kzalloc(dev, sizeof(struct byt_gpio), GFP_KERNEL);
+       if (!vg) {
+               dev_err(&pdev->dev, "can't allocate byt_gpio chip data\n");
+               return -ENOMEM;
+       }
+
+       for (range = byt_ranges; range->name; range++) {
+               if (!strcmp(acpi_dev->pnp.unique_id, range->name)) {
+                       vg->chip.ngpio = range->npins;
+                       vg->range = range;
+                       break;
+               }
+       }
+
+       if (!vg->chip.ngpio || !vg->range)
+               return -ENODEV;
+
+       vg->pdev = pdev;
+       platform_set_drvdata(pdev, vg);
+
+       mem_rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       vg->reg_base = devm_ioremap_resource(dev, mem_rc);
+       if (IS_ERR(vg->reg_base))
+               return PTR_ERR(vg->reg_base);
+
+       spin_lock_init(&vg->lock);
+
+       gc = &vg->chip;
+       gc->label = dev_name(&pdev->dev);
+       gc->owner = THIS_MODULE;
+       gc->request = byt_gpio_request;
+       gc->free = byt_gpio_free;
+       gc->direction_input = byt_gpio_direction_input;
+       gc->direction_output = byt_gpio_direction_output;
+       gc->get = byt_gpio_get;
+       gc->set = byt_gpio_set;
+       gc->dbg_show = byt_gpio_dbg_show;
+       gc->base = -1;
+       gc->can_sleep = 0;
+       gc->dev = dev;
+
+       ret = gpiochip_add(gc);
+       if (ret) {
+               dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
+               return ret;
+       }
+
+       /* set up interrupts  */
+       irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (irq_rc && irq_rc->start) {
+               hwirq = irq_rc->start;
+               gc->to_irq = byt_gpio_to_irq;
+
+               vg->domain = irq_domain_add_linear(NULL, gc->ngpio,
+                                                  &byt_gpio_irq_ops, vg);
+               if (!vg->domain)
+                       return -ENXIO;
+
+               byt_gpio_irq_init_hw(vg);
+
+               irq_set_handler_data(hwirq, vg);
+               irq_set_chained_handler(hwirq, byt_gpio_irq_handler);
+
+               /* Register interrupt handlers for gpio signaled acpi events */
+               acpi_gpiochip_request_interrupts(gc);
+       }
+
+       pm_runtime_enable(dev);
+
+       return 0;
+}
+
+static int byt_gpio_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int byt_gpio_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+
+static const struct dev_pm_ops byt_gpio_pm_ops = {
+       .runtime_suspend = byt_gpio_runtime_suspend,
+       .runtime_resume = byt_gpio_runtime_resume,
+};
+
+static const struct acpi_device_id byt_gpio_acpi_match[] = {
+       { "INT33B2", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match);
+
+static int byt_gpio_remove(struct platform_device *pdev)
+{
+       struct byt_gpio *vg = platform_get_drvdata(pdev);
+       int err;
+       pm_runtime_disable(&pdev->dev);
+       err = gpiochip_remove(&vg->chip);
+       if (err)
+               dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
+
+       return 0;
+}
+
+static struct platform_driver byt_gpio_driver = {
+       .probe          = byt_gpio_probe,
+       .remove         = byt_gpio_remove,
+       .driver         = {
+               .name   = "byt_gpio",
+               .owner  = THIS_MODULE,
+               .pm     = &byt_gpio_pm_ops,
+               .acpi_match_table = ACPI_PTR(byt_gpio_acpi_match),
+       },
+};
+
+static int __init byt_gpio_init(void)
+{
+       return platform_driver_register(&byt_gpio_driver);
+}
+
+subsys_initcall(byt_gpio_init);
index c8f20a3d8f8850aa758759627075a2fd87e4f1f5..a1c88b30f71f9aafa603860592e05a06df4a896d 100644 (file)
@@ -113,7 +113,7 @@ static struct lock_class_key gpio_lock_class;
 
 /* pins are just named GPIO0..GPIO53 */
 #define BCM2835_GPIO_PIN(a) PINCTRL_PIN(a, "gpio" #a)
-struct pinctrl_pin_desc bcm2835_gpio_pins[] = {
+static struct pinctrl_pin_desc bcm2835_gpio_pins[] = {
        BCM2835_GPIO_PIN(0),
        BCM2835_GPIO_PIN(1),
        BCM2835_GPIO_PIN(2),
index eeff7f7fc920d6b9362ee028d6e6a1f96e225cd0..f22a2193d949a1915a9759a6466a94a2ecfed2f7 100644 (file)
@@ -853,7 +853,6 @@ static int __exit u300_gpio_remove(struct platform_device *pdev)
        }
        u300_gpio_free_ports(gpio);
        clk_disable_unprepare(gpio->clk);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 5f58cf0e96e2e1e55660677193bd0b142eecf771..a74b3cbd745163a8624930114eccc43f5dcdc90a 100644 (file)
@@ -50,37 +50,58 @@ static const struct of_device_id exynos_wkup_irq_ids[] = {
        { }
 };
 
-static void exynos_gpio_irq_unmask(struct irq_data *irqd)
+static void exynos_gpio_irq_mask(struct irq_data *irqd)
 {
        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
        struct samsung_pinctrl_drv_data *d = bank->drvdata;
        unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
        unsigned long mask;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bank->slock, flags);
 
        mask = readl(d->virt_base + reg_mask);
-       mask &= ~(1 << irqd->hwirq);
+       mask |= 1 << irqd->hwirq;
        writel(mask, d->virt_base + reg_mask);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
 }
 
-static void exynos_gpio_irq_mask(struct irq_data *irqd)
+static void exynos_gpio_irq_ack(struct irq_data *irqd)
 {
        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
        struct samsung_pinctrl_drv_data *d = bank->drvdata;
-       unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
-       unsigned long mask;
+       unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset;
 
-       mask = readl(d->virt_base + reg_mask);
-       mask |= 1 << irqd->hwirq;
-       writel(mask, d->virt_base + reg_mask);
+       writel(1 << irqd->hwirq, d->virt_base + reg_pend);
 }
 
-static void exynos_gpio_irq_ack(struct irq_data *irqd)
+static void exynos_gpio_irq_unmask(struct irq_data *irqd)
 {
        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
        struct samsung_pinctrl_drv_data *d = bank->drvdata;
-       unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset;
+       unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
+       unsigned long mask;
+       unsigned long flags;
 
-       writel(1 << irqd->hwirq, d->virt_base + reg_pend);
+       /*
+        * Ack level interrupts right before unmask
+        *
+        * If we don't do this we'll get a double-interrupt.  Level triggered
+        * interrupts must not fire an interrupt if the level is not
+        * _currently_ active, even if it was active while the interrupt was
+        * masked.
+        */
+       if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK)
+               exynos_gpio_irq_ack(irqd);
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       mask = readl(d->virt_base + reg_mask);
+       mask &= ~(1 << irqd->hwirq);
+       writel(mask, d->virt_base + reg_mask);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
 }
 
 static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
@@ -258,37 +279,58 @@ err_domains:
        return ret;
 }
 
-static void exynos_wkup_irq_unmask(struct irq_data *irqd)
+static void exynos_wkup_irq_mask(struct irq_data *irqd)
 {
        struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
        struct samsung_pinctrl_drv_data *d = b->drvdata;
        unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset;
        unsigned long mask;
+       unsigned long flags;
+
+       spin_lock_irqsave(&b->slock, flags);
 
        mask = readl(d->virt_base + reg_mask);
-       mask &= ~(1 << irqd->hwirq);
+       mask |= 1 << irqd->hwirq;
        writel(mask, d->virt_base + reg_mask);
+
+       spin_unlock_irqrestore(&b->slock, flags);
 }
 
-static void exynos_wkup_irq_mask(struct irq_data *irqd)
+static void exynos_wkup_irq_ack(struct irq_data *irqd)
 {
        struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
        struct samsung_pinctrl_drv_data *d = b->drvdata;
-       unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset;
-       unsigned long mask;
+       unsigned long pend = d->ctrl->weint_pend + b->eint_offset;
 
-       mask = readl(d->virt_base + reg_mask);
-       mask |= 1 << irqd->hwirq;
-       writel(mask, d->virt_base + reg_mask);
+       writel(1 << irqd->hwirq, d->virt_base + pend);
 }
 
-static void exynos_wkup_irq_ack(struct irq_data *irqd)
+static void exynos_wkup_irq_unmask(struct irq_data *irqd)
 {
        struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
        struct samsung_pinctrl_drv_data *d = b->drvdata;
-       unsigned long pend = d->ctrl->weint_pend + b->eint_offset;
+       unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset;
+       unsigned long mask;
+       unsigned long flags;
 
-       writel(1 << irqd->hwirq, d->virt_base + pend);
+       /*
+        * Ack level interrupts right before unmask
+        *
+        * If we don't do this we'll get a double-interrupt.  Level triggered
+        * interrupts must not fire an interrupt if the level is not
+        * _currently_ active, even if it was active while the interrupt was
+        * masked.
+        */
+       if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK)
+               exynos_wkup_irq_ack(irqd);
+
+       spin_lock_irqsave(&b->slock, flags);
+
+       mask = readl(d->virt_base + reg_mask);
+       mask &= ~(1 << irqd->hwirq);
+       writel(mask, d->virt_base + reg_mask);
+
+       spin_unlock_irqrestore(&b->slock, flags);
 }
 
 static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
index 32a48f44f574264f5c1b320e00db8065f1ba0616..3b283fd898ff54c9ab7b1dbdc3a2dd3c8dff0d53 100644 (file)
@@ -220,7 +220,7 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev,
                dev_err(dev, "failed to alloc memory for group name\n");
                goto free_map;
        }
-       sprintf(gname, "%s%s", np->name, GROUP_SUFFIX);
+       snprintf(gname, strlen(np->name) + 4, "%s%s", np->name, GROUP_SUFFIX);
 
        /*
         * don't have config options? then skip over to creating function
@@ -259,7 +259,8 @@ skip_cfgs:
                        dev_err(dev, "failed to alloc memory for func name\n");
                        goto free_cfg;
                }
-               sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX);
+               snprintf(fname, strlen(np->name) + 4, "%s%s", np->name,
+                        FUNCTION_SUFFIX);
 
                map[*nmaps].data.mux.group = gname;
                map[*nmaps].data.mux.function = fname;
@@ -713,7 +714,8 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
                        dev_err(dev, "failed to alloc memory for group name\n");
                        return -ENOMEM;
                }
-               sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX);
+               snprintf(gname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name,
+                        GROUP_SUFFIX);
 
                grp->name = gname;
                grp->pins = pin_list;
@@ -733,7 +735,8 @@ skip_to_pin_function:
                        dev_err(dev, "failed to alloc memory for func name\n");
                        return -ENOMEM;
                }
-               sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX);
+               snprintf(fname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name,
+                        FUNCTION_SUFFIX);
 
                func->name = fname;
                func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL);
@@ -806,7 +809,7 @@ static int exynos5440_pinctrl_register(struct platform_device *pdev,
 
        /* for each pin, set the name of the pin */
        for (pin = 0; pin < ctrldesc->npins; pin++) {
-               sprintf(pin_names, "gpio%02d", pin);
+               snprintf(pin_names, 6, "gpio%02d", pin);
                pdesc = pindesc + pin;
                pdesc->name = pin_names;
                pin_names += PIN_NAME_LENGTH;
index 4fcfff9243bee88ca8558c13e8324d02ec088862..57a4eb0add2ed36cb0e308cdea6b5b4bf4910d82 100644 (file)
@@ -221,13 +221,21 @@ static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
                pin_id = pins[i];
                pin_reg = &info->pin_regs[pin_id];
 
-               if (!pin_reg->mux_reg) {
+               if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->mux_reg) {
                        dev_err(ipctl->dev, "Pin(%s) does not support mux function\n",
                                info->pins[pin_id].name);
                        return -EINVAL;
                }
 
-               writel(mux[i], ipctl->base + pin_reg->mux_reg);
+               if (info->flags & SHARE_MUX_CONF_REG) {
+                       u32 reg;
+                       reg = readl(ipctl->base + pin_reg->mux_reg);
+                       reg &= ~(0x7 << 20);
+                       reg |= (mux[i] << 20);
+                       writel(reg, ipctl->base + pin_reg->mux_reg);
+               } else {
+                       writel(mux[i], ipctl->base + pin_reg->mux_reg);
+               }
                dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
                        pin_reg->mux_reg, mux[i]);
 
@@ -287,7 +295,7 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev,
        const struct imx_pinctrl_soc_info *info = ipctl->info;
        const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
 
-       if (!pin_reg->conf_reg) {
+       if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) {
                dev_err(info->dev, "Pin(%s) does not support config function\n",
                        info->pins[pin_id].name);
                return -EINVAL;
@@ -295,6 +303,9 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev,
 
        *config = readl(ipctl->base + pin_reg->conf_reg);
 
+       if (info->flags & SHARE_MUX_CONF_REG)
+               *config &= 0xffff;
+
        return 0;
 }
 
@@ -305,7 +316,7 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev,
        const struct imx_pinctrl_soc_info *info = ipctl->info;
        const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
 
-       if (!pin_reg->conf_reg) {
+       if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) {
                dev_err(info->dev, "Pin(%s) does not support config function\n",
                        info->pins[pin_id].name);
                return -EINVAL;
@@ -314,7 +325,15 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev,
        dev_dbg(ipctl->dev, "pinconf set pin %s\n",
                info->pins[pin_id].name);
 
-       writel(config, ipctl->base + pin_reg->conf_reg);
+       if (info->flags & SHARE_MUX_CONF_REG) {
+               u32 reg;
+               reg = readl(ipctl->base + pin_reg->conf_reg);
+               reg &= ~0xffff;
+               reg |= config;
+               writel(reg, ipctl->base + pin_reg->conf_reg);
+       } else {
+               writel(config, ipctl->base + pin_reg->conf_reg);
+       }
        dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
                pin_reg->conf_reg, config);
 
@@ -381,19 +400,24 @@ static struct pinctrl_desc imx_pinctrl_desc = {
  * 1 u32 CONFIG, so 24 types in total for each pin.
  */
 #define FSL_PIN_SIZE 24
+#define SHARE_FSL_PIN_SIZE 20
 
 static int imx_pinctrl_parse_groups(struct device_node *np,
                                    struct imx_pin_group *grp,
                                    struct imx_pinctrl_soc_info *info,
                                    u32 index)
 {
-       int size;
+       int size, pin_size;
        const __be32 *list;
        int i;
        u32 config;
 
        dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
 
+       if (info->flags & SHARE_MUX_CONF_REG)
+               pin_size = SHARE_FSL_PIN_SIZE;
+       else
+               pin_size = FSL_PIN_SIZE;
        /* Initialise group */
        grp->name = np->name;
 
@@ -403,12 +427,12 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
         */
        list = of_get_property(np, "fsl,pins", &size);
        /* we do not check return since it's safe node passed down */
-       if (!size || size % FSL_PIN_SIZE) {
+       if (!size || size % pin_size) {
                dev_err(info->dev, "Invalid fsl,pins property\n");
                return -EINVAL;
        }
 
-       grp->npins = size / FSL_PIN_SIZE;
+       grp->npins = size / pin_size;
        grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
                                GFP_KERNEL);
        grp->mux_mode = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
@@ -421,10 +445,17 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
                                GFP_KERNEL);
        for (i = 0; i < grp->npins; i++) {
                u32 mux_reg = be32_to_cpu(*list++);
-               u32 conf_reg = be32_to_cpu(*list++);
-               unsigned int pin_id = mux_reg ? mux_reg / 4 : conf_reg / 4;
-               struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
+               u32 conf_reg;
+               unsigned int pin_id;
+               struct imx_pin_reg *pin_reg;
 
+               if (info->flags & SHARE_MUX_CONF_REG)
+                       conf_reg = mux_reg;
+               else
+                       conf_reg = be32_to_cpu(*list++);
+
+               pin_id = mux_reg ? mux_reg / 4 : conf_reg / 4;
+               pin_reg = &info->pin_regs[pin_id];
                grp->pins[i] = pin_id;
                pin_reg->mux_reg = mux_reg;
                pin_reg->conf_reg = conf_reg;
index 607ef5497552db14c8ae99162ff2d010ab281999..bcedd991c9f344371ef80d1f8517e9353706e413 100644 (file)
@@ -74,8 +74,12 @@ struct imx_pinctrl_soc_info {
        unsigned int ngroups;
        struct imx_pmx_func *functions;
        unsigned int nfunctions;
+       unsigned int flags;
 };
 
+#define ZERO_OFFSET_VALID      0x1
+#define SHARE_MUX_CONF_REG     0x2
+
 #define NO_MUX         0x0
 #define NO_PAD         0x0
 
index b45c4eb357988beaa0091835e45e09c46209ac76..f5d56436ba7f838d77e78deb526178944c8efa35 100644 (file)
@@ -515,7 +515,6 @@ int mxs_pinctrl_probe(struct platform_device *pdev,
        return 0;
 
 err:
-       platform_set_drvdata(pdev, NULL);
        iounmap(d->base);
        return ret;
 }
@@ -525,7 +524,6 @@ int mxs_pinctrl_remove(struct platform_device *pdev)
 {
        struct mxs_pinctrl_data *d = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        pinctrl_unregister(d->pctl);
        iounmap(d->base);
 
index 8a4f9c5c0b8ee7b456ba2608efb70591eae47246..4a1cfdce22320aed2ad1579c61c30a7dbc955003 100644 (file)
@@ -1309,7 +1309,7 @@ static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
        return 0;
 }
 
-const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
+static const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
        .map = nmk_gpio_irq_map,
        .xlate = irq_domain_xlate_twocell,
 };
@@ -1681,7 +1681,7 @@ static bool nmk_pinctrl_dt_get_config(struct device_node *np,
        return has_config;
 }
 
-int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
                struct device_node *np,
                struct pinctrl_map **map,
                unsigned *reserved_maps,
@@ -1740,7 +1740,7 @@ exit:
        return ret;
 }
 
-int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+static int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
                                 struct device_node *np_config,
                                 struct pinctrl_map **map, unsigned *num_maps)
 {
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
new file mode 100644 (file)
index 0000000..1eb5a2e
--- /dev/null
@@ -0,0 +1,1394 @@
+/*
+ * Pinctrl driver for Rockchip SoCs
+ *
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * With some ideas taken from pinctrl-samsung:
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2012 Linaro Ltd
+ *             http://www.linaro.org
+ *
+ * and pinctrl-at91:
+ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/clk-provider.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+
+#include "core.h"
+#include "pinconf.h"
+
+/* GPIO control registers */
+#define GPIO_SWPORT_DR         0x00
+#define GPIO_SWPORT_DDR                0x04
+#define GPIO_INTEN             0x30
+#define GPIO_INTMASK           0x34
+#define GPIO_INTTYPE_LEVEL     0x38
+#define GPIO_INT_POLARITY      0x3c
+#define GPIO_INT_STATUS                0x40
+#define GPIO_INT_RAWSTATUS     0x44
+#define GPIO_DEBOUNCE          0x48
+#define GPIO_PORTS_EOI         0x4c
+#define GPIO_EXT_PORT          0x50
+#define GPIO_LS_SYNC           0x60
+
+/**
+ * @reg_base: register base of the gpio bank
+ * @clk: clock of the gpio bank
+ * @irq: interrupt of the gpio bank
+ * @pin_base: first pin number
+ * @nr_pins: number of pins in this bank
+ * @name: name of the bank
+ * @bank_num: number of the bank, to account for holes
+ * @valid: are all necessary informations present
+ * @of_node: dt node of this bank
+ * @drvdata: common pinctrl basedata
+ * @domain: irqdomain of the gpio bank
+ * @gpio_chip: gpiolib chip
+ * @grange: gpio range
+ * @slock: spinlock for the gpio bank
+ */
+struct rockchip_pin_bank {
+       void __iomem                    *reg_base;
+       struct clk                      *clk;
+       int                             irq;
+       u32                             pin_base;
+       u8                              nr_pins;
+       char                            *name;
+       u8                              bank_num;
+       bool                            valid;
+       struct device_node              *of_node;
+       struct rockchip_pinctrl         *drvdata;
+       struct irq_domain               *domain;
+       struct gpio_chip                gpio_chip;
+       struct pinctrl_gpio_range       grange;
+       spinlock_t                      slock;
+
+};
+
+#define PIN_BANK(id, pins, label)                      \
+       {                                               \
+               .bank_num       = id,                   \
+               .nr_pins        = pins,                 \
+               .name           = label,                \
+       }
+
+/**
+ * @pull_auto: some SoCs don't allow pulls to be specified as up or down, but
+ *            instead decide this automatically based on the pad-type.
+ */
+struct rockchip_pin_ctrl {
+       struct rockchip_pin_bank        *pin_banks;
+       u32                             nr_banks;
+       u32                             nr_pins;
+       char                            *label;
+       int                             mux_offset;
+       int                             pull_offset;
+       bool                            pull_auto;
+       int                             pull_bank_stride;
+};
+
+struct rockchip_pin_config {
+       unsigned int            func;
+       unsigned long           *configs;
+       unsigned int            nconfigs;
+};
+
+/**
+ * struct rockchip_pin_group: represent group of pins of a pinmux function.
+ * @name: name of the pin group, used to lookup the group.
+ * @pins: the pins included in this group.
+ * @npins: number of pins included in this group.
+ * @func: the mux function number to be programmed when selected.
+ * @configs: the config values to be set for each pin
+ * @nconfigs: number of configs for each pin
+ */
+struct rockchip_pin_group {
+       const char                      *name;
+       unsigned int                    npins;
+       unsigned int                    *pins;
+       struct rockchip_pin_config      *data;
+};
+
+/**
+ * struct rockchip_pmx_func: represent a pin function.
+ * @name: name of the pin function, used to lookup the function.
+ * @groups: one or more names of pin groups that provide this function.
+ * @num_groups: number of groups included in @groups.
+ */
+struct rockchip_pmx_func {
+       const char              *name;
+       const char              **groups;
+       u8                      ngroups;
+};
+
+struct rockchip_pinctrl {
+       void __iomem                    *reg_base;
+       struct device                   *dev;
+       struct rockchip_pin_ctrl        *ctrl;
+       struct pinctrl_desc             pctl;
+       struct pinctrl_dev              *pctl_dev;
+       struct rockchip_pin_group       *groups;
+       unsigned int                    ngroups;
+       struct rockchip_pmx_func        *functions;
+       unsigned int                    nfunctions;
+};
+
+static inline struct rockchip_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
+{
+       return container_of(gc, struct rockchip_pin_bank, gpio_chip);
+}
+
+static const inline struct rockchip_pin_group *pinctrl_name_to_group(
+                                       const struct rockchip_pinctrl *info,
+                                       const char *name)
+{
+       const struct rockchip_pin_group *grp = NULL;
+       int i;
+
+       for (i = 0; i < info->ngroups; i++) {
+               if (strcmp(info->groups[i].name, name))
+                       continue;
+
+               grp = &info->groups[i];
+               break;
+       }
+
+       return grp;
+}
+
+/*
+ * given a pin number that is local to a pin controller, find out the pin bank
+ * and the register base of the pin bank.
+ */
+static struct rockchip_pin_bank *pin_to_bank(struct rockchip_pinctrl *info,
+                                                               unsigned pin)
+{
+       struct rockchip_pin_bank *b = info->ctrl->pin_banks;
+
+       while ((pin >= b->pin_base) &&
+                       ((b->pin_base + b->nr_pins - 1) < pin))
+               b++;
+
+       return b;
+}
+
+static struct rockchip_pin_bank *bank_num_to_bank(
+                                       struct rockchip_pinctrl *info,
+                                       unsigned num)
+{
+       struct rockchip_pin_bank *b = info->ctrl->pin_banks;
+       int i;
+
+       for (i = 0; i < info->ctrl->nr_banks; i++) {
+               if (b->bank_num == num)
+                       break;
+
+               b++;
+       }
+
+       if (b->bank_num != num)
+               return ERR_PTR(-EINVAL);
+
+       return b;
+}
+
+/*
+ * Pinctrl_ops handling
+ */
+
+static int rockchip_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->ngroups;
+}
+
+static const char *rockchip_get_group_name(struct pinctrl_dev *pctldev,
+                                                       unsigned selector)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->groups[selector].name;
+}
+
+static int rockchip_get_group_pins(struct pinctrl_dev *pctldev,
+                                     unsigned selector, const unsigned **pins,
+                                     unsigned *npins)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       if (selector >= info->ngroups)
+               return -EINVAL;
+
+       *pins = info->groups[selector].pins;
+       *npins = info->groups[selector].npins;
+
+       return 0;
+}
+
+static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev,
+                                struct device_node *np,
+                                struct pinctrl_map **map, unsigned *num_maps)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const struct rockchip_pin_group *grp;
+       struct pinctrl_map *new_map;
+       struct device_node *parent;
+       int map_num = 1;
+       int i;
+
+       /*
+        * first find the group of this node and check if we need to create
+        * config maps for pins
+        */
+       grp = pinctrl_name_to_group(info, np->name);
+       if (!grp) {
+               dev_err(info->dev, "unable to find group for node %s\n",
+                       np->name);
+               return -EINVAL;
+       }
+
+       map_num += grp->npins;
+       new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num,
+                                                               GFP_KERNEL);
+       if (!new_map)
+               return -ENOMEM;
+
+       *map = new_map;
+       *num_maps = map_num;
+
+       /* create mux map */
+       parent = of_get_parent(np);
+       if (!parent) {
+               devm_kfree(pctldev->dev, new_map);
+               return -EINVAL;
+       }
+       new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+       new_map[0].data.mux.function = parent->name;
+       new_map[0].data.mux.group = np->name;
+       of_node_put(parent);
+
+       /* create config map */
+       new_map++;
+       for (i = 0; i < grp->npins; i++) {
+               new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
+               new_map[i].data.configs.group_or_pin =
+                               pin_get_name(pctldev, grp->pins[i]);
+               new_map[i].data.configs.configs = grp->data[i].configs;
+               new_map[i].data.configs.num_configs = grp->data[i].nconfigs;
+       }
+
+       dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
+               (*map)->data.mux.function, (*map)->data.mux.group, map_num);
+
+       return 0;
+}
+
+static void rockchip_dt_free_map(struct pinctrl_dev *pctldev,
+                                   struct pinctrl_map *map, unsigned num_maps)
+{
+}
+
+static const struct pinctrl_ops rockchip_pctrl_ops = {
+       .get_groups_count       = rockchip_get_groups_count,
+       .get_group_name         = rockchip_get_group_name,
+       .get_group_pins         = rockchip_get_group_pins,
+       .dt_node_to_map         = rockchip_dt_node_to_map,
+       .dt_free_map            = rockchip_dt_free_map,
+};
+
+/*
+ * Hardware access
+ */
+
+/*
+ * Set a new mux function for a pin.
+ *
+ * The register is divided into the upper and lower 16 bit. When changing
+ * a value, the previous register value is not read and changed. Instead
+ * it seems the changed bits are marked in the upper 16 bit, while the
+ * changed value gets set in the same offset in the lower 16 bit.
+ * All pin settings seem to be 2 bit wide in both the upper and lower
+ * parts.
+ * @bank: pin bank to change
+ * @pin: pin to change
+ * @mux: new mux function to set
+ */
+static void rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+       void __iomem *reg = info->reg_base + info->ctrl->mux_offset;
+       unsigned long flags;
+       u8 bit;
+       u32 data;
+
+       dev_dbg(info->dev, "setting mux of GPIO%d-%d to %d\n",
+                                               bank->bank_num, pin, mux);
+
+       /* get basic quadrupel of mux registers and the correct reg inside */
+       reg += bank->bank_num * 0x10;
+       reg += (pin / 8) * 4;
+       bit = (pin % 8) * 2;
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       data = (3 << (bit + 16));
+       data |= (mux & 3) << bit;
+       writel(data, reg);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       void __iomem *reg;
+       u8 bit;
+
+       /* rk3066b does support any pulls */
+       if (!ctrl->pull_offset)
+               return PIN_CONFIG_BIAS_DISABLE;
+
+       reg = info->reg_base + ctrl->pull_offset;
+
+       if (ctrl->pull_auto) {
+               reg += bank->bank_num * ctrl->pull_bank_stride;
+               reg += (pin_num / 16) * 4;
+               bit = pin_num % 16;
+
+               return !(readl_relaxed(reg) & BIT(bit))
+                               ? PIN_CONFIG_BIAS_PULL_PIN_DEFAULT
+                               : PIN_CONFIG_BIAS_DISABLE;
+       } else {
+               dev_err(info->dev, "pull support for rk31xx not implemented\n");
+               return -EIO;
+       }
+}
+
+static int rockchip_set_pull(struct rockchip_pin_bank *bank,
+                                       int pin_num, int pull)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       void __iomem *reg;
+       unsigned long flags;
+       u8 bit;
+       u32 data;
+
+       dev_dbg(info->dev, "setting pull of GPIO%d-%d to %d\n",
+                bank->bank_num, pin_num, pull);
+
+       /* rk3066b does support any pulls */
+       if (!ctrl->pull_offset)
+               return pull ? -EINVAL : 0;
+
+       reg = info->reg_base + ctrl->pull_offset;
+
+       if (ctrl->pull_auto) {
+               if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT &&
+                                       pull != PIN_CONFIG_BIAS_DISABLE) {
+                       dev_err(info->dev, "only PIN_DEFAULT and DISABLE allowed\n");
+                       return -EINVAL;
+               }
+
+               reg += bank->bank_num * ctrl->pull_bank_stride;
+               reg += (pin_num / 16) * 4;
+               bit = pin_num % 16;
+
+               spin_lock_irqsave(&bank->slock, flags);
+
+               data = BIT(bit + 16);
+               if (pull == PIN_CONFIG_BIAS_DISABLE)
+                       data |= BIT(bit);
+               writel(data, reg);
+
+               spin_unlock_irqrestore(&bank->slock, flags);
+       } else {
+               if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) {
+                       dev_err(info->dev, "pull direction (up/down) needs to be specified\n");
+                       return -EINVAL;
+               }
+
+               dev_err(info->dev, "pull support for rk31xx not implemented\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * Pinmux_ops handling
+ */
+
+static int rockchip_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->nfunctions;
+}
+
+static const char *rockchip_pmx_get_func_name(struct pinctrl_dev *pctldev,
+                                         unsigned selector)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->functions[selector].name;
+}
+
+static int rockchip_pmx_get_groups(struct pinctrl_dev *pctldev,
+                               unsigned selector, const char * const **groups,
+                               unsigned * const num_groups)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       *groups = info->functions[selector].groups;
+       *num_groups = info->functions[selector].ngroups;
+
+       return 0;
+}
+
+static int rockchip_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+                                                           unsigned group)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const unsigned int *pins = info->groups[group].pins;
+       const struct rockchip_pin_config *data = info->groups[group].data;
+       struct rockchip_pin_bank *bank;
+       int cnt;
+
+       dev_dbg(info->dev, "enable function %s group %s\n",
+               info->functions[selector].name, info->groups[group].name);
+
+       /*
+        * for each pin in the pin group selected, program the correspoding pin
+        * pin function number in the config register.
+        */
+       for (cnt = 0; cnt < info->groups[group].npins; cnt++) {
+               bank = pin_to_bank(info, pins[cnt]);
+               rockchip_set_mux(bank, pins[cnt] - bank->pin_base,
+                                data[cnt].func);
+       }
+
+       return 0;
+}
+
+static void rockchip_pmx_disable(struct pinctrl_dev *pctldev,
+                                       unsigned selector, unsigned group)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const unsigned int *pins = info->groups[group].pins;
+       struct rockchip_pin_bank *bank;
+       int cnt;
+
+       dev_dbg(info->dev, "disable function %s group %s\n",
+               info->functions[selector].name, info->groups[group].name);
+
+       for (cnt = 0; cnt < info->groups[group].npins; cnt++) {
+               bank = pin_to_bank(info, pins[cnt]);
+               rockchip_set_mux(bank, pins[cnt] - bank->pin_base, 0);
+       }
+}
+
+/*
+ * The calls to gpio_direction_output() and gpio_direction_input()
+ * leads to this function call (via the pinctrl_gpio_direction_{input|output}()
+ * function called from the gpiolib interface).
+ */
+static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+                                             struct pinctrl_gpio_range *range,
+                                             unsigned offset, bool input)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       struct rockchip_pin_bank *bank;
+       struct gpio_chip *chip;
+       int pin;
+       u32 data;
+
+       chip = range->gc;
+       bank = gc_to_pin_bank(chip);
+       pin = offset - chip->base;
+
+       dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n",
+                offset, range->name, pin, input ? "input" : "output");
+
+       rockchip_set_mux(bank, pin, RK_FUNC_GPIO);
+
+       data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
+       /* set bit to 1 for output, 0 for input */
+       if (!input)
+               data |= BIT(pin);
+       else
+               data &= ~BIT(pin);
+       writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
+
+       return 0;
+}
+
+static const struct pinmux_ops rockchip_pmx_ops = {
+       .get_functions_count    = rockchip_pmx_get_funcs_count,
+       .get_function_name      = rockchip_pmx_get_func_name,
+       .get_function_groups    = rockchip_pmx_get_groups,
+       .enable                 = rockchip_pmx_enable,
+       .disable                = rockchip_pmx_disable,
+       .gpio_set_direction     = rockchip_pmx_gpio_set_direction,
+};
+
+/*
+ * Pinconf_ops handling
+ */
+
+static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
+                                       enum pin_config_param pull)
+{
+       /* rk3066b does support any pulls */
+       if (!ctrl->pull_offset)
+               return pull ? false : true;
+
+       if (ctrl->pull_auto) {
+               if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT &&
+                                       pull != PIN_CONFIG_BIAS_DISABLE)
+                       return false;
+       } else {
+               if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+                       return false;
+       }
+
+       return true;
+}
+
+/* set the pin config settings for a specified pin */
+static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+                                                       unsigned long config)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       struct rockchip_pin_bank *bank = pin_to_bank(info, pin);
+       enum pin_config_param param = pinconf_to_config_param(config);
+       u16 arg = pinconf_to_config_argument(config);
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+               return rockchip_set_pull(bank, pin - bank->pin_base, param);
+               break;
+       case PIN_CONFIG_BIAS_PULL_UP:
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+       case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+               if (!rockchip_pinconf_pull_valid(info->ctrl, param))
+                       return -ENOTSUPP;
+
+               if (!arg)
+                       return -EINVAL;
+
+               return rockchip_set_pull(bank, pin - bank->pin_base, param);
+               break;
+       default:
+               return -ENOTSUPP;
+               break;
+       }
+
+       return 0;
+}
+
+/* get the pin config settings for a specified pin */
+static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
+                                                       unsigned long *config)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       struct rockchip_pin_bank *bank = pin_to_bank(info, pin);
+       enum pin_config_param param = pinconf_to_config_param(*config);
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+               if (rockchip_get_pull(bank, pin - bank->pin_base) != param)
+                       return -EINVAL;
+
+               *config = 0;
+               break;
+       case PIN_CONFIG_BIAS_PULL_UP:
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+       case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+               if (!rockchip_pinconf_pull_valid(info->ctrl, param))
+                       return -ENOTSUPP;
+
+               if (rockchip_get_pull(bank, pin - bank->pin_base) != param)
+                       return -EINVAL;
+
+               *config = 1;
+               break;
+       default:
+               return -ENOTSUPP;
+               break;
+       }
+
+       return 0;
+}
+
+static const struct pinconf_ops rockchip_pinconf_ops = {
+       .pin_config_get                 = rockchip_pinconf_get,
+       .pin_config_set                 = rockchip_pinconf_set,
+};
+
+static const char *gpio_compat = "rockchip,gpio-bank";
+
+static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info,
+                                               struct device_node *np)
+{
+       struct device_node *child;
+
+       for_each_child_of_node(np, child) {
+               if (of_device_is_compatible(child, gpio_compat))
+                       continue;
+
+               info->nfunctions++;
+               info->ngroups += of_get_child_count(child);
+       }
+}
+
+static int rockchip_pinctrl_parse_groups(struct device_node *np,
+                                             struct rockchip_pin_group *grp,
+                                             struct rockchip_pinctrl *info,
+                                             u32 index)
+{
+       struct rockchip_pin_bank *bank;
+       int size;
+       const __be32 *list;
+       int num;
+       int i, j;
+       int ret;
+
+       dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+
+       /* Initialise group */
+       grp->name = np->name;
+
+       /*
+        * the binding format is rockchip,pins = <bank pin mux CONFIG>,
+        * do sanity check and calculate pins number
+        */
+       list = of_get_property(np, "rockchip,pins", &size);
+       /* we do not check return since it's safe node passed down */
+       size /= sizeof(*list);
+       if (!size || size % 4) {
+               dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n");
+               return -EINVAL;
+       }
+
+       grp->npins = size / 4;
+
+       grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
+                                               GFP_KERNEL);
+       grp->data = devm_kzalloc(info->dev, grp->npins *
+                                         sizeof(struct rockchip_pin_config),
+                                       GFP_KERNEL);
+       if (!grp->pins || !grp->data)
+               return -ENOMEM;
+
+       for (i = 0, j = 0; i < size; i += 4, j++) {
+               const __be32 *phandle;
+               struct device_node *np_config;
+
+               num = be32_to_cpu(*list++);
+               bank = bank_num_to_bank(info, num);
+               if (IS_ERR(bank))
+                       return PTR_ERR(bank);
+
+               grp->pins[j] = bank->pin_base + be32_to_cpu(*list++);
+               grp->data[j].func = be32_to_cpu(*list++);
+
+               phandle = list++;
+               if (!phandle)
+                       return -EINVAL;
+
+               np_config = of_find_node_by_phandle(be32_to_cpup(phandle));
+               ret = pinconf_generic_parse_dt_config(np_config,
+                               &grp->data[j].configs, &grp->data[j].nconfigs);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int rockchip_pinctrl_parse_functions(struct device_node *np,
+                                               struct rockchip_pinctrl *info,
+                                               u32 index)
+{
+       struct device_node *child;
+       struct rockchip_pmx_func *func;
+       struct rockchip_pin_group *grp;
+       int ret;
+       static u32 grp_index;
+       u32 i = 0;
+
+       dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+
+       func = &info->functions[index];
+
+       /* Initialise function */
+       func->name = np->name;
+       func->ngroups = of_get_child_count(np);
+       if (func->ngroups <= 0)
+               return 0;
+
+       func->groups = devm_kzalloc(info->dev,
+                       func->ngroups * sizeof(char *), GFP_KERNEL);
+       if (!func->groups)
+               return -ENOMEM;
+
+       for_each_child_of_node(np, child) {
+               func->groups[i] = child->name;
+               grp = &info->groups[grp_index++];
+               ret = rockchip_pinctrl_parse_groups(child, grp, info, i++);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int rockchip_pinctrl_parse_dt(struct platform_device *pdev,
+                                             struct rockchip_pinctrl *info)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct device_node *child;
+       int ret;
+       int i;
+
+       rockchip_pinctrl_child_count(info, np);
+
+       dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
+       dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
+
+       info->functions = devm_kzalloc(dev, info->nfunctions *
+                                             sizeof(struct rockchip_pmx_func),
+                                             GFP_KERNEL);
+       if (!info->functions) {
+               dev_err(dev, "failed to allocate memory for function list\n");
+               return -EINVAL;
+       }
+
+       info->groups = devm_kzalloc(dev, info->ngroups *
+                                           sizeof(struct rockchip_pin_group),
+                                           GFP_KERNEL);
+       if (!info->groups) {
+               dev_err(dev, "failed allocate memory for ping group list\n");
+               return -EINVAL;
+       }
+
+       i = 0;
+
+       for_each_child_of_node(np, child) {
+               if (of_device_is_compatible(child, gpio_compat))
+                       continue;
+               ret = rockchip_pinctrl_parse_functions(child, info, i++);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to parse function\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int rockchip_pinctrl_register(struct platform_device *pdev,
+                                       struct rockchip_pinctrl *info)
+{
+       struct pinctrl_desc *ctrldesc = &info->pctl;
+       struct pinctrl_pin_desc *pindesc, *pdesc;
+       struct rockchip_pin_bank *pin_bank;
+       int pin, bank, ret;
+       int k;
+
+       ctrldesc->name = "rockchip-pinctrl";
+       ctrldesc->owner = THIS_MODULE;
+       ctrldesc->pctlops = &rockchip_pctrl_ops;
+       ctrldesc->pmxops = &rockchip_pmx_ops;
+       ctrldesc->confops = &rockchip_pinconf_ops;
+
+       pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
+                       info->ctrl->nr_pins, GFP_KERNEL);
+       if (!pindesc) {
+               dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
+               return -ENOMEM;
+       }
+       ctrldesc->pins = pindesc;
+       ctrldesc->npins = info->ctrl->nr_pins;
+
+       pdesc = pindesc;
+       for (bank = 0 , k = 0; bank < info->ctrl->nr_banks; bank++) {
+               pin_bank = &info->ctrl->pin_banks[bank];
+               for (pin = 0; pin < pin_bank->nr_pins; pin++, k++) {
+                       pdesc->number = k;
+                       pdesc->name = kasprintf(GFP_KERNEL, "%s-%d",
+                                               pin_bank->name, pin);
+                       pdesc++;
+               }
+       }
+
+       info->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, info);
+       if (!info->pctl_dev) {
+               dev_err(&pdev->dev, "could not register pinctrl driver\n");
+               return -EINVAL;
+       }
+
+       for (bank = 0; bank < info->ctrl->nr_banks; ++bank) {
+               pin_bank = &info->ctrl->pin_banks[bank];
+               pin_bank->grange.name = pin_bank->name;
+               pin_bank->grange.id = bank;
+               pin_bank->grange.pin_base = pin_bank->pin_base;
+               pin_bank->grange.base = pin_bank->gpio_chip.base;
+               pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
+               pin_bank->grange.gc = &pin_bank->gpio_chip;
+               pinctrl_add_gpio_range(info->pctl_dev, &pin_bank->grange);
+       }
+
+       ret = rockchip_pinctrl_parse_dt(pdev, info);
+       if (ret) {
+               pinctrl_unregister(info->pctl_dev);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * GPIO handling
+ */
+
+static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+       struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+       void __iomem *reg = bank->reg_base + GPIO_SWPORT_DR;
+       unsigned long flags;
+       u32 data;
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       data = readl(reg);
+       data &= ~BIT(offset);
+       if (value)
+               data |= BIT(offset);
+       writel(data, reg);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+/*
+ * Returns the level of the pin for input direction and setting of the DR
+ * register for output gpios.
+ */
+static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+       u32 data;
+
+       data = readl(bank->reg_base + GPIO_EXT_PORT);
+       data >>= offset;
+       data &= 1;
+       return data;
+}
+
+/*
+ * gpiolib gpio_direction_input callback function. The setting of the pin
+ * mux function as 'gpio input' will be handled by the pinctrl susbsystem
+ * interface.
+ */
+static int rockchip_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+       return pinctrl_gpio_direction_input(gc->base + offset);
+}
+
+/*
+ * gpiolib gpio_direction_output callback function. The setting of the pin
+ * mux function as 'gpio output' will be handled by the pinctrl susbsystem
+ * interface.
+ */
+static int rockchip_gpio_direction_output(struct gpio_chip *gc,
+                                         unsigned offset, int value)
+{
+       rockchip_gpio_set(gc, offset, value);
+       return pinctrl_gpio_direction_output(gc->base + offset);
+}
+
+/*
+ * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
+ * and a virtual IRQ, if not already present.
+ */
+static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+       unsigned int virq;
+
+       if (!bank->domain)
+               return -ENXIO;
+
+       virq = irq_create_mapping(bank->domain, offset);
+
+       return (virq) ? : -ENXIO;
+}
+
+static const struct gpio_chip rockchip_gpiolib_chip = {
+       .set = rockchip_gpio_set,
+       .get = rockchip_gpio_get,
+       .direction_input = rockchip_gpio_direction_input,
+       .direction_output = rockchip_gpio_direction_output,
+       .to_irq = rockchip_gpio_to_irq,
+       .owner = THIS_MODULE,
+};
+
+/*
+ * Interrupt handling
+ */
+
+static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct rockchip_pin_bank *bank = irq_get_handler_data(irq);
+       u32 pend;
+
+       dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name);
+
+       chained_irq_enter(chip, desc);
+
+       pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS);
+
+       while (pend) {
+               unsigned int virq;
+
+               irq = __ffs(pend);
+               pend &= ~BIT(irq);
+               virq = irq_linear_revmap(bank->domain, irq);
+
+               if (!virq) {
+                       dev_err(bank->drvdata->dev, "unmapped irq %d\n", irq);
+                       continue;
+               }
+
+               dev_dbg(bank->drvdata->dev, "handling irq %d\n", irq);
+
+               generic_handle_irq(virq);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct rockchip_pin_bank *bank = gc->private;
+       u32 mask = BIT(d->hwirq);
+       u32 polarity;
+       u32 level;
+       u32 data;
+
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
+       else
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+
+       irq_gc_lock(gc);
+
+       level = readl_relaxed(gc->reg_base + GPIO_INTTYPE_LEVEL);
+       polarity = readl_relaxed(gc->reg_base + GPIO_INT_POLARITY);
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               level |= mask;
+               polarity |= mask;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               level |= mask;
+               polarity &= ~mask;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               level &= ~mask;
+               polarity |= mask;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               level &= ~mask;
+               polarity &= ~mask;
+               break;
+       default:
+               irq_gc_unlock(gc);
+               return -EINVAL;
+       }
+
+       writel_relaxed(level, gc->reg_base + GPIO_INTTYPE_LEVEL);
+       writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY);
+
+       irq_gc_unlock(gc);
+
+       /* make sure the pin is configured as gpio input */
+       rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO);
+       data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
+       data &= ~mask;
+       writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
+
+       return 0;
+}
+
+static int rockchip_interrupts_register(struct platform_device *pdev,
+                                               struct rockchip_pinctrl *info)
+{
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       struct rockchip_pin_bank *bank = ctrl->pin_banks;
+       unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+       struct irq_chip_generic *gc;
+       int ret;
+       int i;
+
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               if (!bank->valid) {
+                       dev_warn(&pdev->dev, "bank %s is not valid\n",
+                                bank->name);
+                       continue;
+               }
+
+               bank->domain = irq_domain_add_linear(bank->of_node, 32,
+                                               &irq_generic_chip_ops, NULL);
+               if (!bank->domain) {
+                       dev_warn(&pdev->dev, "could not initialize irq domain for bank %s\n",
+                                bank->name);
+                       continue;
+               }
+
+               ret = irq_alloc_domain_generic_chips(bank->domain, 32, 1,
+                                        "rockchip_gpio_irq", handle_level_irq,
+                                        clr, 0, IRQ_GC_INIT_MASK_CACHE);
+               if (ret) {
+                       dev_err(&pdev->dev, "could not alloc generic chips for bank %s\n",
+                               bank->name);
+                       irq_domain_remove(bank->domain);
+                       continue;
+               }
+
+               gc = irq_get_domain_generic_chip(bank->domain, 0);
+               gc->reg_base = bank->reg_base;
+               gc->private = bank;
+               gc->chip_types[0].regs.mask = GPIO_INTEN;
+               gc->chip_types[0].regs.ack = GPIO_PORTS_EOI;
+               gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
+               gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+               gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+               gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
+               gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type;
+
+               irq_set_handler_data(bank->irq, bank);
+               irq_set_chained_handler(bank->irq, rockchip_irq_demux);
+       }
+
+       return 0;
+}
+
+static int rockchip_gpiolib_register(struct platform_device *pdev,
+                                               struct rockchip_pinctrl *info)
+{
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       struct rockchip_pin_bank *bank = ctrl->pin_banks;
+       struct gpio_chip *gc;
+       int ret;
+       int i;
+
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               if (!bank->valid) {
+                       dev_warn(&pdev->dev, "bank %s is not valid\n",
+                                bank->name);
+                       continue;
+               }
+
+               bank->gpio_chip = rockchip_gpiolib_chip;
+
+               gc = &bank->gpio_chip;
+               gc->base = bank->pin_base;
+               gc->ngpio = bank->nr_pins;
+               gc->dev = &pdev->dev;
+               gc->of_node = bank->of_node;
+               gc->label = bank->name;
+
+               ret = gpiochip_add(gc);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
+                                                       gc->label, ret);
+                       goto fail;
+               }
+       }
+
+       rockchip_interrupts_register(pdev, info);
+
+       return 0;
+
+fail:
+       for (--i, --bank; i >= 0; --i, --bank) {
+               if (!bank->valid)
+                       continue;
+
+               if (gpiochip_remove(&bank->gpio_chip))
+                       dev_err(&pdev->dev, "gpio chip %s remove failed\n",
+                                                       bank->gpio_chip.label);
+       }
+       return ret;
+}
+
+static int rockchip_gpiolib_unregister(struct platform_device *pdev,
+                                               struct rockchip_pinctrl *info)
+{
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       struct rockchip_pin_bank *bank = ctrl->pin_banks;
+       int ret = 0;
+       int i;
+
+       for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank) {
+               if (!bank->valid)
+                       continue;
+
+               ret = gpiochip_remove(&bank->gpio_chip);
+       }
+
+       if (ret)
+               dev_err(&pdev->dev, "gpio chip remove failed\n");
+
+       return ret;
+}
+
+static int rockchip_get_bank_data(struct rockchip_pin_bank *bank,
+                                 struct device *dev)
+{
+       struct resource res;
+
+       if (of_address_to_resource(bank->of_node, 0, &res)) {
+               dev_err(dev, "cannot find IO resource for bank\n");
+               return -ENOENT;
+       }
+
+       bank->reg_base = devm_ioremap_resource(dev, &res);
+       if (IS_ERR(bank->reg_base))
+               return PTR_ERR(bank->reg_base);
+
+       bank->irq = irq_of_parse_and_map(bank->of_node, 0);
+
+       bank->clk = of_clk_get(bank->of_node, 0);
+       if (IS_ERR(bank->clk))
+               return PTR_ERR(bank->clk);
+
+       return clk_prepare_enable(bank->clk);
+}
+
+static const struct of_device_id rockchip_pinctrl_dt_match[];
+
+/* retrieve the soc specific data */
+static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
+                                               struct rockchip_pinctrl *d,
+                                               struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *np;
+       struct rockchip_pin_ctrl *ctrl;
+       struct rockchip_pin_bank *bank;
+       int i;
+
+       match = of_match_node(rockchip_pinctrl_dt_match, node);
+       ctrl = (struct rockchip_pin_ctrl *)match->data;
+
+       for_each_child_of_node(node, np) {
+               if (!of_find_property(np, "gpio-controller", NULL))
+                       continue;
+
+               bank = ctrl->pin_banks;
+               for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+                       if (!strcmp(bank->name, np->name)) {
+                               bank->of_node = np;
+
+                               if (!rockchip_get_bank_data(bank, &pdev->dev))
+                                       bank->valid = true;
+
+                               break;
+                       }
+               }
+       }
+
+       bank = ctrl->pin_banks;
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               spin_lock_init(&bank->slock);
+               bank->drvdata = d;
+               bank->pin_base = ctrl->nr_pins;
+               ctrl->nr_pins += bank->nr_pins;
+       }
+
+       return ctrl;
+}
+
+static int rockchip_pinctrl_probe(struct platform_device *pdev)
+{
+       struct rockchip_pinctrl *info;
+       struct device *dev = &pdev->dev;
+       struct rockchip_pin_ctrl *ctrl;
+       struct resource *res;
+       int ret;
+
+       if (!dev->of_node) {
+               dev_err(dev, "device tree node not found\n");
+               return -ENODEV;
+       }
+
+       info = devm_kzalloc(dev, sizeof(struct rockchip_pinctrl), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       ctrl = rockchip_pinctrl_get_soc_data(info, pdev);
+       if (!ctrl) {
+               dev_err(dev, "driver data not available\n");
+               return -EINVAL;
+       }
+       info->ctrl = ctrl;
+       info->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "cannot find IO resource\n");
+               return -ENOENT;
+       }
+
+       info->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(info->reg_base))
+               return PTR_ERR(info->reg_base);
+
+       ret = rockchip_gpiolib_register(pdev, info);
+       if (ret)
+               return ret;
+
+       ret = rockchip_pinctrl_register(pdev, info);
+       if (ret) {
+               rockchip_gpiolib_unregister(pdev, info);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, info);
+
+       return 0;
+}
+
+static struct rockchip_pin_bank rk2928_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 rk2928_pin_ctrl = {
+               .pin_banks              = rk2928_pin_banks,
+               .nr_banks               = ARRAY_SIZE(rk2928_pin_banks),
+               .label                  = "RK2928-GPIO",
+               .mux_offset             = 0xa8,
+               .pull_offset            = 0x118,
+               .pull_auto              = 1,
+               .pull_bank_stride       = 8,
+};
+
+static struct rockchip_pin_bank rk3066a_pin_banks[] = {
+       PIN_BANK(0, 32, "gpio0"),
+       PIN_BANK(1, 32, "gpio1"),
+       PIN_BANK(2, 32, "gpio2"),
+       PIN_BANK(3, 32, "gpio3"),
+       PIN_BANK(4, 32, "gpio4"),
+       PIN_BANK(6, 16, "gpio6"),
+};
+
+static struct rockchip_pin_ctrl rk3066a_pin_ctrl = {
+               .pin_banks              = rk3066a_pin_banks,
+               .nr_banks               = ARRAY_SIZE(rk3066a_pin_banks),
+               .label                  = "RK3066a-GPIO",
+               .mux_offset             = 0xa8,
+               .pull_offset            = 0x118,
+               .pull_auto              = 1,
+               .pull_bank_stride       = 8,
+};
+
+static struct rockchip_pin_bank rk3066b_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 rk3066b_pin_ctrl = {
+               .pin_banks      = rk3066b_pin_banks,
+               .nr_banks       = ARRAY_SIZE(rk3066b_pin_banks),
+               .label          = "RK3066b-GPIO",
+               .mux_offset     = 0x60,
+               .pull_offset    = -EINVAL,
+};
+
+static struct rockchip_pin_bank rk3188_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 rk3188_pin_ctrl = {
+               .pin_banks              = rk3188_pin_banks,
+               .nr_banks               = ARRAY_SIZE(rk3188_pin_banks),
+               .label                  = "RK3188-GPIO",
+               .mux_offset             = 0x68,
+               .pull_offset            = 0x164,
+               .pull_bank_stride       = 16,
+};
+
+static const struct of_device_id rockchip_pinctrl_dt_match[] = {
+       { .compatible = "rockchip,rk2928-pinctrl",
+               .data = (void *)&rk2928_pin_ctrl },
+       { .compatible = "rockchip,rk3066a-pinctrl",
+               .data = (void *)&rk3066a_pin_ctrl },
+       { .compatible = "rockchip,rk3066b-pinctrl",
+               .data = (void *)&rk3066b_pin_ctrl },
+       { .compatible = "rockchip,rk3188-pinctrl",
+               .data = (void *)&rk3188_pin_ctrl },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rockchip_pinctrl_dt_match);
+
+static struct platform_driver rockchip_pinctrl_driver = {
+       .probe          = rockchip_pinctrl_probe,
+       .driver = {
+               .name   = "rockchip-pinctrl",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(rockchip_pinctrl_dt_match),
+       },
+};
+
+static int __init rockchip_pinctrl_drv_register(void)
+{
+       return platform_driver_register(&rockchip_pinctrl_driver);
+}
+postcore_initcall(rockchip_pinctrl_drv_register);
+
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_DESCRIPTION("Rockchip pinctrl driver");
+MODULE_LICENSE("GPL v2");
index 0a6c720b6655ba1860d282a453073ac89da9881e..a7fa9e2d475137252de98d7ff635171ff6124540 100644 (file)
@@ -50,7 +50,7 @@ static struct pin_config {
 };
 
 /* Global list of devices (struct samsung_pinctrl_drv_data) */
-LIST_HEAD(drvdata_list);
+static LIST_HEAD(drvdata_list);
 
 static unsigned int pin_base;
 
index b9fa046186011bb0e3c781bbc6b0b7787b272c97..6866548fab31669d5141a7c8af21c10e0caa895d 100644 (file)
@@ -30,7 +30,7 @@
 #define DRIVER_NAME                    "pinctrl-single"
 #define PCS_MUX_PINS_NAME              "pinctrl-single,pins"
 #define PCS_MUX_BITS_NAME              "pinctrl-single,bits"
-#define PCS_REG_NAME_LEN               ((sizeof(unsigned long) * 2) + 1)
+#define PCS_REG_NAME_LEN               ((sizeof(unsigned long) * 2) + 3)
 #define PCS_OFF_DISABLED               ~0U
 
 /**
@@ -163,6 +163,7 @@ struct pcs_name {
  * @foff:      value to turn mux off
  * @fmax:      max number of functions in fmask
  * @is_pinconf:        whether supports pinconf
+ * @bits_per_pin:number of bits per pin
  * @names:     array of register names for pins
  * @pins:      physical pins on the SoC
  * @pgtree:    pingroup index radix tree
@@ -190,6 +191,7 @@ struct pcs_device {
        unsigned fmax;
        bool bits_per_mux;
        bool is_pinconf;
+       unsigned bits_per_pin;
        struct pcs_name *names;
        struct pcs_data pins;
        struct radix_tree_root pgtree;
@@ -431,10 +433,11 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector,
 
                vals = &func->vals[i];
                val = pcs->read(vals->reg);
-               if (!vals->mask)
-                       mask = pcs->fmask;
+
+               if (pcs->bits_per_mux)
+                       mask = vals->mask;
                else
-                       mask = pcs->fmask & vals->mask;
+                       mask = pcs->fmask;
 
                val &= ~mask;
                val |= (vals->val & mask);
@@ -741,7 +744,8 @@ static const struct pinconf_ops pcs_pinconf_ops = {
  * @pcs: pcs driver instance
  * @offset: register offset from base
  */
-static int pcs_add_pin(struct pcs_device *pcs, unsigned offset)
+static int pcs_add_pin(struct pcs_device *pcs, unsigned offset,
+               unsigned pin_pos)
 {
        struct pinctrl_pin_desc *pin;
        struct pcs_name *pn;
@@ -756,8 +760,8 @@ static int pcs_add_pin(struct pcs_device *pcs, unsigned offset)
 
        pin = &pcs->pins.pa[i];
        pn = &pcs->names[i];
-       sprintf(pn->name, "%lx",
-               (unsigned long)pcs->res->start + offset);
+       sprintf(pn->name, "%lx.%d",
+               (unsigned long)pcs->res->start + offset, pin_pos);
        pin->name = pn->name;
        pin->number = i;
        pcs->pins.cur++;
@@ -777,9 +781,17 @@ static int pcs_add_pin(struct pcs_device *pcs, unsigned offset)
 static int pcs_allocate_pin_table(struct pcs_device *pcs)
 {
        int mux_bytes, nr_pins, i;
+       int num_pins_in_register = 0;
 
        mux_bytes = pcs->width / BITS_PER_BYTE;
-       nr_pins = pcs->size / mux_bytes;
+
+       if (pcs->bits_per_mux) {
+               pcs->bits_per_pin = fls(pcs->fmask);
+               nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin;
+               num_pins_in_register = pcs->width / pcs->bits_per_pin;
+       } else {
+               nr_pins = pcs->size / mux_bytes;
+       }
 
        dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins);
        pcs->pins.pa = devm_kzalloc(pcs->dev,
@@ -800,9 +812,17 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs)
        for (i = 0; i < pcs->desc.npins; i++) {
                unsigned offset;
                int res;
-
-               offset = i * mux_bytes;
-               res = pcs_add_pin(pcs, offset);
+               int byte_num;
+               int pin_pos = 0;
+
+               if (pcs->bits_per_mux) {
+                       byte_num = (pcs->bits_per_pin * i) / BITS_PER_BYTE;
+                       offset = (byte_num / mux_bytes) * mux_bytes;
+                       pin_pos = i % num_pins_in_register;
+               } else {
+                       offset = i * mux_bytes;
+               }
+               res = pcs_add_pin(pcs, offset, pin_pos);
                if (res < 0) {
                        dev_err(pcs->dev, "error adding pins: %i\n", res);
                        return res;
@@ -919,7 +939,10 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
                return -EINVAL;
        }
 
-       index = offset / (pcs->width / BITS_PER_BYTE);
+       if (pcs->bits_per_mux)
+               index = (offset * BITS_PER_BYTE) / pcs->bits_per_pin;
+       else
+               index = offset / (pcs->width / BITS_PER_BYTE);
 
        return index;
 }
@@ -1097,29 +1120,18 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
 {
        struct pcs_func_vals *vals;
        const __be32 *mux;
-       int size, params, rows, *pins, index = 0, found = 0, res = -ENOMEM;
+       int size, rows, *pins, index = 0, found = 0, res = -ENOMEM;
        struct pcs_function *function;
 
-       if (pcs->bits_per_mux) {
-               params = 3;
-               mux = of_get_property(np, PCS_MUX_BITS_NAME, &size);
-       } else {
-               params = 2;
-               mux = of_get_property(np, PCS_MUX_PINS_NAME, &size);
-       }
-
-       if (!mux) {
-               dev_err(pcs->dev, "no valid property for %s\n", np->name);
-               return -EINVAL;
-       }
-
-       if (size < (sizeof(*mux) * params)) {
-               dev_err(pcs->dev, "bad data for %s\n", np->name);
+       mux = of_get_property(np, PCS_MUX_PINS_NAME, &size);
+       if ((!mux) || (size < sizeof(*mux) * 2)) {
+               dev_err(pcs->dev, "bad data for mux %s\n",
+                       np->name);
                return -EINVAL;
        }
 
        size /= sizeof(*mux);   /* Number of elements in array */
-       rows = size / params;
+       rows = size / 2;
 
        vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL);
        if (!vals)
@@ -1137,10 +1149,6 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
                val = be32_to_cpup(mux + index++);
                vals[found].reg = pcs->base + offset;
                vals[found].val = val;
-               if (params == 3) {
-                       val = be32_to_cpup(mux + index++);
-                       vals[found].mask = val;
-               }
 
                pin = pcs_get_pin_by_offset(pcs, offset);
                if (pin < 0) {
@@ -1184,6 +1192,125 @@ free_function:
 free_pins:
        devm_kfree(pcs->dev, pins);
 
+free_vals:
+       devm_kfree(pcs->dev, vals);
+
+       return res;
+}
+
+#define PARAMS_FOR_BITS_PER_MUX 3
+
+static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
+                                               struct device_node *np,
+                                               struct pinctrl_map **map,
+                                               unsigned *num_maps,
+                                               const char **pgnames)
+{
+       struct pcs_func_vals *vals;
+       const __be32 *mux;
+       int size, rows, *pins, index = 0, found = 0, res = -ENOMEM;
+       int npins_in_row;
+       struct pcs_function *function;
+
+       mux = of_get_property(np, PCS_MUX_BITS_NAME, &size);
+
+       if (!mux) {
+               dev_err(pcs->dev, "no valid property for %s\n", np->name);
+               return -EINVAL;
+       }
+
+       if (size < (sizeof(*mux) * PARAMS_FOR_BITS_PER_MUX)) {
+               dev_err(pcs->dev, "bad data for %s\n", np->name);
+               return -EINVAL;
+       }
+
+       /* Number of elements in array */
+       size /= sizeof(*mux);
+
+       rows = size / PARAMS_FOR_BITS_PER_MUX;
+       npins_in_row = pcs->width / pcs->bits_per_pin;
+
+       vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows * npins_in_row,
+                       GFP_KERNEL);
+       if (!vals)
+               return -ENOMEM;
+
+       pins = devm_kzalloc(pcs->dev, sizeof(*pins) * rows * npins_in_row,
+                       GFP_KERNEL);
+       if (!pins)
+               goto free_vals;
+
+       while (index < size) {
+               unsigned offset, val;
+               unsigned mask, bit_pos, val_pos, mask_pos, submask;
+               unsigned pin_num_from_lsb;
+               int pin;
+
+               offset = be32_to_cpup(mux + index++);
+               val = be32_to_cpup(mux + index++);
+               mask = be32_to_cpup(mux + index++);
+
+               /* Parse pins in each row from LSB */
+               while (mask) {
+                       bit_pos = ffs(mask);
+                       pin_num_from_lsb = bit_pos / pcs->bits_per_pin;
+                       mask_pos = ((pcs->fmask) << (bit_pos - 1));
+                       val_pos = val & mask_pos;
+                       submask = mask & mask_pos;
+                       mask &= ~mask_pos;
+
+                       if (submask != mask_pos) {
+                               dev_warn(pcs->dev,
+                                               "Invalid submask 0x%x for %s at 0x%x\n",
+                                               submask, np->name, offset);
+                               continue;
+                       }
+
+                       vals[found].mask = submask;
+                       vals[found].reg = pcs->base + offset;
+                       vals[found].val = val_pos;
+
+                       pin = pcs_get_pin_by_offset(pcs, offset);
+                       if (pin < 0) {
+                               dev_err(pcs->dev,
+                                       "could not add functions for %s %ux\n",
+                                       np->name, offset);
+                               break;
+                       }
+                       pins[found++] = pin + pin_num_from_lsb;
+               }
+       }
+
+       pgnames[0] = np->name;
+       function = pcs_add_function(pcs, np, np->name, vals, found, pgnames, 1);
+       if (!function)
+               goto free_pins;
+
+       res = pcs_add_pingroup(pcs, np, np->name, pins, found);
+       if (res < 0)
+               goto free_function;
+
+       (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
+       (*map)->data.mux.group = np->name;
+       (*map)->data.mux.function = np->name;
+
+       if (pcs->is_pinconf) {
+               dev_err(pcs->dev, "pinconf not supported\n");
+               goto free_pingroups;
+       }
+
+       *num_maps = 1;
+       return 0;
+
+free_pingroups:
+       pcs_free_pingroups(pcs);
+       *num_maps = 1;
+free_function:
+       pcs_remove_function(pcs, function);
+
+free_pins:
+       devm_kfree(pcs->dev, pins);
+
 free_vals:
        devm_kfree(pcs->dev, vals);
 
@@ -1219,12 +1346,22 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
                goto free_map;
        }
 
-       ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, num_maps,
-                                         pgnames);
-       if (ret < 0) {
-               dev_err(pcs->dev, "no pins entries for %s\n",
-                       np_config->name);
-               goto free_pgnames;
+       if (pcs->bits_per_mux) {
+               ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config, map,
+                               num_maps, pgnames);
+               if (ret < 0) {
+                       dev_err(pcs->dev, "no pins entries for %s\n",
+                               np_config->name);
+                       goto free_pgnames;
+               }
+       } else {
+               ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
+                               num_maps, pgnames);
+               if (ret < 0) {
+                       dev_err(pcs->dev, "no pins entries for %s\n",
+                               np_config->name);
+                       goto free_pgnames;
+               }
        }
 
        return 0;
@@ -1346,6 +1483,29 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
        return ret;
 }
 
+static int pinctrl_single_suspend(struct platform_device *pdev,
+                                       pm_message_t state)
+{
+       struct pcs_device *pcs;
+
+       pcs = platform_get_drvdata(pdev);
+       if (!pcs)
+               return -EINVAL;
+
+       return pinctrl_force_sleep(pcs->pctl);
+}
+
+static int pinctrl_single_resume(struct platform_device *pdev)
+{
+       struct pcs_device *pcs;
+
+       pcs = platform_get_drvdata(pdev);
+       if (!pcs)
+               return -EINVAL;
+
+       return pinctrl_force_default(pcs->pctl);
+}
+
 static int pcs_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -1494,6 +1654,10 @@ static struct platform_driver pcs_driver = {
                .name           = DRIVER_NAME,
                .of_match_table = pcs_of_match,
        },
+#ifdef CONFIG_PM
+       .suspend = pinctrl_single_suspend,
+       .resume = pinctrl_single_resume,
+#endif
 };
 
 module_platform_driver(pcs_driver);
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
new file mode 100644 (file)
index 0000000..04d4506
--- /dev/null
@@ -0,0 +1,1403 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Authors:
+ *     Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/platform_device.h>
+#include "core.h"
+
+/* PIO Block registers */
+/* PIO output */
+#define REG_PIO_POUT                   0x00
+/* Set bits of POUT */
+#define REG_PIO_SET_POUT               0x04
+/* Clear bits of POUT */
+#define REG_PIO_CLR_POUT               0x08
+/* PIO input */
+#define REG_PIO_PIN                    0x10
+/* PIO configuration */
+#define REG_PIO_PC(n)                  (0x20 + (n) * 0x10)
+/* Set bits of PC[2:0] */
+#define REG_PIO_SET_PC(n)              (0x24 + (n) * 0x10)
+/* Clear bits of PC[2:0] */
+#define REG_PIO_CLR_PC(n)              (0x28 + (n) * 0x10)
+/* PIO input comparison */
+#define REG_PIO_PCOMP                  0x50
+/* Set bits of PCOMP */
+#define REG_PIO_SET_PCOMP              0x54
+/* Clear bits of PCOMP */
+#define REG_PIO_CLR_PCOMP              0x58
+/* PIO input comparison mask */
+#define REG_PIO_PMASK                  0x60
+/* Set bits of PMASK */
+#define REG_PIO_SET_PMASK              0x64
+/* Clear bits of PMASK */
+#define REG_PIO_CLR_PMASK              0x68
+
+#define ST_GPIO_DIRECTION_BIDIR        0x1
+#define ST_GPIO_DIRECTION_OUT  0x2
+#define ST_GPIO_DIRECTION_IN   0x4
+
+/**
+ *  Packed style retime configuration.
+ *  There are two registers cfg0 and cfg1 in this style for each bank.
+ *  Each field in this register is 8 bit corresponding to 8 pins in the bank.
+ */
+#define RT_P_CFGS_PER_BANK                     2
+#define RT_P_CFG0_CLK1NOTCLK0_FIELD(reg)       REG_FIELD(reg, 0, 7)
+#define RT_P_CFG0_DELAY_0_FIELD(reg)           REG_FIELD(reg, 16, 23)
+#define RT_P_CFG0_DELAY_1_FIELD(reg)           REG_FIELD(reg, 24, 31)
+#define RT_P_CFG1_INVERTCLK_FIELD(reg)         REG_FIELD(reg, 0, 7)
+#define RT_P_CFG1_RETIME_FIELD(reg)            REG_FIELD(reg, 8, 15)
+#define RT_P_CFG1_CLKNOTDATA_FIELD(reg)                REG_FIELD(reg, 16, 23)
+#define RT_P_CFG1_DOUBLE_EDGE_FIELD(reg)       REG_FIELD(reg, 24, 31)
+
+/**
+ * Dedicated style retime Configuration register
+ * each register is dedicated per pin.
+ */
+#define RT_D_CFGS_PER_BANK             8
+#define RT_D_CFG_CLK_SHIFT             0
+#define RT_D_CFG_CLK_MASK              (0x3 << 0)
+#define RT_D_CFG_CLKNOTDATA_SHIFT      2
+#define RT_D_CFG_CLKNOTDATA_MASK       BIT(2)
+#define RT_D_CFG_DELAY_SHIFT           3
+#define RT_D_CFG_DELAY_MASK            (0xf << 3)
+#define RT_D_CFG_DELAY_INNOTOUT_SHIFT  7
+#define RT_D_CFG_DELAY_INNOTOUT_MASK   BIT(7)
+#define RT_D_CFG_DOUBLE_EDGE_SHIFT     8
+#define RT_D_CFG_DOUBLE_EDGE_MASK      BIT(8)
+#define RT_D_CFG_INVERTCLK_SHIFT       9
+#define RT_D_CFG_INVERTCLK_MASK                BIT(9)
+#define RT_D_CFG_RETIME_SHIFT          10
+#define RT_D_CFG_RETIME_MASK           BIT(10)
+
+/*
+ * Pinconf is represented in an opaque unsigned long variable.
+ * Below is the bit allocation details for each possible configuration.
+ * All the bit fields can be encapsulated into four variables
+ * (direction, retime-type, retime-clk, retime-delay)
+ *
+ *      +----------------+
+ *[31:28]| reserved-3     |
+ *      +----------------+-------------
+ *[27]   |     oe        |             |
+ *      +----------------+             v
+ *[26]   |     pu        |     [Direction      ]
+ *      +----------------+             ^
+ *[25]   |     od        |             |
+ *      +----------------+-------------
+ *[24]   | reserved-2     |
+ *      +----------------+-------------
+ *[23]   |    retime      |            |
+ *      +----------------+             |
+ *[22]   | retime-invclk  |            |
+ *      +----------------+             v
+ *[21]   |retime-clknotdat|    [Retime-type    ]
+ *      +----------------+             ^
+ *[20]   | retime-de      |            |
+ *      +----------------+-------------
+ *[19:18]| retime-clk     |------>[Retime-Clk  ]
+ *      +----------------+
+ *[17:16]|  reserved-1    |
+ *      +----------------+
+ *[15..0]| retime-delay   |------>[Retime Delay]
+ *      +----------------+
+ */
+
+#define ST_PINCONF_UNPACK(conf, param)\
+                               ((conf >> ST_PINCONF_ ##param ##_SHIFT) \
+                               & ST_PINCONF_ ##param ##_MASK)
+
+#define ST_PINCONF_PACK(conf, val, param)      (conf |=\
+                               ((val & ST_PINCONF_ ##param ##_MASK) << \
+                                       ST_PINCONF_ ##param ##_SHIFT))
+
+/* Output enable */
+#define ST_PINCONF_OE_MASK             0x1
+#define ST_PINCONF_OE_SHIFT            27
+#define ST_PINCONF_OE                  BIT(27)
+#define ST_PINCONF_UNPACK_OE(conf)     ST_PINCONF_UNPACK(conf, OE)
+#define ST_PINCONF_PACK_OE(conf)       ST_PINCONF_PACK(conf, 1, OE)
+
+/* Pull Up */
+#define ST_PINCONF_PU_MASK             0x1
+#define ST_PINCONF_PU_SHIFT            26
+#define ST_PINCONF_PU                  BIT(26)
+#define ST_PINCONF_UNPACK_PU(conf)     ST_PINCONF_UNPACK(conf, PU)
+#define ST_PINCONF_PACK_PU(conf)       ST_PINCONF_PACK(conf, 1, PU)
+
+/* Open Drain */
+#define ST_PINCONF_OD_MASK             0x1
+#define ST_PINCONF_OD_SHIFT            25
+#define ST_PINCONF_OD                  BIT(25)
+#define ST_PINCONF_UNPACK_OD(conf)     ST_PINCONF_UNPACK(conf, OD)
+#define ST_PINCONF_PACK_OD(conf)       ST_PINCONF_PACK(conf, 1, OD)
+
+#define ST_PINCONF_RT_MASK             0x1
+#define ST_PINCONF_RT_SHIFT            23
+#define ST_PINCONF_RT                  BIT(23)
+#define ST_PINCONF_UNPACK_RT(conf)     ST_PINCONF_UNPACK(conf, RT)
+#define ST_PINCONF_PACK_RT(conf)       ST_PINCONF_PACK(conf, 1, RT)
+
+#define ST_PINCONF_RT_INVERTCLK_MASK   0x1
+#define ST_PINCONF_RT_INVERTCLK_SHIFT  22
+#define ST_PINCONF_RT_INVERTCLK                BIT(22)
+#define ST_PINCONF_UNPACK_RT_INVERTCLK(conf) \
+                       ST_PINCONF_UNPACK(conf, RT_INVERTCLK)
+#define ST_PINCONF_PACK_RT_INVERTCLK(conf) \
+                       ST_PINCONF_PACK(conf, 1, RT_INVERTCLK)
+
+#define ST_PINCONF_RT_CLKNOTDATA_MASK  0x1
+#define ST_PINCONF_RT_CLKNOTDATA_SHIFT 21
+#define ST_PINCONF_RT_CLKNOTDATA       BIT(21)
+#define ST_PINCONF_UNPACK_RT_CLKNOTDATA(conf)  \
+                               ST_PINCONF_UNPACK(conf, RT_CLKNOTDATA)
+#define ST_PINCONF_PACK_RT_CLKNOTDATA(conf) \
+                               ST_PINCONF_PACK(conf, 1, RT_CLKNOTDATA)
+
+#define ST_PINCONF_RT_DOUBLE_EDGE_MASK 0x1
+#define ST_PINCONF_RT_DOUBLE_EDGE_SHIFT        20
+#define ST_PINCONF_RT_DOUBLE_EDGE      BIT(20)
+#define ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(conf) \
+                               ST_PINCONF_UNPACK(conf, RT_DOUBLE_EDGE)
+#define ST_PINCONF_PACK_RT_DOUBLE_EDGE(conf) \
+                               ST_PINCONF_PACK(conf, 1, RT_DOUBLE_EDGE)
+
+#define ST_PINCONF_RT_CLK_MASK         0x3
+#define ST_PINCONF_RT_CLK_SHIFT                18
+#define ST_PINCONF_RT_CLK              BIT(18)
+#define ST_PINCONF_UNPACK_RT_CLK(conf) ST_PINCONF_UNPACK(conf, RT_CLK)
+#define ST_PINCONF_PACK_RT_CLK(conf, val) ST_PINCONF_PACK(conf, val, RT_CLK)
+
+/* RETIME_DELAY in Pico Secs */
+#define ST_PINCONF_RT_DELAY_MASK       0xffff
+#define ST_PINCONF_RT_DELAY_SHIFT      0
+#define ST_PINCONF_UNPACK_RT_DELAY(conf) ST_PINCONF_UNPACK(conf, RT_DELAY)
+#define ST_PINCONF_PACK_RT_DELAY(conf, val) \
+                               ST_PINCONF_PACK(conf, val, RT_DELAY)
+
+#define ST_GPIO_PINS_PER_BANK  (8)
+#define OF_GPIO_ARGS_MIN       (4)
+#define OF_RT_ARGS_MIN         (2)
+
+#define gpio_range_to_bank(chip) \
+               container_of(chip, struct st_gpio_bank, range)
+
+#define gpio_chip_to_bank(chip) \
+               container_of(chip, struct st_gpio_bank, gpio_chip)
+
+
+enum st_retime_style {
+       st_retime_style_none,
+       st_retime_style_packed,
+       st_retime_style_dedicated,
+};
+
+struct st_retime_dedicated {
+       struct regmap_field *rt[ST_GPIO_PINS_PER_BANK];
+};
+
+struct st_retime_packed {
+       struct regmap_field *clk1notclk0;
+       struct regmap_field *delay_0;
+       struct regmap_field *delay_1;
+       struct regmap_field *invertclk;
+       struct regmap_field *retime;
+       struct regmap_field *clknotdata;
+       struct regmap_field *double_edge;
+};
+
+struct st_pio_control {
+       u32 rt_pin_mask;
+       struct regmap_field *alt, *oe, *pu, *od;
+       /* retiming */
+       union {
+               struct st_retime_packed         rt_p;
+               struct st_retime_dedicated      rt_d;
+       } rt;
+};
+
+struct st_pctl_data {
+       enum st_retime_style rt_style;
+       unsigned int    *input_delays;
+       int             ninput_delays;
+       unsigned int    *output_delays;
+       int             noutput_delays;
+       /* register offset information */
+       int alt, oe, pu, od, rt;
+};
+
+struct st_pinconf {
+       int             pin;
+       const char      *name;
+       unsigned long   config;
+       int             altfunc;
+};
+
+struct st_pmx_func {
+       const char      *name;
+       const char      **groups;
+       unsigned        ngroups;
+};
+
+struct st_pctl_group {
+       const char              *name;
+       unsigned int            *pins;
+       unsigned                npins;
+       struct st_pinconf       *pin_conf;
+};
+
+struct st_gpio_bank {
+       struct gpio_chip                gpio_chip;
+       struct pinctrl_gpio_range       range;
+       void __iomem                    *base;
+       struct st_pio_control           pc;
+};
+
+struct st_pinctrl {
+       struct device                   *dev;
+       struct pinctrl_dev              *pctl;
+       struct st_gpio_bank             *banks;
+       int                             nbanks;
+       struct st_pmx_func              *functions;
+       int                             nfunctions;
+       struct st_pctl_group            *groups;
+       int                             ngroups;
+       struct regmap                   *regmap;
+       const struct st_pctl_data       *data;
+};
+
+/* SOC specific data */
+/* STiH415 data */
+unsigned int stih415_input_delays[] = {0, 500, 1000, 1500};
+unsigned int stih415_output_delays[] = {0, 1000, 2000, 3000};
+
+#define STIH415_PCTRL_COMMON_DATA                              \
+       .rt_style       = st_retime_style_packed,               \
+       .input_delays   = stih415_input_delays,                 \
+       .ninput_delays  = 4,                                    \
+       .output_delays = stih415_output_delays,                 \
+       .noutput_delays = 4
+
+static const struct st_pctl_data  stih415_sbc_data = {
+       STIH415_PCTRL_COMMON_DATA,
+       .alt = 0, .oe = 5, .pu = 7, .od = 9, .rt = 16,
+};
+
+static const struct st_pctl_data  stih415_front_data = {
+       STIH415_PCTRL_COMMON_DATA,
+       .alt = 0, .oe = 8, .pu = 10, .od = 12, .rt = 16,
+};
+
+static const struct st_pctl_data  stih415_rear_data = {
+       STIH415_PCTRL_COMMON_DATA,
+       .alt = 0, .oe = 6, .pu = 8, .od = 10, .rt = 38,
+};
+
+static const struct st_pctl_data  stih415_left_data = {
+       STIH415_PCTRL_COMMON_DATA,
+       .alt = 0, .oe = 3, .pu = 4, .od = 5, .rt = 6,
+};
+
+static const struct st_pctl_data  stih415_right_data = {
+       STIH415_PCTRL_COMMON_DATA,
+       .alt = 0, .oe = 5, .pu = 7, .od = 9, .rt = 11,
+};
+
+/* STiH416 data */
+unsigned int stih416_delays[] = {0, 300, 500, 750, 1000, 1250, 1500,
+                       1750, 2000, 2250, 2500, 2750, 3000, 3250 };
+
+static const struct st_pctl_data  stih416_data = {
+       .rt_style       = st_retime_style_dedicated,
+       .input_delays   = stih416_delays,
+       .ninput_delays  = 14,
+       .output_delays  = stih416_delays,
+       .noutput_delays = 14,
+       .alt = 0, .oe = 40, .pu = 50, .od = 60, .rt = 100,
+};
+
+/* Low level functions.. */
+static inline int st_gpio_bank(int gpio)
+{
+       return gpio/ST_GPIO_PINS_PER_BANK;
+}
+
+static inline int st_gpio_pin(int gpio)
+{
+       return gpio%ST_GPIO_PINS_PER_BANK;
+}
+
+static void st_pinconf_set_config(struct st_pio_control *pc,
+                               int pin, unsigned long config)
+{
+       struct regmap_field *output_enable = pc->oe;
+       struct regmap_field *pull_up = pc->pu;
+       struct regmap_field *open_drain = pc->od;
+       unsigned int oe_value, pu_value, od_value;
+       unsigned long mask = BIT(pin);
+
+       regmap_field_read(output_enable, &oe_value);
+       regmap_field_read(pull_up, &pu_value);
+       regmap_field_read(open_drain, &od_value);
+
+       /* Clear old values */
+       oe_value &= ~mask;
+       pu_value &= ~mask;
+       od_value &= ~mask;
+
+       if (config & ST_PINCONF_OE)
+               oe_value |= mask;
+       if (config & ST_PINCONF_PU)
+               pu_value |= mask;
+       if (config & ST_PINCONF_OD)
+               od_value |= mask;
+
+       regmap_field_write(output_enable, oe_value);
+       regmap_field_write(pull_up, pu_value);
+       regmap_field_write(open_drain, od_value);
+}
+
+static void st_pctl_set_function(struct st_pio_control *pc,
+                               int pin_id, int function)
+{
+       struct regmap_field *alt = pc->alt;
+       unsigned int val;
+       int pin = st_gpio_pin(pin_id);
+       int offset = pin * 4;
+
+       regmap_field_read(alt, &val);
+       val &= ~(0xf << offset);
+       val |= function << offset;
+       regmap_field_write(alt, val);
+}
+
+static unsigned long st_pinconf_delay_to_bit(unsigned int delay,
+       const struct st_pctl_data *data, unsigned long config)
+{
+       unsigned int *delay_times;
+       int num_delay_times, i, closest_index = -1;
+       unsigned int closest_divergence = UINT_MAX;
+
+       if (ST_PINCONF_UNPACK_OE(config)) {
+               delay_times = data->output_delays;
+               num_delay_times = data->noutput_delays;
+       } else {
+               delay_times = data->input_delays;
+               num_delay_times = data->ninput_delays;
+       }
+
+       for (i = 0; i < num_delay_times; i++) {
+               unsigned int divergence = abs(delay - delay_times[i]);
+
+               if (divergence == 0)
+                       return i;
+
+               if (divergence < closest_divergence) {
+                       closest_divergence = divergence;
+                       closest_index = i;
+               }
+       }
+
+       pr_warn("Attempt to set delay %d, closest available %d\n",
+            delay, delay_times[closest_index]);
+
+       return closest_index;
+}
+
+static unsigned long st_pinconf_bit_to_delay(unsigned int index,
+       const struct st_pctl_data *data, unsigned long output)
+{
+       unsigned int *delay_times;
+       int num_delay_times;
+
+       if (output) {
+               delay_times = data->output_delays;
+               num_delay_times = data->noutput_delays;
+       } else {
+               delay_times = data->input_delays;
+               num_delay_times = data->ninput_delays;
+       }
+
+       if (index < num_delay_times) {
+               return delay_times[index];
+       } else {
+               pr_warn("Delay not found in/out delay list\n");
+               return 0;
+       }
+}
+
+static void st_regmap_field_bit_set_clear_pin(struct regmap_field *field,
+       int enable, int pin)
+{
+       unsigned int val = 0;
+
+       regmap_field_read(field, &val);
+       if (enable)
+               val |= BIT(pin);
+       else
+               val &= ~BIT(pin);
+       regmap_field_write(field, val);
+}
+
+static void st_pinconf_set_retime_packed(struct st_pinctrl *info,
+       struct st_pio_control *pc,      unsigned long config, int pin)
+{
+       const struct st_pctl_data *data = info->data;
+       struct st_retime_packed *rt_p = &pc->rt.rt_p;
+       unsigned int delay;
+
+       st_regmap_field_bit_set_clear_pin(rt_p->clk1notclk0,
+                               ST_PINCONF_UNPACK_RT_CLK(config), pin);
+
+       st_regmap_field_bit_set_clear_pin(rt_p->clknotdata,
+                               ST_PINCONF_UNPACK_RT_CLKNOTDATA(config), pin);
+
+       st_regmap_field_bit_set_clear_pin(rt_p->double_edge,
+                               ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config), pin);
+
+       st_regmap_field_bit_set_clear_pin(rt_p->invertclk,
+                               ST_PINCONF_UNPACK_RT_INVERTCLK(config), pin);
+
+       st_regmap_field_bit_set_clear_pin(rt_p->retime,
+                               ST_PINCONF_UNPACK_RT(config), pin);
+
+       delay = st_pinconf_delay_to_bit(ST_PINCONF_UNPACK_RT_DELAY(config),
+                                       data, config);
+       /* 2 bit delay, lsb */
+       st_regmap_field_bit_set_clear_pin(rt_p->delay_0, delay & 0x1, pin);
+       /* 2 bit delay, msb */
+       st_regmap_field_bit_set_clear_pin(rt_p->delay_1, delay & 0x2, pin);
+
+}
+
+static void st_pinconf_set_retime_dedicated(struct st_pinctrl *info,
+       struct st_pio_control *pc, unsigned long config, int pin)
+{
+       int input       = ST_PINCONF_UNPACK_OE(config) ? 0 : 1;
+       int clk         = ST_PINCONF_UNPACK_RT_CLK(config);
+       int clknotdata  = ST_PINCONF_UNPACK_RT_CLKNOTDATA(config);
+       int double_edge = ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config);
+       int invertclk   = ST_PINCONF_UNPACK_RT_INVERTCLK(config);
+       int retime      = ST_PINCONF_UNPACK_RT(config);
+
+       unsigned long delay = st_pinconf_delay_to_bit(
+                       ST_PINCONF_UNPACK_RT_DELAY(config),
+                       info->data, config);
+       struct st_retime_dedicated *rt_d = &pc->rt.rt_d;
+
+       unsigned long retime_config =
+               ((clk) << RT_D_CFG_CLK_SHIFT) |
+               ((delay) << RT_D_CFG_DELAY_SHIFT) |
+               ((input) << RT_D_CFG_DELAY_INNOTOUT_SHIFT) |
+               ((retime) << RT_D_CFG_RETIME_SHIFT) |
+               ((clknotdata) << RT_D_CFG_CLKNOTDATA_SHIFT) |
+               ((invertclk) << RT_D_CFG_INVERTCLK_SHIFT) |
+               ((double_edge) << RT_D_CFG_DOUBLE_EDGE_SHIFT);
+
+       regmap_field_write(rt_d->rt[pin], retime_config);
+}
+
+static void st_pinconf_get_direction(struct st_pio_control *pc,
+       int pin, unsigned long *config)
+{
+       unsigned int oe_value, pu_value, od_value;
+
+       regmap_field_read(pc->oe, &oe_value);
+       regmap_field_read(pc->pu, &pu_value);
+       regmap_field_read(pc->od, &od_value);
+
+       if (oe_value & BIT(pin))
+               ST_PINCONF_PACK_OE(*config);
+       if (pu_value & BIT(pin))
+               ST_PINCONF_PACK_PU(*config);
+       if (od_value & BIT(pin))
+               ST_PINCONF_PACK_OD(*config);
+
+}
+
+static int st_pinconf_get_retime_packed(struct st_pinctrl *info,
+       struct st_pio_control *pc,      int pin, unsigned long *config)
+{
+       const struct st_pctl_data *data = info->data;
+       struct st_retime_packed *rt_p = &pc->rt.rt_p;
+       unsigned int delay_bits, delay, delay0, delay1, val;
+       int output = ST_PINCONF_UNPACK_OE(*config);
+
+       if (!regmap_field_read(rt_p->retime, &val) && (val & BIT(pin)))
+               ST_PINCONF_PACK_RT(*config);
+
+       if (!regmap_field_read(rt_p->clk1notclk0, &val) && (val & BIT(pin)))
+               ST_PINCONF_PACK_RT_CLK(*config, 1);
+
+       if (!regmap_field_read(rt_p->clknotdata, &val) && (val & BIT(pin)))
+               ST_PINCONF_PACK_RT_CLKNOTDATA(*config);
+
+       if (!regmap_field_read(rt_p->double_edge, &val) && (val & BIT(pin)))
+               ST_PINCONF_PACK_RT_DOUBLE_EDGE(*config);
+
+       if (!regmap_field_read(rt_p->invertclk, &val) && (val & BIT(pin)))
+               ST_PINCONF_PACK_RT_INVERTCLK(*config);
+
+       regmap_field_read(rt_p->delay_0, &delay0);
+       regmap_field_read(rt_p->delay_1, &delay1);
+       delay_bits = (((delay1 & BIT(pin)) ? 1 : 0) << 1) |
+                       (((delay0 & BIT(pin)) ? 1 : 0));
+       delay =  st_pinconf_bit_to_delay(delay_bits, data, output);
+       ST_PINCONF_PACK_RT_DELAY(*config, delay);
+
+       return 0;
+}
+
+static int st_pinconf_get_retime_dedicated(struct st_pinctrl *info,
+       struct st_pio_control *pc,      int pin, unsigned long *config)
+{
+       unsigned int value;
+       unsigned long delay_bits, delay, rt_clk;
+       int output = ST_PINCONF_UNPACK_OE(*config);
+       struct st_retime_dedicated *rt_d = &pc->rt.rt_d;
+
+       regmap_field_read(rt_d->rt[pin], &value);
+
+       rt_clk = (value & RT_D_CFG_CLK_MASK) >> RT_D_CFG_CLK_SHIFT;
+       ST_PINCONF_PACK_RT_CLK(*config, rt_clk);
+
+       delay_bits = (value & RT_D_CFG_DELAY_MASK) >> RT_D_CFG_DELAY_SHIFT;
+       delay =  st_pinconf_bit_to_delay(delay_bits, info->data, output);
+       ST_PINCONF_PACK_RT_DELAY(*config, delay);
+
+       if (value & RT_D_CFG_CLKNOTDATA_MASK)
+               ST_PINCONF_PACK_RT_CLKNOTDATA(*config);
+
+       if (value & RT_D_CFG_DOUBLE_EDGE_MASK)
+               ST_PINCONF_PACK_RT_DOUBLE_EDGE(*config);
+
+       if (value & RT_D_CFG_INVERTCLK_MASK)
+               ST_PINCONF_PACK_RT_INVERTCLK(*config);
+
+       if (value & RT_D_CFG_RETIME_MASK)
+               ST_PINCONF_PACK_RT(*config);
+
+       return 0;
+}
+
+/* GPIO related functions */
+
+static inline void __st_gpio_set(struct st_gpio_bank *bank,
+       unsigned offset, int value)
+{
+       if (value)
+               writel(BIT(offset), bank->base + REG_PIO_SET_POUT);
+       else
+               writel(BIT(offset), bank->base + REG_PIO_CLR_POUT);
+}
+
+static void st_gpio_direction(struct st_gpio_bank *bank,
+               unsigned int gpio, unsigned int direction)
+{
+       int offset = st_gpio_pin(gpio);
+       int i = 0;
+       /**
+        * There are three configuration registers (PIOn_PC0, PIOn_PC1
+        * and PIOn_PC2) for each port. These are used to configure the
+        * PIO port pins. Each pin can be configured as an input, output,
+        * bidirectional, or alternative function pin. Three bits, one bit
+        * from each of the three registers, configure the corresponding bit of
+        * the port. Valid bit settings is:
+        *
+        * PC2          PC1             PC0     Direction.
+        * 0            0               0       [Input Weak pull-up]
+        * 0            0 or 1          1       [Bidirection]
+        * 0            1               0       [Output]
+        * 1            0               0       [Input]
+        *
+        * PIOn_SET_PC and PIOn_CLR_PC registers are used to set and clear bits
+        * individually.
+        */
+       for (i = 0; i <= 2; i++) {
+               if (direction & BIT(i))
+                       writel(BIT(offset), bank->base + REG_PIO_SET_PC(i));
+               else
+                       writel(BIT(offset), bank->base + REG_PIO_CLR_PC(i));
+       }
+}
+
+static int st_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void st_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       pinctrl_free_gpio(chip->base + offset);
+}
+
+static int st_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+
+       return !!(readl(bank->base + REG_PIO_PIN) & BIT(offset));
+}
+
+static void st_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+       __st_gpio_set(bank, offset, value);
+}
+
+static int st_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       pinctrl_gpio_direction_input(chip->base + offset);
+
+       return 0;
+}
+
+static int st_gpio_direction_output(struct gpio_chip *chip,
+       unsigned offset, int value)
+{
+       struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
+
+       __st_gpio_set(bank, offset, value);
+       pinctrl_gpio_direction_output(chip->base + offset);
+
+       return 0;
+}
+
+static int st_gpio_xlate(struct gpio_chip *gc,
+                       const struct of_phandle_args *gpiospec, u32 *flags)
+{
+       if (WARN_ON(gc->of_gpio_n_cells < 1))
+               return -EINVAL;
+
+       if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
+               return -EINVAL;
+
+       if (gpiospec->args[0] > gc->ngpio)
+               return -EINVAL;
+
+       return gpiospec->args[0];
+}
+
+/* Pinctrl Groups */
+static int st_pctl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->ngroups;
+}
+
+static const char *st_pctl_get_group_name(struct pinctrl_dev *pctldev,
+                                      unsigned selector)
+{
+       struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->groups[selector].name;
+}
+
+static int st_pctl_get_group_pins(struct pinctrl_dev *pctldev,
+       unsigned selector, const unsigned **pins, unsigned *npins)
+{
+       struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       if (selector >= info->ngroups)
+               return -EINVAL;
+
+       *pins = info->groups[selector].pins;
+       *npins = info->groups[selector].npins;
+
+       return 0;
+}
+
+static const inline struct st_pctl_group *st_pctl_find_group_by_name(
+       const struct st_pinctrl *info, const char *name)
+{
+       int i;
+
+       for (i = 0; i < info->ngroups; i++) {
+               if (!strcmp(info->groups[i].name, name))
+                       return &info->groups[i];
+       }
+
+       return NULL;
+}
+
+static int st_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
+       struct device_node *np, struct pinctrl_map **map, unsigned *num_maps)
+{
+       struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const struct st_pctl_group *grp;
+       struct pinctrl_map *new_map;
+       struct device_node *parent;
+       int map_num, i;
+
+       grp = st_pctl_find_group_by_name(info, np->name);
+       if (!grp) {
+               dev_err(info->dev, "unable to find group for node %s\n",
+                       np->name);
+               return -EINVAL;
+       }
+
+       map_num = grp->npins + 1;
+       new_map = devm_kzalloc(pctldev->dev,
+                               sizeof(*new_map) * map_num, GFP_KERNEL);
+       if (!new_map)
+               return -ENOMEM;
+
+       parent = of_get_parent(np);
+       if (!parent) {
+               devm_kfree(pctldev->dev, new_map);
+               return -EINVAL;
+       }
+
+       *map = new_map;
+       *num_maps = map_num;
+       new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+       new_map[0].data.mux.function = parent->name;
+       new_map[0].data.mux.group = np->name;
+       of_node_put(parent);
+
+       /* create config map per pin */
+       new_map++;
+       for (i = 0; i < grp->npins; i++) {
+               new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
+               new_map[i].data.configs.group_or_pin =
+                               pin_get_name(pctldev, grp->pins[i]);
+               new_map[i].data.configs.configs = &grp->pin_conf[i].config;
+               new_map[i].data.configs.num_configs = 1;
+       }
+       dev_info(pctldev->dev, "maps: function %s group %s num %d\n",
+               (*map)->data.mux.function, grp->name, map_num);
+
+       return 0;
+}
+
+static void st_pctl_dt_free_map(struct pinctrl_dev *pctldev,
+                       struct pinctrl_map *map, unsigned num_maps)
+{
+}
+
+static struct pinctrl_ops st_pctlops = {
+       .get_groups_count       = st_pctl_get_groups_count,
+       .get_group_pins         = st_pctl_get_group_pins,
+       .get_group_name         = st_pctl_get_group_name,
+       .dt_node_to_map         = st_pctl_dt_node_to_map,
+       .dt_free_map            = st_pctl_dt_free_map,
+};
+
+/* Pinmux */
+static int st_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+       struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->nfunctions;
+}
+
+const char *st_pmx_get_fname(struct pinctrl_dev *pctldev,
+       unsigned selector)
+{
+       struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->functions[selector].name;
+}
+
+static int st_pmx_get_groups(struct pinctrl_dev *pctldev,
+       unsigned selector, const char * const **grps, unsigned * const ngrps)
+{
+       struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       *grps = info->functions[selector].groups;
+       *ngrps = info->functions[selector].ngroups;
+
+       return 0;
+}
+
+static struct st_pio_control *st_get_pio_control(
+                       struct pinctrl_dev *pctldev, int pin)
+{
+       struct pinctrl_gpio_range *range =
+                        pinctrl_find_gpio_range_from_pin(pctldev, pin);
+       struct st_gpio_bank *bank = gpio_range_to_bank(range);
+
+       return &bank->pc;
+}
+
+static int st_pmx_enable(struct pinctrl_dev *pctldev, unsigned fselector,
+               unsigned group)
+{
+       struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       struct st_pinconf *conf = info->groups[group].pin_conf;
+       struct st_pio_control *pc;
+       int i;
+
+       for (i = 0; i < info->groups[group].npins; i++) {
+               pc = st_get_pio_control(pctldev, conf[i].pin);
+               st_pctl_set_function(pc, conf[i].pin, conf[i].altfunc);
+       }
+
+       return 0;
+}
+
+static void st_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
+               unsigned group)
+{
+}
+
+static int st_pmx_set_gpio_direction(struct pinctrl_dev *pctldev,
+                       struct pinctrl_gpio_range *range, unsigned gpio,
+                       bool input)
+{
+       struct st_gpio_bank *bank = gpio_range_to_bank(range);
+       /*
+        * When a PIO bank is used in its primary function mode (altfunc = 0)
+        * Output Enable (OE), Open Drain(OD), and Pull Up (PU)
+        * for the primary PIO functions are driven by the related PIO block
+        */
+       st_pctl_set_function(&bank->pc, gpio, 0);
+       st_gpio_direction(bank, gpio, input ?
+               ST_GPIO_DIRECTION_IN : ST_GPIO_DIRECTION_OUT);
+
+       return 0;
+}
+
+static struct pinmux_ops st_pmxops = {
+       .get_functions_count    = st_pmx_get_funcs_count,
+       .get_function_name      = st_pmx_get_fname,
+       .get_function_groups    = st_pmx_get_groups,
+       .enable                 = st_pmx_enable,
+       .disable                = st_pmx_disable,
+       .gpio_set_direction     = st_pmx_set_gpio_direction,
+};
+
+/* Pinconf  */
+static void st_pinconf_get_retime(struct st_pinctrl *info,
+       struct st_pio_control *pc, int pin, unsigned long *config)
+{
+       if (info->data->rt_style == st_retime_style_packed)
+               st_pinconf_get_retime_packed(info, pc, pin, config);
+       else if (info->data->rt_style == st_retime_style_dedicated)
+               if ((BIT(pin) & pc->rt_pin_mask))
+                       st_pinconf_get_retime_dedicated(info, pc,
+                                       pin, config);
+}
+
+static void st_pinconf_set_retime(struct st_pinctrl *info,
+       struct st_pio_control *pc, int pin, unsigned long config)
+{
+       if (info->data->rt_style == st_retime_style_packed)
+               st_pinconf_set_retime_packed(info, pc, config, pin);
+       else if (info->data->rt_style == st_retime_style_dedicated)
+               if ((BIT(pin) & pc->rt_pin_mask))
+                       st_pinconf_set_retime_dedicated(info, pc,
+                                                       config, pin);
+}
+
+static int st_pinconf_set(struct pinctrl_dev *pctldev,
+                            unsigned pin_id, unsigned long config)
+{
+       int pin = st_gpio_pin(pin_id);
+       struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id);
+
+       st_pinconf_set_config(pc, pin, config);
+       st_pinconf_set_retime(info, pc, pin, config);
+
+       return 0;
+}
+
+static int st_pinconf_get(struct pinctrl_dev *pctldev,
+                            unsigned pin_id, unsigned long *config)
+{
+       int pin = st_gpio_pin(pin_id);
+       struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id);
+
+       *config = 0;
+       st_pinconf_get_direction(pc, pin, config);
+       st_pinconf_get_retime(info, pc, pin, config);
+
+       return 0;
+}
+
+static void st_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+                                  struct seq_file *s, unsigned pin_id)
+{
+       unsigned long config;
+       st_pinconf_get(pctldev, pin_id, &config);
+
+       seq_printf(s, "[OE:%ld,PU:%ld,OD:%ld]\n"
+               "\t\t[retime:%ld,invclk:%ld,clknotdat:%ld,"
+               "de:%ld,rt-clk:%ld,rt-delay:%ld]",
+               ST_PINCONF_UNPACK_OE(config),
+               ST_PINCONF_UNPACK_PU(config),
+               ST_PINCONF_UNPACK_OD(config),
+               ST_PINCONF_UNPACK_RT(config),
+               ST_PINCONF_UNPACK_RT_INVERTCLK(config),
+               ST_PINCONF_UNPACK_RT_CLKNOTDATA(config),
+               ST_PINCONF_UNPACK_RT_DOUBLE_EDGE(config),
+               ST_PINCONF_UNPACK_RT_CLK(config),
+               ST_PINCONF_UNPACK_RT_DELAY(config));
+}
+
+static struct pinconf_ops st_confops = {
+       .pin_config_get         = st_pinconf_get,
+       .pin_config_set         = st_pinconf_set,
+       .pin_config_dbg_show    = st_pinconf_dbg_show,
+};
+
+static void st_pctl_dt_child_count(struct st_pinctrl *info,
+                                    struct device_node *np)
+{
+       struct device_node *child;
+       for_each_child_of_node(np, child) {
+               if (of_property_read_bool(child, "gpio-controller")) {
+                       info->nbanks++;
+               } else {
+                       info->nfunctions++;
+                       info->ngroups += of_get_child_count(child);
+               }
+       }
+}
+
+static int st_pctl_dt_setup_retime_packed(struct st_pinctrl *info,
+       int bank, struct st_pio_control *pc)
+{
+       struct device *dev = info->dev;
+       struct regmap *rm = info->regmap;
+       const struct st_pctl_data *data = info->data;
+       /* 2 registers per bank */
+       int reg = (data->rt + bank * RT_P_CFGS_PER_BANK) * 4;
+       struct st_retime_packed *rt_p = &pc->rt.rt_p;
+       /* cfg0 */
+       struct reg_field clk1notclk0 = RT_P_CFG0_CLK1NOTCLK0_FIELD(reg);
+       struct reg_field delay_0 = RT_P_CFG0_DELAY_0_FIELD(reg);
+       struct reg_field delay_1 = RT_P_CFG0_DELAY_1_FIELD(reg);
+       /* cfg1 */
+       struct reg_field invertclk = RT_P_CFG1_INVERTCLK_FIELD(reg + 4);
+       struct reg_field retime = RT_P_CFG1_RETIME_FIELD(reg + 4);
+       struct reg_field clknotdata = RT_P_CFG1_CLKNOTDATA_FIELD(reg + 4);
+       struct reg_field double_edge = RT_P_CFG1_DOUBLE_EDGE_FIELD(reg + 4);
+
+       rt_p->clk1notclk0 = devm_regmap_field_alloc(dev, rm, clk1notclk0);
+       rt_p->delay_0   = devm_regmap_field_alloc(dev, rm, delay_0);
+       rt_p->delay_1 = devm_regmap_field_alloc(dev, rm, delay_1);
+       rt_p->invertclk = devm_regmap_field_alloc(dev, rm, invertclk);
+       rt_p->retime = devm_regmap_field_alloc(dev, rm, retime);
+       rt_p->clknotdata = devm_regmap_field_alloc(dev, rm, clknotdata);
+       rt_p->double_edge = devm_regmap_field_alloc(dev, rm, double_edge);
+
+       if (IS_ERR(rt_p->clk1notclk0) || IS_ERR(rt_p->delay_0) ||
+                IS_ERR(rt_p->delay_1) || IS_ERR(rt_p->invertclk) ||
+                IS_ERR(rt_p->retime) || IS_ERR(rt_p->clknotdata) ||
+                IS_ERR(rt_p->double_edge))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int st_pctl_dt_setup_retime_dedicated(struct st_pinctrl *info,
+       int bank, struct st_pio_control *pc)
+{
+       struct device *dev = info->dev;
+       struct regmap *rm = info->regmap;
+       const struct st_pctl_data *data = info->data;
+       /* 8 registers per bank */
+       int reg_offset = (data->rt + bank * RT_D_CFGS_PER_BANK) * 4;
+       struct st_retime_dedicated *rt_d = &pc->rt.rt_d;
+       unsigned int j;
+       u32 pin_mask = pc->rt_pin_mask;
+
+       for (j = 0; j < RT_D_CFGS_PER_BANK; j++) {
+               if (BIT(j) & pin_mask) {
+                       struct reg_field reg = REG_FIELD(reg_offset, 0, 31);
+                       rt_d->rt[j] = devm_regmap_field_alloc(dev, rm, reg);
+                       if (IS_ERR(rt_d->rt[j]))
+                               return -EINVAL;
+                       reg_offset += 4;
+               }
+       }
+       return 0;
+}
+
+static int st_pctl_dt_setup_retime(struct st_pinctrl *info,
+       int bank, struct st_pio_control *pc)
+{
+       const struct st_pctl_data *data = info->data;
+       if (data->rt_style  == st_retime_style_packed)
+               return st_pctl_dt_setup_retime_packed(info, bank, pc);
+       else if (data->rt_style == st_retime_style_dedicated)
+               return st_pctl_dt_setup_retime_dedicated(info, bank, pc);
+
+       return -EINVAL;
+}
+
+static int st_parse_syscfgs(struct st_pinctrl *info,
+               int bank, struct device_node *np)
+{
+       const struct st_pctl_data *data = info->data;
+       /**
+        * For a given shared register like OE/PU/OD, there are 8 bits per bank
+        * 0:7 belongs to bank0, 8:15 belongs to bank1 ...
+        * So each register is shared across 4 banks.
+        */
+       int lsb = (bank%4) * ST_GPIO_PINS_PER_BANK;
+       int msb = lsb + ST_GPIO_PINS_PER_BANK - 1;
+       struct reg_field alt_reg = REG_FIELD((data->alt + bank) * 4, 0, 31);
+       struct reg_field oe_reg = REG_FIELD((data->oe + bank/4) * 4, lsb, msb);
+       struct reg_field pu_reg = REG_FIELD((data->pu + bank/4) * 4, lsb, msb);
+       struct reg_field od_reg = REG_FIELD((data->od + bank/4) * 4, lsb, msb);
+       struct st_pio_control *pc = &info->banks[bank].pc;
+       struct device *dev = info->dev;
+       struct regmap *regmap  = info->regmap;
+
+       pc->alt = devm_regmap_field_alloc(dev, regmap, alt_reg);
+       pc->oe = devm_regmap_field_alloc(dev, regmap, oe_reg);
+       pc->pu = devm_regmap_field_alloc(dev, regmap, pu_reg);
+       pc->od = devm_regmap_field_alloc(dev, regmap, od_reg);
+
+       if (IS_ERR(pc->alt) || IS_ERR(pc->oe) ||
+                       IS_ERR(pc->pu) || IS_ERR(pc->od))
+               return -EINVAL;
+
+       /* retime avaiable for all pins by default */
+       pc->rt_pin_mask = 0xff;
+       of_property_read_u32(np, "st,retime-pin-mask", &pc->rt_pin_mask);
+       st_pctl_dt_setup_retime(info, bank, pc);
+
+       return 0;
+}
+
+/*
+ * Each pin is represented in of the below forms.
+ * <bank offset mux direction rt_type rt_delay rt_clk>
+ */
+static int st_pctl_dt_parse_groups(struct device_node *np,
+       struct st_pctl_group *grp, struct st_pinctrl *info, int idx)
+{
+       /* bank pad direction val altfunction */
+       const __be32 *list;
+       struct property *pp;
+       struct st_pinconf *conf;
+       phandle phandle;
+       struct device_node *pins;
+       u32 pin;
+       int i = 0, npins = 0, nr_props;
+
+       pins = of_get_child_by_name(np, "st,pins");
+       if (!pins)
+               return -ENODATA;
+
+       for_each_property_of_node(pins, pp) {
+               /* Skip those we do not want to proceed */
+               if (!strcmp(pp->name, "name"))
+                       continue;
+
+               if (pp  && (pp->length/sizeof(__be32)) >= OF_GPIO_ARGS_MIN) {
+                       npins++;
+               } else {
+                       pr_warn("Invalid st,pins in %s node\n", np->name);
+                       return -EINVAL;
+               }
+       }
+
+       grp->npins = npins;
+       grp->name = np->name;
+       grp->pins = devm_kzalloc(info->dev, npins * sizeof(u32), GFP_KERNEL);
+       grp->pin_conf = devm_kzalloc(info->dev,
+                                       npins * sizeof(*conf), GFP_KERNEL);
+
+       if (!grp->pins || !grp->pin_conf)
+               return -ENOMEM;
+
+       /* <bank offset mux direction rt_type rt_delay rt_clk> */
+       for_each_property_of_node(pins, pp) {
+               if (!strcmp(pp->name, "name"))
+                       continue;
+               nr_props = pp->length/sizeof(u32);
+               list = pp->value;
+               conf = &grp->pin_conf[i];
+
+               /* bank & offset */
+               phandle = be32_to_cpup(list++);
+               pin = be32_to_cpup(list++);
+               conf->pin = of_get_named_gpio(pins, pp->name, 0);
+               conf->name = pp->name;
+               grp->pins[i] = conf->pin;
+               /* mux */
+               conf->altfunc = be32_to_cpup(list++);
+               conf->config = 0;
+               /* direction */
+               conf->config |= be32_to_cpup(list++);
+               /* rt_type rt_delay rt_clk */
+               if (nr_props >= OF_GPIO_ARGS_MIN + OF_RT_ARGS_MIN) {
+                       /* rt_type */
+                       conf->config |= be32_to_cpup(list++);
+                       /* rt_delay */
+                       conf->config |= be32_to_cpup(list++);
+                       /* rt_clk */
+                       if (nr_props > OF_GPIO_ARGS_MIN + OF_RT_ARGS_MIN)
+                               conf->config |= be32_to_cpup(list++);
+               }
+               i++;
+       }
+       of_node_put(pins);
+
+       return 0;
+}
+
+static int st_pctl_parse_functions(struct device_node *np,
+                       struct st_pinctrl *info, u32 index, int *grp_index)
+{
+       struct device_node *child;
+       struct st_pmx_func *func;
+       struct st_pctl_group *grp;
+       int ret, i;
+
+       func = &info->functions[index];
+       func->name = np->name;
+       func->ngroups = of_get_child_count(np);
+       if (func->ngroups <= 0) {
+               dev_err(info->dev, "No groups defined\n");
+               return -EINVAL;
+       }
+       func->groups = devm_kzalloc(info->dev,
+                       func->ngroups * sizeof(char *), GFP_KERNEL);
+       if (!func->groups)
+               return -ENOMEM;
+
+       i = 0;
+       for_each_child_of_node(np, child) {
+               func->groups[i] = child->name;
+               grp = &info->groups[*grp_index];
+               *grp_index += 1;
+               ret = st_pctl_dt_parse_groups(child, grp, info, i++);
+               if (ret)
+                       return ret;
+       }
+       dev_info(info->dev, "Function[%d\t name:%s,\tgroups:%d]\n",
+                               index, func->name, func->ngroups);
+
+       return 0;
+}
+
+static struct gpio_chip st_gpio_template = {
+       .request                = st_gpio_request,
+       .free                   = st_gpio_free,
+       .get                    = st_gpio_get,
+       .set                    = st_gpio_set,
+       .direction_input        = st_gpio_direction_input,
+       .direction_output       = st_gpio_direction_output,
+       .ngpio                  = ST_GPIO_PINS_PER_BANK,
+       .of_gpio_n_cells        = 1,
+       .of_xlate               = st_gpio_xlate,
+};
+
+static int st_gpiolib_register_bank(struct st_pinctrl *info,
+       int bank_nr, struct device_node *np)
+{
+       struct st_gpio_bank *bank = &info->banks[bank_nr];
+       struct pinctrl_gpio_range *range = &bank->range;
+       struct device *dev = info->dev;
+       int bank_num = of_alias_get_id(np, "gpio");
+       struct resource res;
+       int err;
+
+       if (of_address_to_resource(np, 0, &res))
+               return -ENODEV;
+
+       bank->base = devm_request_and_ioremap(dev, &res);
+       if (!bank->base) {
+               dev_err(dev, "Can't get IO memory mapping!\n");
+               return -ENODEV;
+       }
+
+       bank->gpio_chip = st_gpio_template;
+       bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK;
+       bank->gpio_chip.ngpio = ST_GPIO_PINS_PER_BANK;
+       bank->gpio_chip.of_node = np;
+
+       of_property_read_string(np, "st,bank-name", &range->name);
+       bank->gpio_chip.label = range->name;
+
+       range->id = bank_num;
+       range->pin_base = range->base = range->id * ST_GPIO_PINS_PER_BANK;
+       range->npins = bank->gpio_chip.ngpio;
+       range->gc = &bank->gpio_chip;
+       err  = gpiochip_add(&bank->gpio_chip);
+       if (err) {
+               dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_num);
+               return err;
+       }
+       dev_info(dev, "%s bank added.\n", range->name);
+
+       return 0;
+}
+
+static struct of_device_id st_pctl_of_match[] = {
+       { .compatible = "st,stih415-sbc-pinctrl", .data = &stih415_sbc_data },
+       { .compatible = "st,stih415-rear-pinctrl", .data = &stih415_rear_data },
+       { .compatible = "st,stih415-left-pinctrl", .data = &stih415_left_data },
+       { .compatible = "st,stih415-right-pinctrl",
+               .data = &stih415_right_data },
+       { .compatible = "st,stih415-front-pinctrl",
+               .data = &stih415_front_data },
+       { .compatible = "st,stih416-sbc-pinctrl", .data = &stih416_data},
+       { .compatible = "st,stih416-front-pinctrl", .data = &stih416_data},
+       { .compatible = "st,stih416-rear-pinctrl", .data = &stih416_data},
+       { .compatible = "st,stih416-fvdp-fe-pinctrl", .data = &stih416_data},
+       { .compatible = "st,stih416-fvdp-lite-pinctrl", .data = &stih416_data},
+       { /* sentinel */ }
+};
+
+static int st_pctl_probe_dt(struct platform_device *pdev,
+       struct pinctrl_desc *pctl_desc, struct st_pinctrl *info)
+{
+       int ret = 0;
+       int i = 0, j = 0, k = 0, bank;
+       struct pinctrl_pin_desc *pdesc;
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *child;
+       int grp_index = 0;
+
+       st_pctl_dt_child_count(info, np);
+       if (!info->nbanks) {
+               dev_err(&pdev->dev, "you need atleast one gpio bank\n");
+               return -EINVAL;
+       }
+
+       dev_info(&pdev->dev, "nbanks = %d\n", info->nbanks);
+       dev_info(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
+       dev_info(&pdev->dev, "ngroups = %d\n", info->ngroups);
+
+       info->functions = devm_kzalloc(&pdev->dev,
+               info->nfunctions * sizeof(*info->functions), GFP_KERNEL);
+
+       info->groups = devm_kzalloc(&pdev->dev,
+                       info->ngroups * sizeof(*info->groups) , GFP_KERNEL);
+
+       info->banks = devm_kzalloc(&pdev->dev,
+                       info->nbanks * sizeof(*info->banks), GFP_KERNEL);
+
+       if (!info->functions || !info->groups || !info->banks)
+               return -ENOMEM;
+
+       info->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+       if (IS_ERR(info->regmap)) {
+               dev_err(info->dev, "No syscfg phandle specified\n");
+               return PTR_ERR(info->regmap);
+       }
+       info->data = of_match_node(st_pctl_of_match, np)->data;
+
+       pctl_desc->npins = info->nbanks * ST_GPIO_PINS_PER_BANK;
+       pdesc = devm_kzalloc(&pdev->dev,
+                       sizeof(*pdesc) * pctl_desc->npins, GFP_KERNEL);
+       if (!pdesc)
+               return -ENOMEM;
+
+       pctl_desc->pins = pdesc;
+
+       bank = 0;
+       for_each_child_of_node(np, child) {
+               if (of_property_read_bool(child, "gpio-controller")) {
+                       const char *bank_name = NULL;
+                       ret = st_gpiolib_register_bank(info, bank, child);
+                       if (ret)
+                               return ret;
+
+                       k = info->banks[bank].range.pin_base;
+                       bank_name = info->banks[bank].range.name;
+                       for (j = 0; j < ST_GPIO_PINS_PER_BANK; j++, k++) {
+                               pdesc->number = k;
+                               pdesc->name = kasprintf(GFP_KERNEL, "%s[%d]",
+                                                       bank_name, j);
+                               pdesc++;
+                       }
+                       st_parse_syscfgs(info, bank, child);
+                       bank++;
+               } else {
+                       ret = st_pctl_parse_functions(child, info,
+                                                       i++, &grp_index);
+                       if (ret) {
+                               dev_err(&pdev->dev, "No functions found.\n");
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int st_pctl_probe(struct platform_device *pdev)
+{
+       struct st_pinctrl *info;
+       struct pinctrl_desc *pctl_desc;
+       int ret, i;
+
+       if (!pdev->dev.of_node) {
+               dev_err(&pdev->dev, "device node not found.\n");
+               return -EINVAL;
+       }
+
+       pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
+       if (!pctl_desc)
+               return -ENOMEM;
+
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->dev = &pdev->dev;
+       platform_set_drvdata(pdev, info);
+       ret = st_pctl_probe_dt(pdev, pctl_desc, info);
+       if (ret)
+               return ret;
+
+       pctl_desc->owner        = THIS_MODULE,
+       pctl_desc->pctlops      = &st_pctlops,
+       pctl_desc->pmxops       = &st_pmxops,
+       pctl_desc->confops      = &st_confops,
+       pctl_desc->name         = dev_name(&pdev->dev);
+
+       info->pctl = pinctrl_register(pctl_desc, &pdev->dev, info);
+       if (!info->pctl) {
+               dev_err(&pdev->dev, "Failed pinctrl registration\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < info->nbanks; i++)
+               pinctrl_add_gpio_range(info->pctl, &info->banks[i].range);
+
+       return 0;
+}
+
+static struct platform_driver st_pctl_driver = {
+       .driver = {
+               .name = "st-pinctrl",
+               .owner = THIS_MODULE,
+               .of_match_table = st_pctl_of_match,
+       },
+       .probe = st_pctl_probe,
+};
+
+static int __init st_pctl_init(void)
+{
+       return platform_driver_register(&st_pctl_driver);
+}
+arch_initcall(st_pctl_init);
diff --git a/drivers/pinctrl/pinctrl-sunxi-pins.h b/drivers/pinctrl/pinctrl-sunxi-pins.h
new file mode 100644 (file)
index 0000000..2eeae0c
--- /dev/null
@@ -0,0 +1,2023 @@
+/*
+ * Allwinner A1X SoCs pinctrl driver.
+ *
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef __PINCTRL_SUNXI_PINS_H
+#define __PINCTRL_SUNXI_PINS_H
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun4i_a10_pins[] = {
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD3 */
+                 SUNXI_FUNCTION(0x3, "spi1"),          /* CS0 */
+                 SUNXI_FUNCTION(0x4, "uart2")),        /* RTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD2 */
+                 SUNXI_FUNCTION(0x3, "spi1"),          /* CLK */
+                 SUNXI_FUNCTION(0x4, "uart2")),        /* CTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD1 */
+                 SUNXI_FUNCTION(0x3, "spi1"),          /* MOSI */
+                 SUNXI_FUNCTION(0x4, "uart2")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD0 */
+                 SUNXI_FUNCTION(0x3, "spi1"),          /* MISO */
+                 SUNXI_FUNCTION(0x4, "uart2")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD3 */
+                 SUNXI_FUNCTION(0x3, "spi1")),         /* CS1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD2 */
+                 SUNXI_FUNCTION(0x3, "spi3")),         /* CS0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD1 */
+                 SUNXI_FUNCTION(0x3, "spi3")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD0 */
+                 SUNXI_FUNCTION(0x3, "spi3")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXCK */
+                 SUNXI_FUNCTION(0x3, "spi3")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXERR */
+                 SUNXI_FUNCTION(0x3, "spi3")),         /* CS1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXDV */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* EMDC */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* EMDIO */
+                 SUNXI_FUNCTION(0x3, "uart6"),         /* TX */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* RTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXEN */
+                 SUNXI_FUNCTION(0x3, "uart6"),         /* RX */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* CTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXCK */
+                 SUNXI_FUNCTION(0x3, "uart7"),         /* TX */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* DTR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ECRS */
+                 SUNXI_FUNCTION(0x3, "uart7"),         /* RX */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* DSR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ECOL */
+                 SUNXI_FUNCTION(0x3, "can"),           /* TX */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* DCD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXERR */
+                 SUNXI_FUNCTION(0x3, "can"),           /* RX */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* RING */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "pwm")),          /* PWM0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ir0")),          /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ir0")),          /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* MCLK */
+                 SUNXI_FUNCTION(0x3, "ac97")),         /* MCLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* BCLK */
+                 SUNXI_FUNCTION(0x3, "ac97")),         /* BCLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* LRCK */
+                 SUNXI_FUNCTION(0x3, "ac97")),         /* SYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* DO0 */
+                 SUNXI_FUNCTION(0x3, "ac97")),         /* DO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s")),          /* DO1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s")),          /* DO2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s")),          /* DO3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* DI */
+                 SUNXI_FUNCTION(0x3, "ac97")),         /* DI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2")),         /* CS1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS0 */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* MS0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* CK0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* MOSI */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* DO0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* MISO */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* DI0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB21,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB22,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart0"),         /* TX */
+                 SUNXI_FUNCTION(0x3, "ir1")),          /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB23,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart0"),         /* RX */
+                 SUNXI_FUNCTION(0x3, "ir1")),          /* RX */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NALE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCLE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NRE# */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB1 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ1 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ2 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ3 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NDQ4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NDQ5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NDQ6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NDQ7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NWP */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE4 */
+                 SUNXI_FUNCTION(0x3, "spi2")),         /* CS0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC20,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE5 */
+                 SUNXI_FUNCTION(0x3, "spi2")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC21,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE6 */
+                 SUNXI_FUNCTION(0x3, "spi2")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC22,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE7 */
+                 SUNXI_FUNCTION(0x3, "spi2")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC23,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* CS0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC24,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NDQS */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D0 */
+                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VP0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D1 */
+                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VN0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D2 */
+                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VP1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D3 */
+                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VN1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D4 */
+                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VP2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D5 */
+                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VN2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D6 */
+                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VPC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D7 */
+                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D8 */
+                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VP3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D9 */
+                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VM3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D10 */
+                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VP0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D11 */
+                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VN0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D12 */
+                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VP1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D13 */
+                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VN1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D14 */
+                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VP2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D15 */
+                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VN2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D16 */
+                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VPC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D17 */
+                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D18 */
+                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VP3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D19 */
+                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VN3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D20 */
+                 SUNXI_FUNCTION(0x3, "csi1")),         /* MCLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D21 */
+                 SUNXI_FUNCTION(0x3, "sim")),          /* VPPEN */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D22 */
+                 SUNXI_FUNCTION(0x3, "sim")),          /* VPPPP */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D23 */
+                 SUNXI_FUNCTION(0x3, "sim")),          /* DET */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "sim")),          /* VCCEN */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* DE */
+                 SUNXI_FUNCTION(0x3, "sim")),          /* RST */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* HSYNC */
+                 SUNXI_FUNCTION(0x3, "sim")),          /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* VSYNC */
+                 SUNXI_FUNCTION(0x3, "sim")),          /* SDA */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* CLK */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* PCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* ERR */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* CK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* SYNC */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* HSYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* DVLD */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* VSYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D0 */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D1 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D1 */
+                 SUNXI_FUNCTION(0x4, "sim")),          /* VPPEN */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D2 */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D3 */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D4 */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D5 */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D6 */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D7 */
+                 SUNXI_FUNCTION(0x3, "csi0")),         /* D7 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D1 */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* MSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D0 */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* DI1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CLK */
+                 SUNXI_FUNCTION(0x4, "uart0")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CMD */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* DO1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D3 */
+                 SUNXI_FUNCTION(0x4, "uart0")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D2 */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* CK1 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* CLK */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* PCK */
+                 SUNXI_FUNCTION(0x4, "mmc1")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* ERR */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* CK */
+                 SUNXI_FUNCTION(0x4, "mmc1")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* SYNC */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* HSYNC */
+                 SUNXI_FUNCTION(0x4, "mmc1")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* DVLD */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* VSYNC */
+                 SUNXI_FUNCTION(0x4, "mmc1")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* D0 */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* D0 */
+                 SUNXI_FUNCTION(0x4, "mmc1"),          /* D2 */
+                 SUNXI_FUNCTION(0x5, "csi0")),         /* D8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* D1 */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* D1 */
+                 SUNXI_FUNCTION(0x4, "mmc1"),          /* D3 */
+                 SUNXI_FUNCTION(0x5, "csi0")),         /* D9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* D2 */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* D2 */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* TX */
+                 SUNXI_FUNCTION(0x5, "csi0")),         /* D10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* D3 */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* D3 */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* RX */
+                 SUNXI_FUNCTION(0x5, "csi0")),         /* D11 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* D4 */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* D4 */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* RTS */
+                 SUNXI_FUNCTION(0x5, "csi0")),         /* D12 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* D5 */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* D5 */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* CTS */
+                 SUNXI_FUNCTION(0x5, "csi0")),         /* D13 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* D6 */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* D6 */
+                 SUNXI_FUNCTION(0x4, "uart4"),         /* TX */
+                 SUNXI_FUNCTION(0x5, "csi0")),         /* D14 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts1"),           /* D7 */
+                 SUNXI_FUNCTION(0x3, "csi1"),          /* D7 */
+                 SUNXI_FUNCTION(0x4, "uart4"),         /* RX */
+                 SUNXI_FUNCTION(0x5, "csi0")),         /* D15 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D0 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAA0 */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 0),           /* EINT0 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D1 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAA1 */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 1),           /* EINT1 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D2 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAA2 */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 2),           /* EINT2 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D3 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAIRQ */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 3),           /* EINT3 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D4 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD0 */
+                 SUNXI_FUNCTION(0x4, "uart4"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 4),           /* EINT4 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D5 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD1 */
+                 SUNXI_FUNCTION(0x4, "uart4"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 5),           /* EINT5 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D6 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD2 */
+                 SUNXI_FUNCTION(0x4, "uart5"),         /* TX */
+                 SUNXI_FUNCTION(0x5, "ms"),            /* BS */
+                 SUNXI_FUNCTION_IRQ(0x6, 6),           /* EINT6 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D7 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD3 */
+                 SUNXI_FUNCTION(0x4, "uart5"),         /* RX */
+                 SUNXI_FUNCTION(0x5, "ms"),            /* CLK */
+                 SUNXI_FUNCTION_IRQ(0x6, 7),           /* EINT7 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D8 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD4 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* IN0 */
+                 SUNXI_FUNCTION(0x5, "ms"),            /* D0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 8),           /* EINT8 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D9 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD5 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* IN1 */
+                 SUNXI_FUNCTION(0x5, "ms"),            /* D1 */
+                 SUNXI_FUNCTION_IRQ(0x6, 9),           /* EINT9 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D10 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD6 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* IN2 */
+                 SUNXI_FUNCTION(0x5, "ms"),            /* D2 */
+                 SUNXI_FUNCTION_IRQ(0x6, 10),          /* EINT10 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D11 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD7 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* IN3 */
+                 SUNXI_FUNCTION(0x5, "ms"),            /* D3 */
+                 SUNXI_FUNCTION_IRQ(0x6, 11),          /* EINT11 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D11 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D12 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD8 */
+                 SUNXI_FUNCTION(0x4, "ps2"),           /* SCK1 */
+                 SUNXI_FUNCTION_IRQ(0x6, 12),          /* EINT12 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D12 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D13 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD9 */
+                 SUNXI_FUNCTION(0x4, "ps2"),           /* SDA1 */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* RST */
+                 SUNXI_FUNCTION_IRQ(0x6, 13),          /* EINT13 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D13 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D14 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD10 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* IN4 */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* VPPEN */
+                 SUNXI_FUNCTION_IRQ(0x6, 14),          /* EINT14 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D14 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D15 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD11 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* IN5 */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* VPPPP */
+                 SUNXI_FUNCTION_IRQ(0x6, 15),          /* EINT15 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D15 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D16 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD12 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* IN6 */
+                 SUNXI_FUNCTION_IRQ(0x6, 16),          /* EINT16 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D16 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D17 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD13 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* IN7 */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* VCCEN */
+               SUNXI_FUNCTION_IRQ(0x6, 17),            /* EINT17 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D17 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D18 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD14 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* OUT0 */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* SCK */
+               SUNXI_FUNCTION_IRQ(0x6, 18),            /* EINT18 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D18 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D19 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAD15 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* OUT1 */
+                 SUNXI_FUNCTION(0x5, "sim"),           /* SDA */
+               SUNXI_FUNCTION_IRQ(0x6, 19),            /* EINT19 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D19 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D20 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAOE */
+                 SUNXI_FUNCTION(0x4, "can"),           /* TX */
+               SUNXI_FUNCTION_IRQ(0x6, 20),            /* EINT20 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D20 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D21 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATADREQ */
+                 SUNXI_FUNCTION(0x4, "can"),           /* RX */
+               SUNXI_FUNCTION_IRQ(0x6, 21),            /* EINT21 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D21 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D22 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATADACK */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* OUT2 */
+                 SUNXI_FUNCTION(0x5, "mmc1"),          /* CMD */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D22 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH23,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* D23 */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATACS0 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* OUT3 */
+                 SUNXI_FUNCTION(0x5, "mmc1"),          /* CLK */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* D23 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH24,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATACS1 */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* OUT4 */
+                 SUNXI_FUNCTION(0x5, "mmc1"),          /* D0 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* PCLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH25,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* DE */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAIORDY */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* OUT5 */
+                 SUNXI_FUNCTION(0x5, "mmc1"),          /* D1 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* FIELD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH26,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* HSYNC */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAIOR */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* OUT6 */
+                 SUNXI_FUNCTION(0x5, "mmc1"),          /* D2 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* HSYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH27,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd1"),          /* VSYNC */
+                 SUNXI_FUNCTION(0x3, "pata"),          /* ATAIOW */
+                 SUNXI_FUNCTION(0x4, "keypad"),        /* OUT7 */
+                 SUNXI_FUNCTION(0x5, "mmc1"),          /* D3 */
+                 SUNXI_FUNCTION(0x7, "csi1")),         /* VSYNC */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out")),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out")),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out")),
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "pwm")),          /* PWM1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc3")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc3")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc3")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc3")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc3")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc3")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi0"),          /* CS0 */
+                 SUNXI_FUNCTION(0x3, "uart5"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 22)),         /* EINT22 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi0"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "uart5"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 23)),         /* EINT23 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi0"),          /* MOSI */
+                 SUNXI_FUNCTION(0x3, "uart6"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 24)),         /* EINT24 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi0"),          /* MISO */
+                 SUNXI_FUNCTION(0x3, "uart6"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 25)),         /* EINT25 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi0"),          /* CS1 */
+                 SUNXI_FUNCTION(0x3, "ps2"),           /* SCK1 */
+                 SUNXI_FUNCTION(0x4, "timer4"),        /* TCLKIN0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 26)),         /* EINT26 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS1 */
+                 SUNXI_FUNCTION(0x3, "ps2"),           /* SDA1 */
+                 SUNXI_FUNCTION(0x4, "timer5"),        /* TCLKIN1 */
+                 SUNXI_FUNCTION_IRQ(0x6, 27)),         /* EINT27 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS0 */
+                 SUNXI_FUNCTION(0x3, "uart2"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 28)),         /* EINT28 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "uart2"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 29)),         /* EINT29 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI18,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* MOSI */
+                 SUNXI_FUNCTION(0x3, "uart2"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 30)),         /* EINT30 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI19,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* MISO */
+                 SUNXI_FUNCTION(0x3, "uart2"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 31)),         /* EINT31 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI20,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ps2"),           /* SCK0 */
+                 SUNXI_FUNCTION(0x3, "uart7"),         /* TX */
+                 SUNXI_FUNCTION(0x4, "hdmi")),         /* HSCL */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI21,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ps2"),           /* SDA0 */
+                 SUNXI_FUNCTION(0x3, "uart7"),         /* RX */
+                 SUNXI_FUNCTION(0x4, "hdmi")),         /* HSDA */
+};
+
+static const struct sunxi_desc_pin sun5i_a10s_pins[] = {
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD3 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* CLK */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD2 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* ERR */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD1 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* SYNC */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD0 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* DLVD */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD3 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D0 */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD2 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D1 */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD1 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D2 */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD0 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D3 */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXCK */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D4 */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* DTR */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXERR */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D5 */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* DSR */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXDV */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D6 */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* DCD */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* EMDC */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D7 */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* RING */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* EMDIO */
+                 SUNXI_FUNCTION(0x3, "uart1"),         /* TX */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXEN */
+                 SUNXI_FUNCTION(0x3, "uart1"),         /* RX */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXCK */
+                 SUNXI_FUNCTION(0x3, "uart1"),         /* CTS */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* TX */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ECRS */
+                 SUNXI_FUNCTION(0x3, "uart1"),         /* RTS */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* RX */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ECOL */
+                 SUNXI_FUNCTION(0x3, "uart2")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXERR */
+                 SUNXI_FUNCTION(0x3, "uart2"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 31)),         /* EINT31 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "pwm"),           /* PWM0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 16)),         /* EINT16 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ir0"),           /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 17)),         /* EINT17 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ir0"),           /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 18)),         /* EINT18 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* MCLK */
+                 SUNXI_FUNCTION_IRQ(0x6, 19)),         /* EINT19 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* BCLK */
+                 SUNXI_FUNCTION_IRQ(0x6, 20)),         /* EINT20 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* LRCK */
+                 SUNXI_FUNCTION_IRQ(0x6, 21)),         /* EINT21 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* DO */
+                 SUNXI_FUNCTION_IRQ(0x6, 22)),         /* EINT22 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* DI */
+                 SUNXI_FUNCTION_IRQ(0x6, 23)),         /* EINT23 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS1 */
+                 SUNXI_FUNCTION_IRQ(0x6, 24)),         /* EINT24 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS0 */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* MS0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 25)),         /* EINT25 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* CK0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 26)),         /* EINT26 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* MOSI */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* DO0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 27)),         /* EINT27 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* MISO */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* DI0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 28)),         /* EINT28 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart0"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 29)),         /* EINT29 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart0"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 30)),         /* EINT30 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NALE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCLE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE1 */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* CS0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NRE */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB1 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ1 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ2 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ3 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ4 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ5 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ6 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ7 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWP */
+                 SUNXI_FUNCTION(0x4, "uart3")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE2 */
+                 SUNXI_FUNCTION(0x4, "uart3")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE3 */
+                 SUNXI_FUNCTION(0x3, "uart2"),         /* TX */
+                 SUNXI_FUNCTION(0x4, "uart3")),        /* CTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE4 */
+                 SUNXI_FUNCTION(0x3, "uart2"),         /* RX */
+                 SUNXI_FUNCTION(0x4, "uart3")),        /* RTS */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D2 */
+                 SUNXI_FUNCTION(0x3, "uart2")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D3 */
+                 SUNXI_FUNCTION(0x3, "uart2")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D4 */
+                 SUNXI_FUNCTION(0x3, "uart2")),        /* CTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D5 */
+                 SUNXI_FUNCTION(0x3, "uart2")),        /* RTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D6 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ECRS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D7 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ECOL */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D10 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D11 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D12 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D13 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D14 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D15 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXERR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D16 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D17 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D18 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXDV */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D19 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D20 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D21 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D22 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D23 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXEN */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* DE */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXERR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* HSYNC */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* EMDC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* VSYNC */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* EMDIO */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* CLK */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* PCK */
+                 SUNXI_FUNCTION(0x4, "spi2"),          /* CS0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 14)),         /* EINT14 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* ERR */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* CK */
+                 SUNXI_FUNCTION(0x4, "spi2"),          /* CLK */
+                 SUNXI_FUNCTION_IRQ(0x6, 15)),         /* EINT15 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* SYNC */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* HSYNC */
+                 SUNXI_FUNCTION(0x4, "spi2")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* DVLD */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* VSYNC */
+                 SUNXI_FUNCTION(0x4, "spi2")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D0 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D0 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D1 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D1 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D2 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D2 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D3 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D3 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D4 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D4 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D5 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D5 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D6 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D6 */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D7 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D7 */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* RX */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D1 */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* MS1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D0 */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* DI1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CLK */
+                 SUNXI_FUNCTION(0x4, "uart0")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CMD */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* DO1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D3 */
+                 SUNXI_FUNCTION(0x4, "uart0")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D2 */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* CK1 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "gps"),           /* CLK */
+                 SUNXI_FUNCTION_IRQ(0x6, 0)),          /* EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "gps"),           /* SIGN */
+                 SUNXI_FUNCTION_IRQ(0x6, 1)),          /* EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "gps"),           /* MAG */
+                 SUNXI_FUNCTION_IRQ(0x6, 2)),          /* EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CMD */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 3)),          /* EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CLK */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 4)),          /* EINT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* DO */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 5)),          /* EINT5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D1 */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* RTS */
+                 SUNXI_FUNCTION(0x5, "uart2"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 6)),          /* EINT6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D2 */
+                 SUNXI_FUNCTION(0x5, "uart2"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 7)),          /* EINT7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D3 */
+                 SUNXI_FUNCTION(0x5, "uart2"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 8)),          /* EINT8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS0 */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 9)),          /* EINT9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 10)),         /* EINT10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* MOSI */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 11)),         /* EINT11 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* MISO */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 12)),         /* EINT12 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS1 */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* PWM1 */
+                 SUNXI_FUNCTION(0x5, "uart2"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 13)),         /* EINT13 */
+};
+
+static const struct sunxi_desc_pin sun5i_a13_pins[] = {
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "pwm"),
+                 SUNXI_FUNCTION_IRQ(0x6, 16)),         /* EINT16 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ir0"),           /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 17)),         /* EINT17 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ir0"),           /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 18)),         /* EINT18 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS1 */
+                 SUNXI_FUNCTION_IRQ(0x6, 24)),         /* EINT24 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SDA */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NALE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCLE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE1 */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* CS0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NRE */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB1 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ1 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ2 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ3 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ4 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ5 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ6 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ7 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQS */
+                 SUNXI_FUNCTION(0x4, "uart3")),        /* RTS */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D7 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D11 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D12 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D13 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D14 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D15 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D18 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D19 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D20 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D21 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D22 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D23 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* DE */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* HSYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* VSYNC */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* PCLK */
+                 SUNXI_FUNCTION(0x4, "spi2"),          /* CS0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 14)),         /* EINT14 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* MCLK */
+                 SUNXI_FUNCTION(0x4, "spi2"),          /* CLK */
+                 SUNXI_FUNCTION_IRQ(0x6, 15)),         /* EINT15 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* HSYNC */
+                 SUNXI_FUNCTION(0x4, "spi2")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* VSYNC */
+                 SUNXI_FUNCTION(0x4, "spi2")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D0 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D1 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D2 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D3 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D4 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D5 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D6 */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D7 */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* RX */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x4, "mmc0")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x4, "mmc0")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x4, "mmc0")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x4, "mmc0")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x4, "mmc0")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x4, "mmc0")),         /* D2 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION_IRQ(0x6, 0)),          /* EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION_IRQ(0x6, 1)),          /* EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION_IRQ(0x6, 2)),          /* EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CMD */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 3)),          /* EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CLK */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 4)),          /* EINT4 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS0 */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 9)),          /* EINT9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 10)),         /* EINT10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* MOSI */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 11)),         /* EINT11 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* MISO */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 12)),         /* EINT12 */
+};
+
+static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
+       .pins = sun4i_a10_pins,
+       .npins = ARRAY_SIZE(sun4i_a10_pins),
+};
+
+static const struct sunxi_pinctrl_desc sun5i_a10s_pinctrl_data = {
+       .pins = sun5i_a10s_pins,
+       .npins = ARRAY_SIZE(sun5i_a10s_pins),
+};
+
+static const struct sunxi_pinctrl_desc sun5i_a13_pinctrl_data = {
+       .pins = sun5i_a13_pins,
+       .npins = ARRAY_SIZE(sun5i_a13_pins),
+};
+
+#endif /* __PINCTRL_SUNXI_PINS_H */
index b7d8c890514c7429c7533ce134f09cbbd440d333..c47fd1e5450ba6f26ba8e70f2ad207efc1959a82 100644 (file)
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
+#include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/machine.h>
 #include <linux/pinctrl/pinctrl.h>
 
 #include "core.h"
 #include "pinctrl-sunxi.h"
-
-static const struct sunxi_desc_pin sun4i_a10_pins[] = {
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ERXD3 */
-               SUNXI_FUNCTION(0x3, "spi1"),            /* CS0 */
-               SUNXI_FUNCTION(0x4, "uart2")),          /* RTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ERXD2 */
-               SUNXI_FUNCTION(0x3, "spi1"),            /* CLK */
-               SUNXI_FUNCTION(0x4, "uart2")),          /* CTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ERXD1 */
-               SUNXI_FUNCTION(0x3, "spi1"),            /* MOSI */
-               SUNXI_FUNCTION(0x4, "uart2")),          /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ERXD0 */
-               SUNXI_FUNCTION(0x3, "spi1"),            /* MISO */
-               SUNXI_FUNCTION(0x4, "uart2")),          /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ETXD3 */
-               SUNXI_FUNCTION(0x3, "spi1")),           /* CS1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ETXD2 */
-               SUNXI_FUNCTION(0x3, "spi3")),           /* CS0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ETXD1 */
-               SUNXI_FUNCTION(0x3, "spi3")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ETXD0 */
-               SUNXI_FUNCTION(0x3, "spi3")),           /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ERXCK */
-               SUNXI_FUNCTION(0x3, "spi3")),           /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ERXERR */
-               SUNXI_FUNCTION(0x3, "spi3")),           /* CS1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ERXDV */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* EMDC */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* EMDIO */
-               SUNXI_FUNCTION(0x3, "uart6"),           /* TX */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* RTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ETXEN */
-               SUNXI_FUNCTION(0x3, "uart6"),           /* RX */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* CTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ETXCK */
-               SUNXI_FUNCTION(0x3, "uart7"),           /* TX */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* DTR */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ECRS */
-               SUNXI_FUNCTION(0x3, "uart7"),           /* RX */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* DSR */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ECOL */
-               SUNXI_FUNCTION(0x3, "can"),             /* TX */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* DCD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "emac"),            /* ETXERR */
-               SUNXI_FUNCTION(0x3, "can"),             /* RX */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* RING */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c0")),           /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c0")),           /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "pwm")),            /* PWM0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ir0")),            /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ir0")),            /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2s"),             /* MCLK */
-               SUNXI_FUNCTION(0x3, "ac97")),           /* MCLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2s"),             /* BCLK */
-               SUNXI_FUNCTION(0x3, "ac97")),           /* BCLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2s"),             /* LRCK */
-               SUNXI_FUNCTION(0x3, "ac97")),           /* SYNC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2s"),             /* DO0 */
-               SUNXI_FUNCTION(0x3, "ac97")),           /* DO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2s")),            /* DO1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2s")),            /* DO2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2s")),            /* DO3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2s"),             /* DI */
-               SUNXI_FUNCTION(0x3, "ac97")),           /* DI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi2")),           /* CS1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi2"),            /* CS0 */
-               SUNXI_FUNCTION(0x3, "jtag")),           /* MS0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi2"),            /* CLK */
-               SUNXI_FUNCTION(0x3, "jtag")),           /* CK0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi2"),            /* MOSI */
-               SUNXI_FUNCTION(0x3, "jtag")),           /* DO0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi2"),            /* MISO */
-               SUNXI_FUNCTION(0x3, "jtag")),           /* DI0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c1")),           /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c1")),           /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c2")),           /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB21,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c2")),           /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB22,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "uart0"),           /* TX */
-               SUNXI_FUNCTION(0x3, "ir1")),            /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB23,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "uart0"),           /* RX */
-               SUNXI_FUNCTION(0x3, "ir1")),            /* RX */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NWE */
-               SUNXI_FUNCTION(0x3, "spi0")),           /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NALE */
-               SUNXI_FUNCTION(0x3, "spi0")),           /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NCLE */
-               SUNXI_FUNCTION(0x3, "spi0")),           /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NCE1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NCE0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),  /* NRE# */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NRB0 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NRB1 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ0 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ1 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ2 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ3 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NDQ4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NDQ5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NDQ6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NDQ7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NWP */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NCE2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NCE3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NCE4 */
-               SUNXI_FUNCTION(0x3, "spi2")),           /* CS0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC20,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NCE5 */
-               SUNXI_FUNCTION(0x3, "spi2")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC21,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NCE6 */
-               SUNXI_FUNCTION(0x3, "spi2")),           /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC22,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NCE7 */
-               SUNXI_FUNCTION(0x3, "spi2")),           /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC23,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x3, "spi0")),           /* CS0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC24,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NDQS */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D0 */
-               SUNXI_FUNCTION(0x3, "lvds0")),          /* VP0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D1 */
-               SUNXI_FUNCTION(0x3, "lvds0")),          /* VN0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D2 */
-               SUNXI_FUNCTION(0x3, "lvds0")),          /* VP1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D3 */
-               SUNXI_FUNCTION(0x3, "lvds0")),          /* VN1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D4 */
-               SUNXI_FUNCTION(0x3, "lvds0")),          /* VP2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D5 */
-               SUNXI_FUNCTION(0x3, "lvds0")),          /* VN2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D6 */
-               SUNXI_FUNCTION(0x3, "lvds0")),          /* VPC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D7 */
-               SUNXI_FUNCTION(0x3, "lvds0")),          /* VNC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D8 */
-               SUNXI_FUNCTION(0x3, "lvds0")),          /* VP3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D9 */
-               SUNXI_FUNCTION(0x3, "lvds0")),          /* VM3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D10 */
-               SUNXI_FUNCTION(0x3, "lvds1")),          /* VP0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D11 */
-               SUNXI_FUNCTION(0x3, "lvds1")),          /* VN0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D12 */
-               SUNXI_FUNCTION(0x3, "lvds1")),          /* VP1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D13 */
-               SUNXI_FUNCTION(0x3, "lvds1")),          /* VN1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D14 */
-               SUNXI_FUNCTION(0x3, "lvds1")),          /* VP2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D15 */
-               SUNXI_FUNCTION(0x3, "lvds1")),          /* VN2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D16 */
-               SUNXI_FUNCTION(0x3, "lvds1")),          /* VPC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D17 */
-               SUNXI_FUNCTION(0x3, "lvds1")),          /* VNC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D18 */
-               SUNXI_FUNCTION(0x3, "lvds1")),          /* VP3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D19 */
-               SUNXI_FUNCTION(0x3, "lvds1")),          /* VN3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D20 */
-               SUNXI_FUNCTION(0x3, "csi1")),           /* MCLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D21 */
-               SUNXI_FUNCTION(0x3, "sim")),            /* VPPEN */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D22 */
-               SUNXI_FUNCTION(0x3, "sim")),            /* VPPPP */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* D23 */
-               SUNXI_FUNCTION(0x3, "sim")),            /* DET */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* CLK */
-               SUNXI_FUNCTION(0x3, "sim")),            /* VCCEN */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* DE */
-               SUNXI_FUNCTION(0x3, "sim")),            /* RST */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* HSYNC */
-               SUNXI_FUNCTION(0x3, "sim")),            /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0"),            /* VSYNC */
-               SUNXI_FUNCTION(0x3, "sim")),            /* SDA */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* CLK */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* PCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* ERR */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* CK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* SYNC */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* HSYNC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* DVLD */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* VSYNC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* D0 */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* D1 */
-               SUNXI_FUNCTION(0x3, "csi0"),            /* D1 */
-               SUNXI_FUNCTION(0x4, "sim")),            /* VPPEN */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* D2 */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* D3 */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* D4 */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* D4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* D5 */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* D5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* D6 */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* D6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts0"),             /* D7 */
-               SUNXI_FUNCTION(0x3, "csi0")),           /* D7 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc0"),            /* D1 */
-               SUNXI_FUNCTION(0x4, "jtag")),           /* MSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc0"),            /* D0 */
-               SUNXI_FUNCTION(0x4, "jtag")),           /* DI1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc0"),            /* CLK */
-               SUNXI_FUNCTION(0x4, "uart0")),          /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc0"),            /* CMD */
-               SUNXI_FUNCTION(0x4, "jtag")),           /* DO1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc0"),            /* D3 */
-               SUNXI_FUNCTION(0x4, "uart0")),          /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc0"),            /* D2 */
-               SUNXI_FUNCTION(0x4, "jtag")),           /* CK1 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* CLK */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* PCK */
-               SUNXI_FUNCTION(0x4, "mmc1")),           /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* ERR */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* CK */
-               SUNXI_FUNCTION(0x4, "mmc1")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* SYNC */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* HSYNC */
-               SUNXI_FUNCTION(0x4, "mmc1")),           /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* DVLD */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* VSYNC */
-               SUNXI_FUNCTION(0x4, "mmc1")),           /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* D0 */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* D0 */
-               SUNXI_FUNCTION(0x4, "mmc1"),            /* D2 */
-               SUNXI_FUNCTION(0x5, "csi0")),           /* D8 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* D1 */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* D1 */
-               SUNXI_FUNCTION(0x4, "mmc1"),            /* D3 */
-               SUNXI_FUNCTION(0x5, "csi0")),           /* D9 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* D2 */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* D2 */
-               SUNXI_FUNCTION(0x4, "uart3"),           /* TX */
-               SUNXI_FUNCTION(0x5, "csi0")),           /* D10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* D3 */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* D3 */
-               SUNXI_FUNCTION(0x4, "uart3"),           /* RX */
-               SUNXI_FUNCTION(0x5, "csi0")),           /* D11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* D4 */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* D4 */
-               SUNXI_FUNCTION(0x4, "uart3"),           /* RTS */
-               SUNXI_FUNCTION(0x5, "csi0")),           /* D12 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* D5 */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* D5 */
-               SUNXI_FUNCTION(0x4, "uart3"),           /* CTS */
-               SUNXI_FUNCTION(0x5, "csi0")),           /* D13 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* D6 */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* D6 */
-               SUNXI_FUNCTION(0x4, "uart4"),           /* TX */
-               SUNXI_FUNCTION(0x5, "csi0")),           /* D14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ts1"),             /* D7 */
-               SUNXI_FUNCTION(0x3, "csi1"),            /* D7 */
-               SUNXI_FUNCTION(0x4, "uart4"),           /* RX */
-               SUNXI_FUNCTION(0x5, "csi0")),           /* D15 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D0 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAA0 */
-               SUNXI_FUNCTION(0x4, "uart3"),           /* TX */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D1 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAA1 */
-               SUNXI_FUNCTION(0x4, "uart3"),           /* RX */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D2 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAA2 */
-               SUNXI_FUNCTION(0x4, "uart3"),           /* RTS */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D3 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAIRQ */
-               SUNXI_FUNCTION(0x4, "uart3"),           /* CTS */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D4 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD0 */
-               SUNXI_FUNCTION(0x4, "uart4"),           /* TX */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D5 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD1 */
-               SUNXI_FUNCTION(0x4, "uart4"),           /* RX */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D6 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD2 */
-               SUNXI_FUNCTION(0x4, "uart5"),           /* TX */
-               SUNXI_FUNCTION(0x5, "ms"),              /* BS */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D7 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD3 */
-               SUNXI_FUNCTION(0x4, "uart5"),           /* RX */
-               SUNXI_FUNCTION(0x5, "ms"),              /* CLK */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH8,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D8 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD4 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* IN0 */
-               SUNXI_FUNCTION(0x5, "ms"),              /* D0 */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D8 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D9 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD5 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* IN1 */
-               SUNXI_FUNCTION(0x5, "ms"),              /* D1 */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D9 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D10 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD6 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* IN2 */
-               SUNXI_FUNCTION(0x5, "ms"),              /* D2 */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D11 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD7 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* IN3 */
-               SUNXI_FUNCTION(0x5, "ms"),              /* D3 */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH12,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D12 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD8 */
-               SUNXI_FUNCTION(0x4, "ps2"),             /* SCK1 */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D12 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH13,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D13 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD9 */
-               SUNXI_FUNCTION(0x4, "ps2"),             /* SDA1 */
-               SUNXI_FUNCTION(0x5, "sim"),             /* RST */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D13 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH14,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D14 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD10 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* IN4 */
-               SUNXI_FUNCTION(0x5, "sim"),             /* VPPEN */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH15,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D15 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD11 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* IN5 */
-               SUNXI_FUNCTION(0x5, "sim"),             /* VPPPP */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D15 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH16,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D16 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD12 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* IN6 */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D16 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH17,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D17 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD13 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* IN7 */
-               SUNXI_FUNCTION(0x5, "sim"),             /* VCCEN */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D17 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D18 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD14 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT0 */
-               SUNXI_FUNCTION(0x5, "sim"),             /* SCK */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D18 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D19 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAD15 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT1 */
-               SUNXI_FUNCTION(0x5, "sim"),             /* SDA */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D19 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D20 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAOE */
-               SUNXI_FUNCTION(0x4, "can"),             /* TX */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D20 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D21 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATADREQ */
-               SUNXI_FUNCTION(0x4, "can"),             /* RX */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D21 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D22 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATADACK */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT2 */
-               SUNXI_FUNCTION(0x5, "mmc1"),            /* CMD */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D22 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH23,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* D23 */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATACS0 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT3 */
-               SUNXI_FUNCTION(0x5, "mmc1"),            /* CLK */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* D23 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH24,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* CLK */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATACS1 */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT4 */
-               SUNXI_FUNCTION(0x5, "mmc1"),            /* D0 */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* PCLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH25,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* DE */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAIORDY */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT5 */
-               SUNXI_FUNCTION(0x5, "mmc1"),            /* D1 */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* FIELD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH26,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* HSYNC */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAIOR */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT6 */
-               SUNXI_FUNCTION(0x5, "mmc1"),            /* D2 */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* HSYNC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PH27,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd1"),            /* VSYNC */
-               SUNXI_FUNCTION(0x3, "pata"),            /* ATAIOW */
-               SUNXI_FUNCTION(0x4, "keypad"),          /* OUT7 */
-               SUNXI_FUNCTION(0x5, "mmc1"),            /* D3 */
-               SUNXI_FUNCTION(0x7, "csi1")),           /* VSYNC */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "pwm")),            /* PWM1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc3")),           /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc3")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc3")),           /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc3")),           /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI8,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc3")),           /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc3")),           /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi0"),            /* CS0 */
-               SUNXI_FUNCTION(0x3, "uart5")),          /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi0"),            /* CLK */
-               SUNXI_FUNCTION(0x3, "uart5")),          /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI12,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi0"),            /* MOSI */
-               SUNXI_FUNCTION(0x3, "uart6")),          /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI13,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi0"),            /* MISO */
-               SUNXI_FUNCTION(0x3, "uart6")),          /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI14,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi0"),            /* CS1 */
-               SUNXI_FUNCTION(0x3, "ps2"),             /* SCK1 */
-               SUNXI_FUNCTION(0x4, "timer4")),         /* TCLKIN0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI15,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi1"),            /* CS1 */
-               SUNXI_FUNCTION(0x3, "ps2"),             /* SDA1 */
-               SUNXI_FUNCTION(0x4, "timer5")),         /* TCLKIN1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI16,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi1"),            /* CS0 */
-               SUNXI_FUNCTION(0x3, "uart2")),          /* RTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI17,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi1"),            /* CLK */
-               SUNXI_FUNCTION(0x3, "uart2")),          /* CTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI18,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi1"),            /* MOSI */
-               SUNXI_FUNCTION(0x3, "uart2")),          /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI19,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi1"),            /* MISO */
-               SUNXI_FUNCTION(0x3, "uart2")),          /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI20,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ps2"),             /* SCK0 */
-               SUNXI_FUNCTION(0x3, "uart7"),           /* TX */
-               SUNXI_FUNCTION(0x4, "hdmi")),           /* HSCL */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PI21,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ps2"),             /* SDA0 */
-               SUNXI_FUNCTION(0x3, "uart7"),           /* RX */
-               SUNXI_FUNCTION(0x4, "hdmi")),           /* HSDA */
-};
-
-static const struct sunxi_desc_pin sun5i_a13_pins[] = {
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c0")),           /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c0")),           /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "pwm")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ir0")),            /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "ir0")),            /* RX */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi2")),           /* CS1 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c1")),           /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c1")),           /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c2")),           /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "i2c2")),           /* SDA */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NWE */
-               SUNXI_FUNCTION(0x3, "spi0")),           /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NALE */
-               SUNXI_FUNCTION(0x3, "spi0")),           /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NCLE */
-               SUNXI_FUNCTION(0x3, "spi0")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NCE1 */
-               SUNXI_FUNCTION(0x3, "spi0")),           /* CS0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NCE0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0")),          /* NRE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NRB0 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NRB1 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ0 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ1 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ2 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ3 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ4 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ5 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ6 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQ7 */
-               SUNXI_FUNCTION(0x3, "mmc2")),           /* D7 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "nand0"),           /* NDQS */
-               SUNXI_FUNCTION(0x4, "uart3")),          /* RTS */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D7 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D12 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D13 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D15 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D18 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D19 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D20 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D21 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D22 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* D23 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* DE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* HSYNC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "lcd0")),           /* VSYNC */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* PCLK */
-               SUNXI_FUNCTION(0x4, "spi2")),           /* CS0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* MCLK */
-               SUNXI_FUNCTION(0x4, "spi2")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* HSYNC */
-               SUNXI_FUNCTION(0x4, "spi2")),           /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* VSYNC */
-               SUNXI_FUNCTION(0x4, "spi2")),           /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* D0 */
-               SUNXI_FUNCTION(0x4, "mmc2")),           /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* D1 */
-               SUNXI_FUNCTION(0x4, "mmc2")),           /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* D2 */
-               SUNXI_FUNCTION(0x4, "mmc2")),           /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* D3 */
-               SUNXI_FUNCTION(0x4, "mmc2")),           /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* D4 */
-               SUNXI_FUNCTION(0x4, "mmc2")),           /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* D5 */
-               SUNXI_FUNCTION(0x4, "mmc2")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* D6 */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x3, "csi0"),            /* D7 */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* RX */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x4, "mmc0")),           /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x4, "mmc0")),           /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x4, "mmc0")),           /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x4, "mmc0")),           /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x4, "mmc0")),           /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x4, "mmc0")),           /* D2 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc1"),            /* CMD */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "mmc1"),            /* CLK */
-               SUNXI_FUNCTION(0x4, "uart1")),          /* RX */
-/* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi1"),            /* CS0 */
-               SUNXI_FUNCTION(0x3, "uart3")),          /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi1"),            /* CLK */
-               SUNXI_FUNCTION(0x3, "uart3")),          /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi1"),            /* MOSI */
-               SUNXI_FUNCTION(0x3, "uart3")),          /* CTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12,
-               SUNXI_FUNCTION(0x0, "gpio_in"),
-               SUNXI_FUNCTION(0x1, "gpio_out"),
-               SUNXI_FUNCTION(0x2, "spi1"),            /* MISO */
-               SUNXI_FUNCTION(0x3, "uart3")),          /* RTS */
-};
-
-static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
-       .pins = sun4i_a10_pins,
-       .npins = ARRAY_SIZE(sun4i_a10_pins),
-};
-
-static const struct sunxi_pinctrl_desc sun5i_a13_pinctrl_data = {
-       .pins = sun5i_a13_pins,
-       .npins = ARRAY_SIZE(sun5i_a13_pins),
-};
+#include "pinctrl-sunxi-pins.h"
 
 static struct sunxi_pinctrl_group *
 sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
@@ -1399,6 +89,31 @@ sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
        return NULL;
 }
 
+static struct sunxi_desc_function *
+sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl,
+                                       const u16 pin_num,
+                                       const char *func_name)
+{
+       int i;
+
+       for (i = 0; i < pctl->desc->npins; i++) {
+               const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+
+               if (pin->pin.number == pin_num) {
+                       struct sunxi_desc_function *func = pin->functions;
+
+                       while (func->name) {
+                               if (!strcmp(func->name, func_name))
+                                       return func;
+
+                               func++;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
 static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
 {
        struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
@@ -1680,37 +395,20 @@ sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
 {
        struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        struct sunxi_desc_function *desc;
-       char pin_name[SUNXI_PIN_NAME_MAX_LEN];
        const char *func;
-       u8 bank, pin;
-       int ret;
-
-       bank = (offset) / PINS_PER_BANK;
-       pin = (offset) % PINS_PER_BANK;
-
-       ret = sprintf(pin_name, "P%c%d", 'A' + bank, pin);
-       if (!ret)
-               goto error;
 
        if (input)
                func = "gpio_in";
        else
                func = "gpio_out";
 
-       desc = sunxi_pinctrl_desc_find_function_by_name(pctl,
-                                                       pin_name,
-                                                       func);
-       if (!desc) {
-               ret = -EINVAL;
-               goto error;
-       }
+       desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, func);
+       if (!desc)
+               return -EINVAL;
 
        sunxi_pmx_set(pctldev, offset, desc->muxval);
 
-       ret = 0;
-
-error:
-       return ret;
+       return 0;
 }
 
 static const struct pinmux_ops sunxi_pmx_ops = {
@@ -1788,6 +486,26 @@ static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
        return pin;
 }
 
+static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
+       struct sunxi_desc_function *desc;
+
+       if (offset > chip->ngpio)
+               return -ENXIO;
+
+       desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, "irq");
+       if (!desc)
+               return -EINVAL;
+
+       pctl->irq_array[desc->irqnum] = offset;
+
+       dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+               chip->label, offset + chip->base, desc->irqnum);
+
+       return irq_find_mapping(pctl->domain, desc->irqnum);
+}
+
 static struct gpio_chip sunxi_pinctrl_gpio_chip = {
        .owner                  = THIS_MODULE,
        .request                = sunxi_pinctrl_gpio_request,
@@ -1797,12 +515,121 @@ static struct gpio_chip sunxi_pinctrl_gpio_chip = {
        .get                    = sunxi_pinctrl_gpio_get,
        .set                    = sunxi_pinctrl_gpio_set,
        .of_xlate               = sunxi_pinctrl_gpio_of_xlate,
+       .to_irq                 = sunxi_pinctrl_gpio_to_irq,
        .of_gpio_n_cells        = 3,
        .can_sleep              = 0,
 };
 
+static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
+                                     unsigned int type)
+{
+       struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+       u32 reg = sunxi_irq_cfg_reg(d->hwirq);
+       u8 index = sunxi_irq_cfg_offset(d->hwirq);
+       u8 mode;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               mode = IRQ_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               mode = IRQ_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               mode = IRQ_EDGE_BOTH;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               mode = IRQ_LEVEL_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               mode = IRQ_LEVEL_LOW;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       writel((mode & IRQ_CFG_IRQ_MASK) << index, pctl->membase + reg);
+
+       return 0;
+}
+
+static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d)
+{
+       struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+       u32 ctrl_reg = sunxi_irq_ctrl_reg(d->hwirq);
+       u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq);
+       u32 status_reg = sunxi_irq_status_reg(d->hwirq);
+       u8 status_idx = sunxi_irq_status_offset(d->hwirq);
+       u32 val;
+
+       /* Mask the IRQ */
+       val = readl(pctl->membase + ctrl_reg);
+       writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg);
+
+       /* Clear the IRQ */
+       writel(1 << status_idx, pctl->membase + status_reg);
+}
+
+static void sunxi_pinctrl_irq_mask(struct irq_data *d)
+{
+       struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+       u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
+       u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
+       u32 val;
+
+       /* Mask the IRQ */
+       val = readl(pctl->membase + reg);
+       writel(val & ~(1 << idx), pctl->membase + reg);
+}
+
+static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
+{
+       struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+       struct sunxi_desc_function *func;
+       u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
+       u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
+       u32 val;
+
+       func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
+                                                      pctl->irq_array[d->hwirq],
+                                                      "irq");
+
+       /* Change muxing to INT mode */
+       sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
+
+       /* Unmask the IRQ */
+       val = readl(pctl->membase + reg);
+       writel(val | (1 << idx), pctl->membase + reg);
+}
+
+static struct irq_chip sunxi_pinctrl_irq_chip = {
+       .irq_mask       = sunxi_pinctrl_irq_mask,
+       .irq_mask_ack   = sunxi_pinctrl_irq_mask_ack,
+       .irq_unmask     = sunxi_pinctrl_irq_unmask,
+       .irq_set_type   = sunxi_pinctrl_irq_set_type,
+};
+
+static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+       struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
+       const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
+
+       /* Clear all interrupts */
+       writel(reg, pctl->membase + IRQ_STATUS_REG);
+
+       if (reg) {
+               int irqoffset;
+
+               for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
+                       int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
+                       generic_handle_irq(pin_irq);
+               }
+       }
+}
+
 static struct of_device_id sunxi_pinctrl_match[] = {
        { .compatible = "allwinner,sun4i-a10-pinctrl", .data = (void *)&sun4i_a10_pinctrl_data },
+       { .compatible = "allwinner,sun5i-a10s-pinctrl", .data = (void *)&sun5i_a10s_pinctrl_data },
        { .compatible = "allwinner,sun5i-a13-pinctrl", .data = (void *)&sun5i_a13_pinctrl_data },
        {}
 };
@@ -1997,6 +824,31 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
 
        clk_prepare_enable(clk);
 
+       pctl->irq = irq_of_parse_and_map(node, 0);
+       if (!pctl->irq) {
+               ret = -EINVAL;
+               goto gpiochip_error;
+       }
+
+       pctl->domain = irq_domain_add_linear(node, SUNXI_IRQ_NUMBER,
+                                            &irq_domain_simple_ops, NULL);
+       if (!pctl->domain) {
+               dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
+               ret = -ENOMEM;
+               goto gpiochip_error;
+       }
+
+       for (i = 0; i < SUNXI_IRQ_NUMBER; i++) {
+               int irqno = irq_create_mapping(pctl->domain, i);
+
+               irq_set_chip_and_handler(irqno, &sunxi_pinctrl_irq_chip,
+                                        handle_simple_irq);
+               irq_set_chip_data(irqno, pctl);
+       };
+
+       irq_set_chained_handler(pctl->irq, sunxi_pinctrl_irq_handler);
+       irq_set_handler_data(pctl->irq, pctl);
+
        dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
 
        return 0;
index e921621059ce025cbb036666ad8928792cb2b3b9..d68047d8f6992e709c250d39dab4cf1497102eea 100644 (file)
 #define PULL_PINS_BITS         2
 #define PULL_PINS_MASK         0x03
 
+#define SUNXI_IRQ_NUMBER       32
+
+#define IRQ_CFG_REG            0x200
+#define IRQ_CFG_IRQ_PER_REG            8
+#define IRQ_CFG_IRQ_BITS               4
+#define IRQ_CFG_IRQ_MASK               ((1 << IRQ_CFG_IRQ_BITS) - 1)
+#define IRQ_CTRL_REG           0x210
+#define IRQ_CTRL_IRQ_PER_REG           32
+#define IRQ_CTRL_IRQ_BITS              1
+#define IRQ_CTRL_IRQ_MASK              ((1 << IRQ_CTRL_IRQ_BITS) - 1)
+#define IRQ_STATUS_REG         0x214
+#define IRQ_STATUS_IRQ_PER_REG         32
+#define IRQ_STATUS_IRQ_BITS            1
+#define IRQ_STATUS_IRQ_MASK            ((1 << IRQ_STATUS_IRQ_BITS) - 1)
+
+#define IRQ_EDGE_RISING                0x00
+#define IRQ_EDGE_FALLING       0x01
+#define IRQ_LEVEL_HIGH         0x02
+#define IRQ_LEVEL_LOW          0x03
+#define IRQ_EDGE_BOTH          0x04
+
 struct sunxi_desc_function {
        const char      *name;
        u8              muxval;
+       u8              irqnum;
 };
 
 struct sunxi_desc_pin {
@@ -378,10 +400,13 @@ struct sunxi_pinctrl {
        struct gpio_chip                *chip;
        struct sunxi_pinctrl_desc       *desc;
        struct device                   *dev;
+       struct irq_domain               *domain;
        struct sunxi_pinctrl_function   *functions;
        unsigned                        nfunctions;
        struct sunxi_pinctrl_group      *groups;
        unsigned                        ngroups;
+       int                             irq;
+       int                             irq_array[SUNXI_IRQ_NUMBER];
        struct pinctrl_dev              *pctl_dev;
 };
 
@@ -398,6 +423,13 @@ struct sunxi_pinctrl {
                .muxval = _val,                                 \
        }
 
+#define SUNXI_FUNCTION_IRQ(_val, _irq)                         \
+       {                                                       \
+               .name = "irq",                                  \
+               .muxval = _val,                                 \
+               .irqnum = _irq,                                 \
+       }
+
 /*
  * The sunXi PIO registers are organized as is:
  * 0x00 - 0x0c Muxing values.
@@ -475,4 +507,40 @@ static inline u32 sunxi_pull_offset(u16 pin)
        return pin_num * PULL_PINS_BITS;
 }
 
+static inline u32 sunxi_irq_cfg_reg(u16 irq)
+{
+       u8 reg = irq / IRQ_CFG_IRQ_PER_REG;
+       return reg + IRQ_CFG_REG;
+}
+
+static inline u32 sunxi_irq_cfg_offset(u16 irq)
+{
+       u32 irq_num = irq % IRQ_CFG_IRQ_PER_REG;
+       return irq_num * IRQ_CFG_IRQ_BITS;
+}
+
+static inline u32 sunxi_irq_ctrl_reg(u16 irq)
+{
+       u8 reg = irq / IRQ_CTRL_IRQ_PER_REG;
+       return reg + IRQ_CTRL_REG;
+}
+
+static inline u32 sunxi_irq_ctrl_offset(u16 irq)
+{
+       u32 irq_num = irq % IRQ_CTRL_IRQ_PER_REG;
+       return irq_num * IRQ_CTRL_IRQ_BITS;
+}
+
+static inline u32 sunxi_irq_status_reg(u16 irq)
+{
+       u8 reg = irq / IRQ_STATUS_IRQ_PER_REG;
+       return reg + IRQ_STATUS_REG;
+}
+
+static inline u32 sunxi_irq_status_offset(u16 irq)
+{
+       u32 irq_num = irq % IRQ_STATUS_IRQ_PER_REG;
+       return irq_num * IRQ_STATUS_IRQ_BITS;
+}
+
 #endif /* __PINCTRL_SUNXI_H */
diff --git a/drivers/pinctrl/pinctrl-tz1090-pdc.c b/drivers/pinctrl/pinctrl-tz1090-pdc.c
new file mode 100644 (file)
index 0000000..d4f12cc
--- /dev/null
@@ -0,0 +1,1024 @@
+/*
+ * Pinctrl driver for the Toumaz Xenif TZ1090 PowerDown Controller pins
+ *
+ * Copyright (c) 2013, Imagination Technologies Ltd.
+ *
+ * Derived from Tegra code:
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Derived from code:
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2010 NVIDIA Corporation
+ * Copyright (C) 2009-2011 ST-Ericsson AB
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+/*
+ * The registers may be shared with other threads/cores, so we need to use the
+ * metag global lock2 for atomicity.
+ */
+#include <asm/global_lock.h>
+
+#include "core.h"
+#include "pinconf.h"
+
+/* Register offsets from bank base address */
+#define REG_GPIO_CONTROL0      0x00
+#define REG_GPIO_CONTROL2      0x08
+
+/* Register field information */
+#define REG_GPIO_CONTROL2_PU_PD_S      16
+#define REG_GPIO_CONTROL2_PDC_POS_S     4
+#define REG_GPIO_CONTROL2_PDC_DR_S      2
+#define REG_GPIO_CONTROL2_PDC_SR_S      1
+#define REG_GPIO_CONTROL2_PDC_SCHMITT_S         0
+
+/* PU_PD field values */
+#define REG_PU_PD_TRISTATE     0
+#define REG_PU_PD_UP           1
+#define REG_PU_PD_DOWN         2
+#define REG_PU_PD_REPEATER     3
+
+/* DR field values */
+#define REG_DR_2mA             0
+#define REG_DR_4mA             1
+#define REG_DR_8mA             2
+#define REG_DR_12mA            3
+
+/**
+ * struct tz1090_pdc_function - TZ1090 PDC pinctrl mux function
+ * @name:      The name of the function, exported to pinctrl core.
+ * @groups:    An array of pin groups that may select this function.
+ * @ngroups:   The number of entries in @groups.
+ */
+struct tz1090_pdc_function {
+       const char              *name;
+       const char * const      *groups;
+       unsigned int            ngroups;
+};
+
+/**
+ * struct tz1090_pdc_pingroup - TZ1090 PDC pin group
+ * @name:      Name of pin group.
+ * @pins:      Array of pin numbers in this pin group.
+ * @npins:     Number of pins in this pin group.
+ * @func:      Function enabled by the mux.
+ * @reg:       Mux register offset.
+ * @bit:       Mux register bit.
+ * @drv:       Drive control supported, otherwise it's a mux.
+ *             This means Schmitt, Slew, and Drive strength.
+ *
+ * A representation of a group of pins (possibly just one pin) in the TZ1090
+ * PDC pin controller. Each group allows some parameter or parameters to be
+ * configured. The most common is mux function selection.
+ */
+struct tz1090_pdc_pingroup {
+       const char              *name;
+       const unsigned int      *pins;
+       unsigned int            npins;
+       int                     func;
+       u16                     reg;
+       u8                      bit;
+       bool                    drv;
+};
+
+/*
+ * All PDC pins can be GPIOs. Define these first to match how the GPIO driver
+ * names/numbers its pins.
+ */
+
+enum tz1090_pdc_pin {
+       TZ1090_PDC_PIN_GPIO0,
+       TZ1090_PDC_PIN_GPIO1,
+       TZ1090_PDC_PIN_SYS_WAKE0,
+       TZ1090_PDC_PIN_SYS_WAKE1,
+       TZ1090_PDC_PIN_SYS_WAKE2,
+       TZ1090_PDC_PIN_IR_DATA,
+       TZ1090_PDC_PIN_EXT_POWER,
+};
+
+/* Pin names */
+
+static const struct pinctrl_pin_desc tz1090_pdc_pins[] = {
+       /* PDC GPIOs */
+       PINCTRL_PIN(TZ1090_PDC_PIN_GPIO0,       "gpio0"),
+       PINCTRL_PIN(TZ1090_PDC_PIN_GPIO1,       "gpio1"),
+       PINCTRL_PIN(TZ1090_PDC_PIN_SYS_WAKE0,   "sys_wake0"),
+       PINCTRL_PIN(TZ1090_PDC_PIN_SYS_WAKE1,   "sys_wake1"),
+       PINCTRL_PIN(TZ1090_PDC_PIN_SYS_WAKE2,   "sys_wake2"),
+       PINCTRL_PIN(TZ1090_PDC_PIN_IR_DATA,     "ir_data"),
+       PINCTRL_PIN(TZ1090_PDC_PIN_EXT_POWER,   "ext_power"),
+};
+
+/* Pin group pins */
+
+static const unsigned int gpio0_pins[] = {
+       TZ1090_PDC_PIN_GPIO0,
+};
+
+static const unsigned int gpio1_pins[] = {
+       TZ1090_PDC_PIN_GPIO1,
+};
+
+static const unsigned int pdc_pins[] = {
+       TZ1090_PDC_PIN_GPIO0,
+       TZ1090_PDC_PIN_GPIO1,
+       TZ1090_PDC_PIN_SYS_WAKE0,
+       TZ1090_PDC_PIN_SYS_WAKE1,
+       TZ1090_PDC_PIN_SYS_WAKE2,
+       TZ1090_PDC_PIN_IR_DATA,
+       TZ1090_PDC_PIN_EXT_POWER,
+};
+
+/* Mux functions */
+
+enum tz1090_pdc_mux {
+       /* PDC_GPIO0 mux */
+       TZ1090_PDC_MUX_IR_MOD_STABLE_OUT,
+       /* PDC_GPIO1 mux */
+       TZ1090_PDC_MUX_IR_MOD_POWER_OUT,
+};
+
+/* Pin groups a function can be muxed to */
+
+static const char * const gpio0_groups[] = {
+       "gpio0",
+};
+
+static const char * const gpio1_groups[] = {
+       "gpio1",
+};
+
+#define FUNCTION(mux, fname, group)                    \
+       [(TZ1090_PDC_MUX_ ## mux)] = {                  \
+               .name = #fname,                         \
+               .groups = group##_groups,               \
+               .ngroups = ARRAY_SIZE(group##_groups),  \
+       }
+
+/* Must correlate with enum tz1090_pdc_mux */
+static const struct tz1090_pdc_function tz1090_pdc_functions[] = {
+       /*       MUX                    fn                      pingroups */
+       FUNCTION(IR_MOD_STABLE_OUT,     ir_mod_stable_out,      gpio0),
+       FUNCTION(IR_MOD_POWER_OUT,      ir_mod_power_out,       gpio1),
+};
+
+/**
+ * MUX_PG() - Initialise a pin group with mux control
+ * @pg_name:   Pin group name (stringified, _pins appended to get pins array)
+ * @f0:                Function 0 (TZ1090_PDC_MUX_ is prepended)
+ * @mux_r:     Mux register (REG_PINCTRL_ is prepended)
+ * @mux_b:     Bit number in register of mux field
+ */
+#define MUX_PG(pg_name, f0, mux_r, mux_b)                      \
+       {                                                       \
+               .name = #pg_name,                               \
+               .pins = pg_name##_pins,                         \
+               .npins = ARRAY_SIZE(pg_name##_pins),            \
+               .func = TZ1090_PDC_MUX_ ## f0,                  \
+               .reg = (REG_ ## mux_r),                         \
+               .bit = (mux_b),                                 \
+       }
+
+/**
+ * DRV_PG() - Initialise a pin group with drive control
+ * @pg_name:   Pin group name (stringified, _pins appended to get pins array)
+ */
+#define DRV_PG(pg_name)                                \
+       {                                                       \
+               .name = #pg_name,                               \
+               .pins = pg_name##_pins,                         \
+               .npins = ARRAY_SIZE(pg_name##_pins),            \
+               .drv = true,                                    \
+       }
+
+static const struct tz1090_pdc_pingroup tz1090_pdc_groups[] = {
+       /* Muxing pin groups */
+       /*     pg_name, f0,                 mux register,  mux bit */
+       MUX_PG(gpio0,   IR_MOD_STABLE_OUT,  GPIO_CONTROL0, 7),
+       MUX_PG(gpio1,   IR_MOD_POWER_OUT,   GPIO_CONTROL0, 6),
+
+       /* Drive pin groups */
+       /*     pg_name */
+       DRV_PG(pdc),
+};
+
+/**
+ * struct tz1090_pdc_pmx - Private pinctrl data
+ * @dev:       Platform device
+ * @pctl:      Pin control device
+ * @regs:      Register region
+ * @lock:      Lock protecting coherency of mux_en and gpio_en
+ * @mux_en:    Muxes that have been enabled
+ * @gpio_en:   Muxable GPIOs that have been enabled
+ */
+struct tz1090_pdc_pmx {
+       struct device           *dev;
+       struct pinctrl_dev      *pctl;
+       void __iomem            *regs;
+       spinlock_t              lock;
+       u32                     mux_en;
+       u32                     gpio_en;
+};
+
+static inline u32 pmx_read(struct tz1090_pdc_pmx *pmx, u32 reg)
+{
+       return ioread32(pmx->regs + reg);
+}
+
+static inline void pmx_write(struct tz1090_pdc_pmx *pmx, u32 val, u32 reg)
+{
+       iowrite32(val, pmx->regs + reg);
+}
+
+/*
+ * Pin control operations
+ */
+
+static int tz1090_pdc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       return ARRAY_SIZE(tz1090_pdc_groups);
+}
+
+static const char *tz1090_pdc_pinctrl_get_group_name(struct pinctrl_dev *pctl,
+                                                    unsigned int group)
+{
+       return tz1090_pdc_groups[group].name;
+}
+
+static int tz1090_pdc_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+                                            unsigned int group,
+                                            const unsigned int **pins,
+                                            unsigned int *num_pins)
+{
+       *pins = tz1090_pdc_groups[group].pins;
+       *num_pins = tz1090_pdc_groups[group].npins;
+
+       return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void tz1090_pdc_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+                                           struct seq_file *s,
+                                           unsigned int offset)
+{
+       seq_printf(s, " %s", dev_name(pctldev->dev));
+}
+#endif
+
+static int reserve_map(struct device *dev, struct pinctrl_map **map,
+                      unsigned int *reserved_maps, unsigned int *num_maps,
+                      unsigned int reserve)
+{
+       unsigned int old_num = *reserved_maps;
+       unsigned int new_num = *num_maps + reserve;
+       struct pinctrl_map *new_map;
+
+       if (old_num >= new_num)
+               return 0;
+
+       new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
+       if (!new_map) {
+               dev_err(dev, "krealloc(map) failed\n");
+               return -ENOMEM;
+       }
+
+       memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
+
+       *map = new_map;
+       *reserved_maps = new_num;
+
+       return 0;
+}
+
+static int add_map_mux(struct pinctrl_map **map, unsigned int *reserved_maps,
+                      unsigned int *num_maps, const char *group,
+                      const char *function)
+{
+       if (WARN_ON(*num_maps == *reserved_maps))
+               return -ENOSPC;
+
+       (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+       (*map)[*num_maps].data.mux.group = group;
+       (*map)[*num_maps].data.mux.function = function;
+       (*num_maps)++;
+
+       return 0;
+}
+
+/**
+ * get_group_selector() - returns the group selector for a group
+ * @pin_group: the pin group to look up
+ *
+ * This is the same as pinctrl_get_group_selector except it doesn't produce an
+ * error message if the group isn't found or debug messages.
+ */
+static int get_group_selector(const char *pin_group)
+{
+       unsigned int group;
+
+       for (group = 0; group < ARRAY_SIZE(tz1090_pdc_groups); ++group)
+               if (!strcmp(tz1090_pdc_groups[group].name, pin_group))
+                       return group;
+
+       return -EINVAL;
+}
+
+static int add_map_configs(struct device *dev,
+                          struct pinctrl_map **map,
+                          unsigned int *reserved_maps, unsigned int *num_maps,
+                          const char *group, unsigned long *configs,
+                          unsigned int num_configs)
+{
+       unsigned long *dup_configs;
+       enum pinctrl_map_type type;
+
+       if (WARN_ON(*num_maps == *reserved_maps))
+               return -ENOSPC;
+
+       dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
+                             GFP_KERNEL);
+       if (!dup_configs) {
+               dev_err(dev, "kmemdup(configs) failed\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * We support both pins and pin groups, but we need to figure out which
+        * one we have.
+        */
+       if (get_group_selector(group) >= 0)
+               type = PIN_MAP_TYPE_CONFIGS_GROUP;
+       else
+               type = PIN_MAP_TYPE_CONFIGS_PIN;
+       (*map)[*num_maps].type = type;
+       (*map)[*num_maps].data.configs.group_or_pin = group;
+       (*map)[*num_maps].data.configs.configs = dup_configs;
+       (*map)[*num_maps].data.configs.num_configs = num_configs;
+       (*num_maps)++;
+
+       return 0;
+}
+
+static void tz1090_pdc_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+                                          struct pinctrl_map *map,
+                                          unsigned int num_maps)
+{
+       int i;
+
+       for (i = 0; i < num_maps; i++)
+               if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+                       kfree(map[i].data.configs.configs);
+
+       kfree(map);
+}
+
+static int tz1090_pdc_pinctrl_dt_subnode_to_map(struct device *dev,
+                                               struct device_node *np,
+                                               struct pinctrl_map **map,
+                                               unsigned int *reserved_maps,
+                                               unsigned int *num_maps)
+{
+       int ret;
+       const char *function;
+       unsigned long *configs = NULL;
+       unsigned int num_configs = 0;
+       unsigned int reserve;
+       struct property *prop;
+       const char *group;
+
+       ret = of_property_read_string(np, "tz1090,function", &function);
+       if (ret < 0) {
+               /* EINVAL=missing, which is fine since it's optional */
+               if (ret != -EINVAL)
+                       dev_err(dev,
+                               "could not parse property function\n");
+               function = NULL;
+       }
+
+       ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
+       if (ret)
+               return ret;
+
+       reserve = 0;
+       if (function != NULL)
+               reserve++;
+       if (num_configs)
+               reserve++;
+       ret = of_property_count_strings(np, "tz1090,pins");
+       if (ret < 0) {
+               dev_err(dev, "could not parse property pins\n");
+               goto exit;
+       }
+       reserve *= ret;
+
+       ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
+       if (ret < 0)
+               goto exit;
+
+       of_property_for_each_string(np, "tz1090,pins", prop, group) {
+               if (function) {
+                       ret = add_map_mux(map, reserved_maps, num_maps,
+                                         group, function);
+                       if (ret < 0)
+                               goto exit;
+               }
+
+               if (num_configs) {
+                       ret = add_map_configs(dev, map, reserved_maps,
+                                             num_maps, group, configs,
+                                             num_configs);
+                       if (ret < 0)
+                               goto exit;
+               }
+       }
+
+       ret = 0;
+
+exit:
+       kfree(configs);
+       return ret;
+}
+
+static int tz1090_pdc_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+                                            struct device_node *np_config,
+                                            struct pinctrl_map **map,
+                                            unsigned int *num_maps)
+{
+       unsigned int reserved_maps;
+       struct device_node *np;
+       int ret;
+
+       reserved_maps = 0;
+       *map = NULL;
+       *num_maps = 0;
+
+       for_each_child_of_node(np_config, np) {
+               ret = tz1090_pdc_pinctrl_dt_subnode_to_map(pctldev->dev, np,
+                                                          map, &reserved_maps,
+                                                          num_maps);
+               if (ret < 0) {
+                       tz1090_pdc_pinctrl_dt_free_map(pctldev, *map,
+                                                      *num_maps);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static struct pinctrl_ops tz1090_pdc_pinctrl_ops = {
+       .get_groups_count       = tz1090_pdc_pinctrl_get_groups_count,
+       .get_group_name         = tz1090_pdc_pinctrl_get_group_name,
+       .get_group_pins         = tz1090_pdc_pinctrl_get_group_pins,
+#ifdef CONFIG_DEBUG_FS
+       .pin_dbg_show           = tz1090_pdc_pinctrl_pin_dbg_show,
+#endif
+       .dt_node_to_map         = tz1090_pdc_pinctrl_dt_node_to_map,
+       .dt_free_map            = tz1090_pdc_pinctrl_dt_free_map,
+};
+
+/*
+ * Pin mux operations
+ */
+
+static int tz1090_pdc_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+       return ARRAY_SIZE(tz1090_pdc_functions);
+}
+
+static const char *tz1090_pdc_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+                                                   unsigned int function)
+{
+       return tz1090_pdc_functions[function].name;
+}
+
+static int tz1090_pdc_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+                                             unsigned int function,
+                                             const char * const **groups,
+                                             unsigned int * const num_groups)
+{
+       *groups = tz1090_pdc_functions[function].groups;
+       *num_groups = tz1090_pdc_functions[function].ngroups;
+
+       return 0;
+}
+
+/**
+ * tz1090_pdc_pinctrl_mux() - update mux bit
+ * @pmx:               Pinmux data
+ * @grp:               Pin mux group
+ */
+static void tz1090_pdc_pinctrl_mux(struct tz1090_pdc_pmx *pmx,
+                                  const struct tz1090_pdc_pingroup *grp)
+{
+       u32 reg, select;
+       unsigned int pin_shift = grp->pins[0];
+       unsigned long flags;
+
+       /* select = mux && !gpio */
+       select = ((pmx->mux_en & ~pmx->gpio_en) >> pin_shift) & 1;
+
+       /* set up the mux */
+       __global_lock2(flags);
+       reg = pmx_read(pmx, grp->reg);
+       reg &= ~BIT(grp->bit);
+       reg |= select << grp->bit;
+       pmx_write(pmx, reg, grp->reg);
+       __global_unlock2(flags);
+}
+
+static int tz1090_pdc_pinctrl_enable(struct pinctrl_dev *pctldev,
+                                    unsigned int function, unsigned int group)
+{
+       struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       const struct tz1090_pdc_pingroup *grp = &tz1090_pdc_groups[group];
+
+       dev_dbg(pctldev->dev, "%s(func=%u (%s), group=%u (%s))\n",
+               __func__,
+               function, tz1090_pdc_functions[function].name,
+               group, tz1090_pdc_groups[group].name);
+
+       /* is it even a mux? */
+       if (grp->drv)
+               return -EINVAL;
+
+       /* does this group even control the function? */
+       if (function != grp->func)
+               return -EINVAL;
+
+       /* record the pin being muxed and update mux bit */
+       spin_lock(&pmx->lock);
+       pmx->mux_en |= BIT(grp->pins[0]);
+       tz1090_pdc_pinctrl_mux(pmx, grp);
+       spin_unlock(&pmx->lock);
+       return 0;
+}
+
+static void tz1090_pdc_pinctrl_disable(struct pinctrl_dev *pctldev,
+                                      unsigned int function,
+                                      unsigned int group)
+{
+       struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       const struct tz1090_pdc_pingroup *grp = &tz1090_pdc_groups[group];
+
+       dev_dbg(pctldev->dev, "%s(func=%u (%s), group=%u (%s))\n",
+               __func__,
+               function, tz1090_pdc_functions[function].name,
+               group, tz1090_pdc_groups[group].name);
+
+       /* is it even a mux? */
+       if (grp->drv)
+               return;
+
+       /* does this group even control the function? */
+       if (function != grp->func)
+               return;
+
+       /* record the pin being unmuxed and update mux bit */
+       spin_lock(&pmx->lock);
+       pmx->mux_en &= ~BIT(grp->pins[0]);
+       tz1090_pdc_pinctrl_mux(pmx, grp);
+       spin_unlock(&pmx->lock);
+}
+
+static const struct tz1090_pdc_pingroup *find_mux_group(
+                                               struct tz1090_pdc_pmx *pmx,
+                                               unsigned int pin)
+{
+       const struct tz1090_pdc_pingroup *grp;
+       unsigned int group;
+
+       grp = tz1090_pdc_groups;
+       for (group = 0; group < ARRAY_SIZE(tz1090_pdc_groups); ++group, ++grp) {
+               /* only match muxes */
+               if (grp->drv)
+                       continue;
+
+               /* with a matching pin */
+               if (grp->pins[0] == pin)
+                       return grp;
+       }
+
+       return NULL;
+}
+
+static int tz1090_pdc_pinctrl_gpio_request_enable(
+                                       struct pinctrl_dev *pctldev,
+                                       struct pinctrl_gpio_range *range,
+                                       unsigned int pin)
+{
+       struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       const struct tz1090_pdc_pingroup *grp = find_mux_group(pmx, pin);
+
+       if (grp) {
+               /* record the pin in GPIO use and update mux bit */
+               spin_lock(&pmx->lock);
+               pmx->gpio_en |= BIT(pin);
+               tz1090_pdc_pinctrl_mux(pmx, grp);
+               spin_unlock(&pmx->lock);
+       }
+       return 0;
+}
+
+static void tz1090_pdc_pinctrl_gpio_disable_free(
+                                       struct pinctrl_dev *pctldev,
+                                       struct pinctrl_gpio_range *range,
+                                       unsigned int pin)
+{
+       struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       const struct tz1090_pdc_pingroup *grp = find_mux_group(pmx, pin);
+
+       if (grp) {
+               /* record the pin not in GPIO use and update mux bit */
+               spin_lock(&pmx->lock);
+               pmx->gpio_en &= ~BIT(pin);
+               tz1090_pdc_pinctrl_mux(pmx, grp);
+               spin_unlock(&pmx->lock);
+       }
+}
+
+static struct pinmux_ops tz1090_pdc_pinmux_ops = {
+       .get_functions_count    = tz1090_pdc_pinctrl_get_funcs_count,
+       .get_function_name      = tz1090_pdc_pinctrl_get_func_name,
+       .get_function_groups    = tz1090_pdc_pinctrl_get_func_groups,
+       .enable                 = tz1090_pdc_pinctrl_enable,
+       .disable                = tz1090_pdc_pinctrl_disable,
+       .gpio_request_enable    = tz1090_pdc_pinctrl_gpio_request_enable,
+       .gpio_disable_free      = tz1090_pdc_pinctrl_gpio_disable_free,
+};
+
+/*
+ * Pin config operations
+ */
+
+static int tz1090_pdc_pinconf_reg(struct pinctrl_dev *pctldev,
+                                 unsigned int pin,
+                                 enum pin_config_param param,
+                                 bool report_err,
+                                 u32 *reg, u32 *width, u32 *mask, u32 *shift,
+                                 u32 *val)
+{
+       /* Find information about parameter's register */
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+       case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+               *val = REG_PU_PD_TRISTATE;
+               break;
+       case PIN_CONFIG_BIAS_PULL_UP:
+               *val = REG_PU_PD_UP;
+               break;
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               *val = REG_PU_PD_DOWN;
+               break;
+       case PIN_CONFIG_BIAS_BUS_HOLD:
+               *val = REG_PU_PD_REPEATER;
+               break;
+       default:
+               return -ENOTSUPP;
+       };
+
+       /* Only input bias parameters supported */
+       *reg = REG_GPIO_CONTROL2;
+       *shift = REG_GPIO_CONTROL2_PU_PD_S + pin*2;
+       *width = 2;
+
+       /* Calculate field information */
+       *mask = (BIT(*width) - 1) << *shift;
+
+       return 0;
+}
+
+static int tz1090_pdc_pinconf_get(struct pinctrl_dev *pctldev,
+                                 unsigned int pin, unsigned long *config)
+{
+       struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       int ret;
+       u32 reg, width, mask, shift, val, tmp, arg;
+
+       /* Get register information */
+       ret = tz1090_pdc_pinconf_reg(pctldev, pin, param, true,
+                                    &reg, &width, &mask, &shift, &val);
+       if (ret < 0)
+               return ret;
+
+       /* Extract field from register */
+       tmp = pmx_read(pmx, reg);
+       arg = ((tmp & mask) >> shift) == val;
+
+       /* Config not active */
+       if (!arg)
+               return -EINVAL;
+
+       /* And pack config */
+       *config = pinconf_to_config_packed(param, arg);
+
+       return 0;
+}
+
+static int tz1090_pdc_pinconf_set(struct pinctrl_dev *pctldev,
+                                 unsigned int pin, unsigned long config)
+{
+       struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param = pinconf_to_config_param(config);
+       unsigned int arg = pinconf_to_config_argument(config);
+       int ret;
+       u32 reg, width, mask, shift, val, tmp;
+       unsigned long flags;
+
+       dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n",
+               __func__, tz1090_pdc_pins[pin].name, config);
+
+       /* Get register information */
+       ret = tz1090_pdc_pinconf_reg(pctldev, pin, param, true,
+                                    &reg, &width, &mask, &shift, &val);
+       if (ret < 0)
+               return ret;
+
+       /* Unpack argument and range check it */
+       if (arg > 1) {
+               dev_dbg(pctldev->dev, "%s: arg %u out of range\n",
+                       __func__, arg);
+               return -EINVAL;
+       }
+
+       /* Write register field */
+       __global_lock2(flags);
+       tmp = pmx_read(pmx, reg);
+       tmp &= ~mask;
+       if (arg)
+               tmp |= val << shift;
+       pmx_write(pmx, tmp, reg);
+       __global_unlock2(flags);
+
+       return 0;
+}
+
+static const int tz1090_pdc_boolean_map[] = {
+       [0]             = -EINVAL,
+       [1]             = 1,
+};
+
+static const int tz1090_pdc_dr_map[] = {
+       [REG_DR_2mA]    = 2,
+       [REG_DR_4mA]    = 4,
+       [REG_DR_8mA]    = 8,
+       [REG_DR_12mA]   = 12,
+};
+
+static int tz1090_pdc_pinconf_group_reg(struct pinctrl_dev *pctldev,
+                                       const struct tz1090_pdc_pingroup *g,
+                                       enum pin_config_param param,
+                                       bool report_err, u32 *reg, u32 *width,
+                                       u32 *mask, u32 *shift, const int **map)
+{
+       /* Drive configuration applies in groups, but not to all groups. */
+       if (!g->drv) {
+               if (report_err)
+                       dev_dbg(pctldev->dev,
+                               "%s: group %s has no drive control\n",
+                               __func__, g->name);
+               return -ENOTSUPP;
+       }
+
+       /* Find information about drive parameter's register */
+       *reg = REG_GPIO_CONTROL2;
+       switch (param) {
+       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               *shift = REG_GPIO_CONTROL2_PDC_SCHMITT_S;
+               *width = 1;
+               *map = tz1090_pdc_boolean_map;
+               break;
+       case PIN_CONFIG_DRIVE_STRENGTH:
+               *shift = REG_GPIO_CONTROL2_PDC_DR_S;
+               *width = 2;
+               *map = tz1090_pdc_dr_map;
+               break;
+       case PIN_CONFIG_LOW_POWER_MODE:
+               *shift = REG_GPIO_CONTROL2_PDC_POS_S;
+               *width = 1;
+               *map = tz1090_pdc_boolean_map;
+               break;
+       default:
+               return -ENOTSUPP;
+       };
+
+       /* Calculate field information */
+       *mask = (BIT(*width) - 1) << *shift;
+
+       return 0;
+}
+
+static int tz1090_pdc_pinconf_group_get(struct pinctrl_dev *pctldev,
+                                       unsigned int group,
+                                       unsigned long *config)
+{
+       struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       const struct tz1090_pdc_pingroup *g = &tz1090_pdc_groups[group];
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       int ret, arg;
+       u32 reg, width, mask, shift, val;
+       const int *map;
+
+       /* Get register information */
+       ret = tz1090_pdc_pinconf_group_reg(pctldev, g, param, true,
+                                          &reg, &width, &mask, &shift, &map);
+       if (ret < 0)
+               return ret;
+
+       /* Extract field from register */
+       val = pmx_read(pmx, reg);
+       arg = map[(val & mask) >> shift];
+       if (arg < 0)
+               return arg;
+
+       /* And pack config */
+       *config = pinconf_to_config_packed(param, arg);
+
+       return 0;
+}
+
+static int tz1090_pdc_pinconf_group_set(struct pinctrl_dev *pctldev,
+                                       unsigned int group,
+                                       unsigned long config)
+{
+       struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       const struct tz1090_pdc_pingroup *g = &tz1090_pdc_groups[group];
+       enum pin_config_param param = pinconf_to_config_param(config);
+       const unsigned int *pit;
+       unsigned int i;
+       int ret, arg;
+       u32 reg, width, mask, shift, val;
+       unsigned long flags;
+       const int *map;
+
+       dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n",
+               __func__, g->name, config);
+
+       /* Get register information */
+       ret = tz1090_pdc_pinconf_group_reg(pctldev, g, param, true,
+                                          &reg, &width, &mask, &shift, &map);
+       if (ret < 0) {
+               /*
+                * Maybe we're trying to set a per-pin configuration of a group,
+                * so do the pins one by one. This is mainly as a convenience.
+                */
+               for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) {
+                       ret = tz1090_pdc_pinconf_set(pctldev, *pit, config);
+                       if (ret)
+                               return ret;
+               }
+               return 0;
+       }
+
+       /* Unpack argument and map it to register value */
+       arg = pinconf_to_config_argument(config);
+       for (i = 0; i < BIT(width); ++i) {
+               if (map[i] == arg || (map[i] == -EINVAL && !arg)) {
+                       /* Write register field */
+                       __global_lock2(flags);
+                       val = pmx_read(pmx, reg);
+                       val &= ~mask;
+                       val |= i << shift;
+                       pmx_write(pmx, val, reg);
+                       __global_unlock2(flags);
+                       return 0;
+               }
+       }
+
+       dev_dbg(pctldev->dev, "%s: arg %u not supported\n",
+               __func__, arg);
+       return 0;
+}
+
+static struct pinconf_ops tz1090_pdc_pinconf_ops = {
+       .is_generic                     = true,
+       .pin_config_get                 = tz1090_pdc_pinconf_get,
+       .pin_config_set                 = tz1090_pdc_pinconf_set,
+       .pin_config_group_get           = tz1090_pdc_pinconf_group_get,
+       .pin_config_group_set           = tz1090_pdc_pinconf_group_set,
+       .pin_config_config_dbg_show     = pinconf_generic_dump_config,
+};
+
+/*
+ * Pin control driver setup
+ */
+
+static struct pinctrl_desc tz1090_pdc_pinctrl_desc = {
+       .pctlops        = &tz1090_pdc_pinctrl_ops,
+       .pmxops         = &tz1090_pdc_pinmux_ops,
+       .confops        = &tz1090_pdc_pinconf_ops,
+       .owner          = THIS_MODULE,
+};
+
+static int tz1090_pdc_pinctrl_probe(struct platform_device *pdev)
+{
+       struct tz1090_pdc_pmx *pmx;
+       struct resource *res;
+
+       pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
+       if (!pmx) {
+               dev_err(&pdev->dev, "Can't alloc tz1090_pdc_pmx\n");
+               return -ENOMEM;
+       }
+       pmx->dev = &pdev->dev;
+       spin_lock_init(&pmx->lock);
+
+       tz1090_pdc_pinctrl_desc.name = dev_name(&pdev->dev);
+       tz1090_pdc_pinctrl_desc.pins = tz1090_pdc_pins;
+       tz1090_pdc_pinctrl_desc.npins = ARRAY_SIZE(tz1090_pdc_pins);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Missing MEM resource\n");
+               return -ENODEV;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev, res->start,
+                                    resource_size(res),
+                                    dev_name(&pdev->dev))) {
+               dev_err(&pdev->dev,
+                       "Couldn't request MEM resource\n");
+               return -ENODEV;
+       }
+
+       pmx->regs = devm_ioremap(&pdev->dev, res->start,
+                                resource_size(res));
+       if (!pmx->regs) {
+               dev_err(&pdev->dev, "Couldn't ioremap regs\n");
+               return -ENODEV;
+       }
+
+       pmx->pctl = pinctrl_register(&tz1090_pdc_pinctrl_desc, &pdev->dev, pmx);
+       if (!pmx->pctl) {
+               dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+               return -ENODEV;
+       }
+
+       platform_set_drvdata(pdev, pmx);
+
+       dev_info(&pdev->dev, "TZ1090 PDC pinctrl driver initialised\n");
+
+       return 0;
+}
+
+static int tz1090_pdc_pinctrl_remove(struct platform_device *pdev)
+{
+       struct tz1090_pdc_pmx *pmx = platform_get_drvdata(pdev);
+
+       pinctrl_unregister(pmx->pctl);
+
+       return 0;
+}
+
+static struct of_device_id tz1090_pdc_pinctrl_of_match[] = {
+       { .compatible = "img,tz1090-pdc-pinctrl", },
+       { },
+};
+
+static struct platform_driver tz1090_pdc_pinctrl_driver = {
+       .driver = {
+               .name           = "tz1090-pdc-pinctrl",
+               .owner          = THIS_MODULE,
+               .of_match_table = tz1090_pdc_pinctrl_of_match,
+       },
+       .probe  = tz1090_pdc_pinctrl_probe,
+       .remove = tz1090_pdc_pinctrl_remove,
+};
+
+static int __init tz1090_pdc_pinctrl_init(void)
+{
+       return platform_driver_register(&tz1090_pdc_pinctrl_driver);
+}
+arch_initcall(tz1090_pdc_pinctrl_init);
+
+static void __exit tz1090_pdc_pinctrl_exit(void)
+{
+       platform_driver_unregister(&tz1090_pdc_pinctrl_driver);
+}
+module_exit(tz1090_pdc_pinctrl_exit);
+
+MODULE_AUTHOR("Imagination Technologies Ltd.");
+MODULE_DESCRIPTION("Toumaz Xenif TZ1090 PDC pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, tz1090_pdc_pinctrl_of_match);
diff --git a/drivers/pinctrl/pinctrl-tz1090.c b/drivers/pinctrl/pinctrl-tz1090.c
new file mode 100644 (file)
index 0000000..4edae08
--- /dev/null
@@ -0,0 +1,2072 @@
+/*
+ * Pinctrl driver for the Toumaz Xenif TZ1090 SoC
+ *
+ * Copyright (c) 2013, Imagination Technologies Ltd.
+ *
+ * Derived from Tegra code:
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Derived from code:
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2010 NVIDIA Corporation
+ * Copyright (C) 2009-2011 ST-Ericsson AB
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+/*
+ * The registers may be shared with other threads/cores, so we need to use the
+ * metag global lock2 for atomicity.
+ */
+#include <asm/global_lock.h>
+
+#include "core.h"
+#include "pinconf.h"
+
+/* Register offsets from bank base address */
+#define REG_PINCTRL_SELECT     0x10
+#define REG_PINCTRL_SCHMITT    0x90
+#define REG_PINCTRL_PU_PD      0xa0
+#define REG_PINCTRL_SR         0xc0
+#define REG_PINCTRL_DR         0xd0
+#define REG_PINCTRL_IF_CTL     0xe0
+
+/* REG_PINCTRL_PU_PD field values */
+#define REG_PU_PD_TRISTATE     0
+#define REG_PU_PD_UP           1
+#define REG_PU_PD_DOWN         2
+#define REG_PU_PD_REPEATER     3
+
+/* REG_PINCTRL_DR field values */
+#define REG_DR_2mA             0
+#define REG_DR_4mA             1
+#define REG_DR_8mA             2
+#define REG_DR_12mA            3
+
+/**
+ * struct tz1090_function - TZ1090 pinctrl mux function
+ * @name:      The name of the function, exported to pinctrl core.
+ * @groups:    An array of pin groups that may select this function.
+ * @ngroups:   The number of entries in @groups.
+ */
+struct tz1090_function {
+       const char              *name;
+       const char * const      *groups;
+       unsigned int            ngroups;
+};
+
+/**
+ * struct tz1090_muxdesc - TZ1090 individual mux description
+ * @funcs:     Function for each mux value.
+ * @reg:       Mux register offset. 0 if unsupported.
+ * @bit:       Mux register bit. 0 if unsupported.
+ * @width:     Mux field width. 0 if unsupported.
+ *
+ * A representation of a group of signals (possibly just one signal) in the
+ * TZ1090 which can be muxed to a set of functions or sub muxes.
+ */
+struct tz1090_muxdesc {
+       int     funcs[5];
+       u16     reg;
+       u8      bit;
+       u8      width;
+};
+
+/**
+ * struct tz1090_pingroup - TZ1090 pin group
+ * @name:      Name of pin group.
+ * @pins:      Array of pin numbers in this pin group.
+ * @npins:     Number of pins in this pin group.
+ * @mux:       Top level mux.
+ * @drv:       Drive control supported, 0 if unsupported.
+ *             This means Schmitt, Slew, and Drive strength.
+ * @slw_bit:   Slew register bit. 0 if unsupported.
+ *             The same bit is used for Schmitt, and Drive (*2).
+ * @func:      Currently muxed function.
+ * @func_count:        Number of pins using current mux function.
+ *
+ * A representation of a group of pins (possibly just one pin) in the TZ1090
+ * pin controller. Each group allows some parameter or parameters to be
+ * configured. The most common is mux function selection.
+ */
+struct tz1090_pingroup {
+       const char              *name;
+       const unsigned int      *pins;
+       unsigned int            npins;
+       struct tz1090_muxdesc   mux;
+
+       bool                    drv;
+       u8                      slw_bit;
+
+       int                     func;
+       unsigned int            func_count;
+};
+
+/*
+ * Most pins affected by the pinmux can also be GPIOs. Define these first.
+ * These must match how the GPIO driver names/numbers its pins.
+ */
+
+enum tz1090_pin {
+       /* GPIO pins */
+       TZ1090_PIN_SDIO_CLK,
+       TZ1090_PIN_SDIO_CMD,
+       TZ1090_PIN_SDIO_D0,
+       TZ1090_PIN_SDIO_D1,
+       TZ1090_PIN_SDIO_D2,
+       TZ1090_PIN_SDIO_D3,
+       TZ1090_PIN_SDH_CD,
+       TZ1090_PIN_SDH_WP,
+       TZ1090_PIN_SPI0_MCLK,
+       TZ1090_PIN_SPI0_CS0,
+       TZ1090_PIN_SPI0_CS1,
+       TZ1090_PIN_SPI0_CS2,
+       TZ1090_PIN_SPI0_DOUT,
+       TZ1090_PIN_SPI0_DIN,
+       TZ1090_PIN_SPI1_MCLK,
+       TZ1090_PIN_SPI1_CS0,
+       TZ1090_PIN_SPI1_CS1,
+       TZ1090_PIN_SPI1_CS2,
+       TZ1090_PIN_SPI1_DOUT,
+       TZ1090_PIN_SPI1_DIN,
+       TZ1090_PIN_UART0_RXD,
+       TZ1090_PIN_UART0_TXD,
+       TZ1090_PIN_UART0_CTS,
+       TZ1090_PIN_UART0_RTS,
+       TZ1090_PIN_UART1_RXD,
+       TZ1090_PIN_UART1_TXD,
+       TZ1090_PIN_SCB0_SDAT,
+       TZ1090_PIN_SCB0_SCLK,
+       TZ1090_PIN_SCB1_SDAT,
+       TZ1090_PIN_SCB1_SCLK,
+       TZ1090_PIN_SCB2_SDAT,
+       TZ1090_PIN_SCB2_SCLK,
+       TZ1090_PIN_I2S_MCLK,
+       TZ1090_PIN_I2S_BCLK_OUT,
+       TZ1090_PIN_I2S_LRCLK_OUT,
+       TZ1090_PIN_I2S_DOUT0,
+       TZ1090_PIN_I2S_DOUT1,
+       TZ1090_PIN_I2S_DOUT2,
+       TZ1090_PIN_I2S_DIN,
+       TZ1090_PIN_PDM_A,
+       TZ1090_PIN_PDM_B,
+       TZ1090_PIN_PDM_C,
+       TZ1090_PIN_PDM_D,
+       TZ1090_PIN_TFT_RED0,
+       TZ1090_PIN_TFT_RED1,
+       TZ1090_PIN_TFT_RED2,
+       TZ1090_PIN_TFT_RED3,
+       TZ1090_PIN_TFT_RED4,
+       TZ1090_PIN_TFT_RED5,
+       TZ1090_PIN_TFT_RED6,
+       TZ1090_PIN_TFT_RED7,
+       TZ1090_PIN_TFT_GREEN0,
+       TZ1090_PIN_TFT_GREEN1,
+       TZ1090_PIN_TFT_GREEN2,
+       TZ1090_PIN_TFT_GREEN3,
+       TZ1090_PIN_TFT_GREEN4,
+       TZ1090_PIN_TFT_GREEN5,
+       TZ1090_PIN_TFT_GREEN6,
+       TZ1090_PIN_TFT_GREEN7,
+       TZ1090_PIN_TFT_BLUE0,
+       TZ1090_PIN_TFT_BLUE1,
+       TZ1090_PIN_TFT_BLUE2,
+       TZ1090_PIN_TFT_BLUE3,
+       TZ1090_PIN_TFT_BLUE4,
+       TZ1090_PIN_TFT_BLUE5,
+       TZ1090_PIN_TFT_BLUE6,
+       TZ1090_PIN_TFT_BLUE7,
+       TZ1090_PIN_TFT_VDDEN_GD,
+       TZ1090_PIN_TFT_PANELCLK,
+       TZ1090_PIN_TFT_BLANK_LS,
+       TZ1090_PIN_TFT_VSYNC_NS,
+       TZ1090_PIN_TFT_HSYNC_NR,
+       TZ1090_PIN_TFT_VD12ACB,
+       TZ1090_PIN_TFT_PWRSAVE,
+       TZ1090_PIN_TX_ON,
+       TZ1090_PIN_RX_ON,
+       TZ1090_PIN_PLL_ON,
+       TZ1090_PIN_PA_ON,
+       TZ1090_PIN_RX_HP,
+       TZ1090_PIN_GAIN0,
+       TZ1090_PIN_GAIN1,
+       TZ1090_PIN_GAIN2,
+       TZ1090_PIN_GAIN3,
+       TZ1090_PIN_GAIN4,
+       TZ1090_PIN_GAIN5,
+       TZ1090_PIN_GAIN6,
+       TZ1090_PIN_GAIN7,
+       TZ1090_PIN_ANT_SEL0,
+       TZ1090_PIN_ANT_SEL1,
+       TZ1090_PIN_SDH_CLK_IN,
+
+       /* Non-GPIO pins */
+       TZ1090_PIN_TCK,
+       TZ1090_PIN_TRST,
+       TZ1090_PIN_TDI,
+       TZ1090_PIN_TDO,
+       TZ1090_PIN_TMS,
+       TZ1090_PIN_CLK_OUT0,
+       TZ1090_PIN_CLK_OUT1,
+
+       NUM_GPIOS = TZ1090_PIN_TCK,
+};
+
+/* Pin names */
+
+static const struct pinctrl_pin_desc tz1090_pins[] = {
+       /* GPIO pins */
+       PINCTRL_PIN(TZ1090_PIN_SDIO_CLK,        "sdio_clk"),
+       PINCTRL_PIN(TZ1090_PIN_SDIO_CMD,        "sdio_cmd"),
+       PINCTRL_PIN(TZ1090_PIN_SDIO_D0,         "sdio_d0"),
+       PINCTRL_PIN(TZ1090_PIN_SDIO_D1,         "sdio_d1"),
+       PINCTRL_PIN(TZ1090_PIN_SDIO_D2,         "sdio_d2"),
+       PINCTRL_PIN(TZ1090_PIN_SDIO_D3,         "sdio_d3"),
+       PINCTRL_PIN(TZ1090_PIN_SDH_CD,          "sdh_cd"),
+       PINCTRL_PIN(TZ1090_PIN_SDH_WP,          "sdh_wp"),
+       PINCTRL_PIN(TZ1090_PIN_SPI0_MCLK,       "spi0_mclk"),
+       PINCTRL_PIN(TZ1090_PIN_SPI0_CS0,        "spi0_cs0"),
+       PINCTRL_PIN(TZ1090_PIN_SPI0_CS1,        "spi0_cs1"),
+       PINCTRL_PIN(TZ1090_PIN_SPI0_CS2,        "spi0_cs2"),
+       PINCTRL_PIN(TZ1090_PIN_SPI0_DOUT,       "spi0_dout"),
+       PINCTRL_PIN(TZ1090_PIN_SPI0_DIN,        "spi0_din"),
+       PINCTRL_PIN(TZ1090_PIN_SPI1_MCLK,       "spi1_mclk"),
+       PINCTRL_PIN(TZ1090_PIN_SPI1_CS0,        "spi1_cs0"),
+       PINCTRL_PIN(TZ1090_PIN_SPI1_CS1,        "spi1_cs1"),
+       PINCTRL_PIN(TZ1090_PIN_SPI1_CS2,        "spi1_cs2"),
+       PINCTRL_PIN(TZ1090_PIN_SPI1_DOUT,       "spi1_dout"),
+       PINCTRL_PIN(TZ1090_PIN_SPI1_DIN,        "spi1_din"),
+       PINCTRL_PIN(TZ1090_PIN_UART0_RXD,       "uart0_rxd"),
+       PINCTRL_PIN(TZ1090_PIN_UART0_TXD,       "uart0_txd"),
+       PINCTRL_PIN(TZ1090_PIN_UART0_CTS,       "uart0_cts"),
+       PINCTRL_PIN(TZ1090_PIN_UART0_RTS,       "uart0_rts"),
+       PINCTRL_PIN(TZ1090_PIN_UART1_RXD,       "uart1_rxd"),
+       PINCTRL_PIN(TZ1090_PIN_UART1_TXD,       "uart1_txd"),
+       PINCTRL_PIN(TZ1090_PIN_SCB0_SDAT,       "scb0_sdat"),
+       PINCTRL_PIN(TZ1090_PIN_SCB0_SCLK,       "scb0_sclk"),
+       PINCTRL_PIN(TZ1090_PIN_SCB1_SDAT,       "scb1_sdat"),
+       PINCTRL_PIN(TZ1090_PIN_SCB1_SCLK,       "scb1_sclk"),
+       PINCTRL_PIN(TZ1090_PIN_SCB2_SDAT,       "scb2_sdat"),
+       PINCTRL_PIN(TZ1090_PIN_SCB2_SCLK,       "scb2_sclk"),
+       PINCTRL_PIN(TZ1090_PIN_I2S_MCLK,        "i2s_mclk"),
+       PINCTRL_PIN(TZ1090_PIN_I2S_BCLK_OUT,    "i2s_bclk_out"),
+       PINCTRL_PIN(TZ1090_PIN_I2S_LRCLK_OUT,   "i2s_lrclk_out"),
+       PINCTRL_PIN(TZ1090_PIN_I2S_DOUT0,       "i2s_dout0"),
+       PINCTRL_PIN(TZ1090_PIN_I2S_DOUT1,       "i2s_dout1"),
+       PINCTRL_PIN(TZ1090_PIN_I2S_DOUT2,       "i2s_dout2"),
+       PINCTRL_PIN(TZ1090_PIN_I2S_DIN,         "i2s_din"),
+       PINCTRL_PIN(TZ1090_PIN_PDM_A,           "pdm_a"),
+       PINCTRL_PIN(TZ1090_PIN_PDM_B,           "pdm_b"),
+       PINCTRL_PIN(TZ1090_PIN_PDM_C,           "pdm_c"),
+       PINCTRL_PIN(TZ1090_PIN_PDM_D,           "pdm_d"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_RED0,        "tft_red0"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_RED1,        "tft_red1"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_RED2,        "tft_red2"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_RED3,        "tft_red3"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_RED4,        "tft_red4"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_RED5,        "tft_red5"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_RED6,        "tft_red6"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_RED7,        "tft_red7"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_GREEN0,      "tft_green0"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_GREEN1,      "tft_green1"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_GREEN2,      "tft_green2"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_GREEN3,      "tft_green3"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_GREEN4,      "tft_green4"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_GREEN5,      "tft_green5"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_GREEN6,      "tft_green6"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_GREEN7,      "tft_green7"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_BLUE0,       "tft_blue0"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_BLUE1,       "tft_blue1"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_BLUE2,       "tft_blue2"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_BLUE3,       "tft_blue3"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_BLUE4,       "tft_blue4"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_BLUE5,       "tft_blue5"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_BLUE6,       "tft_blue6"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_BLUE7,       "tft_blue7"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_VDDEN_GD,    "tft_vdden_gd"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_PANELCLK,    "tft_panelclk"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_BLANK_LS,    "tft_blank_ls"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_VSYNC_NS,    "tft_vsync_ns"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_HSYNC_NR,    "tft_hsync_nr"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_VD12ACB,     "tft_vd12acb"),
+       PINCTRL_PIN(TZ1090_PIN_TFT_PWRSAVE,     "tft_pwrsave"),
+       PINCTRL_PIN(TZ1090_PIN_TX_ON,           "tx_on"),
+       PINCTRL_PIN(TZ1090_PIN_RX_ON,           "rx_on"),
+       PINCTRL_PIN(TZ1090_PIN_PLL_ON,          "pll_on"),
+       PINCTRL_PIN(TZ1090_PIN_PA_ON,           "pa_on"),
+       PINCTRL_PIN(TZ1090_PIN_RX_HP,           "rx_hp"),
+       PINCTRL_PIN(TZ1090_PIN_GAIN0,           "gain0"),
+       PINCTRL_PIN(TZ1090_PIN_GAIN1,           "gain1"),
+       PINCTRL_PIN(TZ1090_PIN_GAIN2,           "gain2"),
+       PINCTRL_PIN(TZ1090_PIN_GAIN3,           "gain3"),
+       PINCTRL_PIN(TZ1090_PIN_GAIN4,           "gain4"),
+       PINCTRL_PIN(TZ1090_PIN_GAIN5,           "gain5"),
+       PINCTRL_PIN(TZ1090_PIN_GAIN6,           "gain6"),
+       PINCTRL_PIN(TZ1090_PIN_GAIN7,           "gain7"),
+       PINCTRL_PIN(TZ1090_PIN_ANT_SEL0,        "ant_sel0"),
+       PINCTRL_PIN(TZ1090_PIN_ANT_SEL1,        "ant_sel1"),
+       PINCTRL_PIN(TZ1090_PIN_SDH_CLK_IN,      "sdh_clk_in"),
+
+       /* Non-GPIO pins */
+       PINCTRL_PIN(TZ1090_PIN_TCK,             "tck"),
+       PINCTRL_PIN(TZ1090_PIN_TRST,            "trst"),
+       PINCTRL_PIN(TZ1090_PIN_TDI,             "tdi"),
+       PINCTRL_PIN(TZ1090_PIN_TDO,             "tdo"),
+       PINCTRL_PIN(TZ1090_PIN_TMS,             "tms"),
+       PINCTRL_PIN(TZ1090_PIN_CLK_OUT0,        "clk_out0"),
+       PINCTRL_PIN(TZ1090_PIN_CLK_OUT1,        "clk_out1"),
+};
+
+/* Pins in each pin group */
+
+static const unsigned int spi1_cs2_pins[] = {
+       TZ1090_PIN_SPI1_CS2,
+};
+
+static const unsigned int pdm_d_pins[] = {
+       TZ1090_PIN_PDM_D,
+};
+
+static const unsigned int tft_pins[] = {
+       TZ1090_PIN_TFT_RED0,
+       TZ1090_PIN_TFT_RED1,
+       TZ1090_PIN_TFT_RED2,
+       TZ1090_PIN_TFT_RED3,
+       TZ1090_PIN_TFT_RED4,
+       TZ1090_PIN_TFT_RED5,
+       TZ1090_PIN_TFT_RED6,
+       TZ1090_PIN_TFT_RED7,
+       TZ1090_PIN_TFT_GREEN0,
+       TZ1090_PIN_TFT_GREEN1,
+       TZ1090_PIN_TFT_GREEN2,
+       TZ1090_PIN_TFT_GREEN3,
+       TZ1090_PIN_TFT_GREEN4,
+       TZ1090_PIN_TFT_GREEN5,
+       TZ1090_PIN_TFT_GREEN6,
+       TZ1090_PIN_TFT_GREEN7,
+       TZ1090_PIN_TFT_BLUE0,
+       TZ1090_PIN_TFT_BLUE1,
+       TZ1090_PIN_TFT_BLUE2,
+       TZ1090_PIN_TFT_BLUE3,
+       TZ1090_PIN_TFT_BLUE4,
+       TZ1090_PIN_TFT_BLUE5,
+       TZ1090_PIN_TFT_BLUE6,
+       TZ1090_PIN_TFT_BLUE7,
+       TZ1090_PIN_TFT_VDDEN_GD,
+       TZ1090_PIN_TFT_PANELCLK,
+       TZ1090_PIN_TFT_BLANK_LS,
+       TZ1090_PIN_TFT_VSYNC_NS,
+       TZ1090_PIN_TFT_HSYNC_NR,
+       TZ1090_PIN_TFT_VD12ACB,
+       TZ1090_PIN_TFT_PWRSAVE,
+};
+
+static const unsigned int afe_pins[] = {
+       TZ1090_PIN_TX_ON,
+       TZ1090_PIN_RX_ON,
+       TZ1090_PIN_PLL_ON,
+       TZ1090_PIN_PA_ON,
+       TZ1090_PIN_RX_HP,
+       TZ1090_PIN_ANT_SEL0,
+       TZ1090_PIN_ANT_SEL1,
+       TZ1090_PIN_GAIN0,
+       TZ1090_PIN_GAIN1,
+       TZ1090_PIN_GAIN2,
+       TZ1090_PIN_GAIN3,
+       TZ1090_PIN_GAIN4,
+       TZ1090_PIN_GAIN5,
+       TZ1090_PIN_GAIN6,
+       TZ1090_PIN_GAIN7,
+};
+
+static const unsigned int sdio_pins[] = {
+       TZ1090_PIN_SDIO_CLK,
+       TZ1090_PIN_SDIO_CMD,
+       TZ1090_PIN_SDIO_D0,
+       TZ1090_PIN_SDIO_D1,
+       TZ1090_PIN_SDIO_D2,
+       TZ1090_PIN_SDIO_D3,
+};
+
+static const unsigned int sdh_pins[] = {
+       TZ1090_PIN_SDH_CD,
+       TZ1090_PIN_SDH_WP,
+       TZ1090_PIN_SDH_CLK_IN,
+};
+
+static const unsigned int spi0_pins[] = {
+       TZ1090_PIN_SPI0_MCLK,
+       TZ1090_PIN_SPI0_CS0,
+       TZ1090_PIN_SPI0_CS1,
+       TZ1090_PIN_SPI0_CS2,
+       TZ1090_PIN_SPI0_DOUT,
+       TZ1090_PIN_SPI0_DIN,
+};
+
+static const unsigned int spi1_pins[] = {
+       TZ1090_PIN_SPI1_MCLK,
+       TZ1090_PIN_SPI1_CS0,
+       TZ1090_PIN_SPI1_CS1,
+       TZ1090_PIN_SPI1_CS2,
+       TZ1090_PIN_SPI1_DOUT,
+       TZ1090_PIN_SPI1_DIN,
+};
+
+static const unsigned int uart0_pins[] = {
+       TZ1090_PIN_UART0_RTS,
+       TZ1090_PIN_UART0_CTS,
+       TZ1090_PIN_UART0_TXD,
+       TZ1090_PIN_UART0_RXD,
+};
+
+static const unsigned int uart1_pins[] = {
+       TZ1090_PIN_UART1_TXD,
+       TZ1090_PIN_UART1_RXD,
+};
+
+static const unsigned int uart_pins[] = {
+       TZ1090_PIN_UART1_TXD,
+       TZ1090_PIN_UART1_RXD,
+       TZ1090_PIN_UART0_RTS,
+       TZ1090_PIN_UART0_CTS,
+       TZ1090_PIN_UART0_TXD,
+       TZ1090_PIN_UART0_RXD,
+};
+
+static const unsigned int scb0_pins[] = {
+       TZ1090_PIN_SCB0_SDAT,
+       TZ1090_PIN_SCB0_SCLK,
+};
+
+static const unsigned int scb1_pins[] = {
+       TZ1090_PIN_SCB1_SDAT,
+       TZ1090_PIN_SCB1_SCLK,
+};
+
+static const unsigned int scb2_pins[] = {
+       TZ1090_PIN_SCB2_SDAT,
+       TZ1090_PIN_SCB2_SCLK,
+};
+
+static const unsigned int i2s_pins[] = {
+       TZ1090_PIN_I2S_MCLK,
+       TZ1090_PIN_I2S_BCLK_OUT,
+       TZ1090_PIN_I2S_LRCLK_OUT,
+       TZ1090_PIN_I2S_DOUT0,
+       TZ1090_PIN_I2S_DOUT1,
+       TZ1090_PIN_I2S_DOUT2,
+       TZ1090_PIN_I2S_DIN,
+};
+
+static const unsigned int jtag_pins[] = {
+       TZ1090_PIN_TCK,
+       TZ1090_PIN_TRST,
+       TZ1090_PIN_TDI,
+       TZ1090_PIN_TDO,
+       TZ1090_PIN_TMS,
+};
+
+/* Pins in each drive pin group */
+
+static const unsigned int drive_sdio_pins[] = {
+       TZ1090_PIN_SDIO_CLK,
+       TZ1090_PIN_SDIO_CMD,
+       TZ1090_PIN_SDIO_D0,
+       TZ1090_PIN_SDIO_D1,
+       TZ1090_PIN_SDIO_D2,
+       TZ1090_PIN_SDIO_D3,
+       TZ1090_PIN_SDH_WP,
+       TZ1090_PIN_SDH_CD,
+       TZ1090_PIN_SDH_CLK_IN,
+};
+
+static const unsigned int drive_i2s_pins[] = {
+       TZ1090_PIN_CLK_OUT1,
+       TZ1090_PIN_I2S_DIN,
+       TZ1090_PIN_I2S_DOUT0,
+       TZ1090_PIN_I2S_DOUT1,
+       TZ1090_PIN_I2S_DOUT2,
+       TZ1090_PIN_I2S_LRCLK_OUT,
+       TZ1090_PIN_I2S_BCLK_OUT,
+       TZ1090_PIN_I2S_MCLK,
+};
+
+static const unsigned int drive_scb0_pins[] = {
+       TZ1090_PIN_SCB0_SCLK,
+       TZ1090_PIN_SCB0_SDAT,
+       TZ1090_PIN_PDM_D,
+       TZ1090_PIN_PDM_C,
+};
+
+static const unsigned int drive_pdm_pins[] = {
+       TZ1090_PIN_CLK_OUT0,
+       TZ1090_PIN_PDM_B,
+       TZ1090_PIN_PDM_A,
+};
+
+/* Pin groups each function can be muxed to */
+
+/*
+ * The magic "perip" function allows otherwise non-muxing pins to be enabled in
+ * peripheral mode.
+ */
+static const char * const perip_groups[] = {
+       /* non-muxing convenient gpio pingroups */
+       "uart",
+       "uart0",
+       "uart1",
+       "spi0",
+       "spi1",
+       "scb0",
+       "scb1",
+       "scb2",
+       "i2s",
+       /* individual pins not part of a pin mux group */
+       "spi0_mclk",
+       "spi0_cs0",
+       "spi0_cs1",
+       "spi0_cs2",
+       "spi0_dout",
+       "spi0_din",
+       "spi1_mclk",
+       "spi1_cs0",
+       "spi1_cs1",
+       "spi1_dout",
+       "spi1_din",
+       "uart0_rxd",
+       "uart0_txd",
+       "uart0_cts",
+       "uart0_rts",
+       "uart1_rxd",
+       "uart1_txd",
+       "scb0_sdat",
+       "scb0_sclk",
+       "scb1_sdat",
+       "scb1_sclk",
+       "scb2_sdat",
+       "scb2_sclk",
+       "i2s_mclk",
+       "i2s_bclk_out",
+       "i2s_lrclk_out",
+       "i2s_dout0",
+       "i2s_dout1",
+       "i2s_dout2",
+       "i2s_din",
+       "pdm_a",
+       "pdm_b",
+       "pdm_c",
+};
+
+static const char * const sdh_sdio_groups[] = {
+       "sdh",
+       "sdio",
+       /* sdh pins */
+       "sdh_cd",
+       "sdh_wp",
+       "sdh_clk_in",
+       /* sdio pins */
+       "sdio_clk",
+       "sdio_cmd",
+       "sdio_d0",
+       "sdio_d1",
+       "sdio_d2",
+       "sdio_d3",
+};
+
+static const char * const spi1_cs2_groups[] = {
+       "spi1_cs2",
+};
+
+static const char * const pdm_dac_groups[] = {
+       "pdm_d",
+};
+
+static const char * const usb_vbus_groups[] = {
+       "spi1_cs2",
+       "pdm_d",
+};
+
+static const char * const afe_groups[] = {
+       "afe",
+       /* afe pins */
+       "tx_on",
+       "rx_on",
+       "pll_on",
+       "pa_on",
+       "rx_hp",
+       "ant_sel0",
+       "ant_sel1",
+       "gain0",
+       "gain1",
+       "gain2",
+       "gain3",
+       "gain4",
+       "gain5",
+       "gain6",
+       "gain7",
+};
+
+static const char * const tft_groups[] = {
+       "tft",
+       /* tft pins */
+       "tft_red0",
+       "tft_red1",
+       "tft_red2",
+       "tft_red3",
+       "tft_red4",
+       "tft_red5",
+       "tft_red6",
+       "tft_red7",
+       "tft_green0",
+       "tft_green1",
+       "tft_green2",
+       "tft_green3",
+       "tft_green4",
+       "tft_green5",
+       "tft_green6",
+       "tft_green7",
+       "tft_blue0",
+       "tft_blue1",
+       "tft_blue2",
+       "tft_blue3",
+       "tft_blue4",
+       "tft_blue5",
+       "tft_blue6",
+       "tft_blue7",
+       "tft_vdden_gd",
+       "tft_panelclk",
+       "tft_blank_ls",
+       "tft_vsync_ns",
+       "tft_hsync_nr",
+       "tft_vd12acb",
+       "tft_pwrsave",
+};
+
+/* Mux functions that can be used by a mux */
+
+enum tz1090_mux {
+       /* internal placeholder */
+       TZ1090_MUX_NA = -1,
+       /* magic per-non-muxing-GPIO-pin peripheral mode mux */
+       TZ1090_MUX_PERIP,
+       /* SDH/SDIO mux */
+       TZ1090_MUX_SDH,
+       TZ1090_MUX_SDIO,
+       /* USB_VBUS muxes */
+       TZ1090_MUX_SPI1_CS2,
+       TZ1090_MUX_PDM_DAC,
+       TZ1090_MUX_USB_VBUS,
+       /* AFE mux */
+       TZ1090_MUX_AFE,
+       TZ1090_MUX_TS_OUT_0,
+       /* EXT_DAC mux */
+       TZ1090_MUX_DAC,
+       TZ1090_MUX_NOT_IQADC_STB,
+       TZ1090_MUX_IQDAC_STB,
+       /* TFT mux */
+       TZ1090_MUX_TFT,
+       TZ1090_MUX_EXT_DAC,
+       TZ1090_MUX_TS_OUT_1,
+       TZ1090_MUX_LCD_TRACE,
+       TZ1090_MUX_PHY_RINGOSC,
+};
+
+#define FUNCTION(mux, fname, group)                    \
+       [(TZ1090_MUX_ ## mux)] = {                      \
+               .name = #fname,                         \
+               .groups = group##_groups,               \
+               .ngroups = ARRAY_SIZE(group##_groups),  \
+       }
+/* For intermediate functions with submuxes */
+#define NULL_FUNCTION(mux, fname)                      \
+       [(TZ1090_MUX_ ## mux)] = {                      \
+               .name = #fname,                         \
+       }
+
+/* Must correlate with enum tz1090_mux */
+static const struct tz1090_function tz1090_functions[] = {
+       /*       FUNCTION       function name   pingroups */
+       FUNCTION(PERIP,         perip,          perip),
+       FUNCTION(SDH,           sdh,            sdh_sdio),
+       FUNCTION(SDIO,          sdio,           sdh_sdio),
+       FUNCTION(SPI1_CS2,      spi1_cs2,       spi1_cs2),
+       FUNCTION(PDM_DAC,       pdm_dac,        pdm_dac),
+       FUNCTION(USB_VBUS,      usb_vbus,       usb_vbus),
+       FUNCTION(AFE,           afe,            afe),
+       FUNCTION(TS_OUT_0,      ts_out_0,       afe),
+       FUNCTION(DAC,           ext_dac,        tft),
+       FUNCTION(NOT_IQADC_STB, not_iqadc_stb,  tft),
+       FUNCTION(IQDAC_STB,     iqdac_stb,      tft),
+       FUNCTION(TFT,           tft,            tft),
+       NULL_FUNCTION(EXT_DAC,  _ext_dac),
+       FUNCTION(TS_OUT_1,      ts_out_1,       tft),
+       FUNCTION(LCD_TRACE,     lcd_trace,      tft),
+       FUNCTION(PHY_RINGOSC,   phy_ringosc,    tft),
+};
+
+/* Sub muxes */
+
+/**
+ * MUX() - Initialise a mux description.
+ * @f0:                Function 0 (TZ1090_MUX_ is prepended, NA for none)
+ * @f1:                Function 1 (TZ1090_MUX_ is prepended, NA for none)
+ * @f2:                Function 2 (TZ1090_MUX_ is prepended, NA for none)
+ * @f3:                Function 3 (TZ1090_MUX_ is prepended, NA for none)
+ * @f4:                Function 4 (TZ1090_MUX_ is prepended, NA for none)
+ * @mux_r:     Mux register (REG_PINCTRL_ is prepended)
+ * @mux_b:     Bit number in register that the mux field begins
+ * @mux_w:     Width of mux field in register
+ */
+#define MUX(f0, f1, f2, f3, f4, mux_r, mux_b, mux_w)           \
+       {                                                       \
+               .funcs = {                                      \
+                       TZ1090_MUX_ ## f0,                      \
+                       TZ1090_MUX_ ## f1,                      \
+                       TZ1090_MUX_ ## f2,                      \
+                       TZ1090_MUX_ ## f3,                      \
+                       TZ1090_MUX_ ## f4,                      \
+               },                                              \
+               .reg = (REG_PINCTRL_ ## mux_r),                 \
+               .bit = (mux_b),                                 \
+               .width = (mux_w),                               \
+       }
+
+/**
+ * DEFINE_SUBMUX() - Defines a submux description separate from a pin group.
+ * @mux:       Mux name (_submux is appended)
+ * @f0:                Function 0 (TZ1090_MUX_ is prepended, NA for none)
+ * @f1:                Function 1 (TZ1090_MUX_ is prepended, NA for none)
+ * @f2:                Function 2 (TZ1090_MUX_ is prepended, NA for none)
+ * @f3:                Function 3 (TZ1090_MUX_ is prepended, NA for none)
+ * @f4:                Function 4 (TZ1090_MUX_ is prepended, NA for none)
+ * @mux_r:     Mux register (REG_PINCTRL_ is prepended)
+ * @mux_b:     Bit number in register that the mux field begins
+ * @mux_w:     Width of mux field in register
+ *
+ * A sub mux is a nested mux that can be bound to a magic function number used
+ * by another mux description. For example value 4 of the top level mux might
+ * correspond to a function which has a submux pointed to in tz1090_submux[].
+ * The outer mux can then take on any function in the top level mux or the
+ * submux, and if a submux function is chosen both muxes are updated to route
+ * the signal from the submux.
+ *
+ * The submux can be defined with DEFINE_SUBMUX and pointed to from
+ * tz1090_submux[] using SUBMUX.
+ */
+#define DEFINE_SUBMUX(mux, f0, f1, f2, f3, f4, mux_r, mux_b, mux_w)    \
+       static struct tz1090_muxdesc mux ## _submux =                   \
+               MUX(f0, f1, f2, f3, f4, mux_r, mux_b, mux_w)
+
+/**
+ * SUBMUX() - Link a submux to a function number.
+ * @f:         Function name (TZ1090_MUX_ is prepended)
+ * @submux:    Submux name (_submux is appended)
+ *
+ * For use in tz1090_submux[] initialisation to link an intermediate function
+ * number to a particular submux description. It indicates that when the
+ * function is chosen the signal is connected to the submux.
+ */
+#define SUBMUX(f, submux)      [(TZ1090_MUX_ ## f)] = &(submux ## _submux)
+
+/**
+ * MUX_PG() - Initialise a pin group with mux control
+ * @pg_name:   Pin group name (stringified, _pins appended to get pins array)
+ * @f0:                Function 0 (TZ1090_MUX_ is prepended, NA for none)
+ * @f1:                Function 1 (TZ1090_MUX_ is prepended, NA for none)
+ * @f2:                Function 2 (TZ1090_MUX_ is prepended, NA for none)
+ * @f3:                Function 3 (TZ1090_MUX_ is prepended, NA for none)
+ * @f4:                Function 4 (TZ1090_MUX_ is prepended, NA for none)
+ * @mux_r:     Mux register (REG_PINCTRL_ is prepended)
+ * @mux_b:     Bit number in register that the mux field begins
+ * @mux_w:     Width of mux field in register
+ */
+#define MUX_PG(pg_name, f0, f1, f2, f3, f4,                    \
+              mux_r, mux_b, mux_w)                             \
+       {                                                       \
+               .name = #pg_name,                               \
+               .pins = pg_name##_pins,                         \
+               .npins = ARRAY_SIZE(pg_name##_pins),            \
+               .mux = MUX(f0, f1, f2, f3, f4,                  \
+                          mux_r, mux_b, mux_w),                \
+       }
+
+/**
+ * SIMPLE_PG() - Initialise a simple convenience pin group
+ * @pg_name:   Pin group name (stringified, _pins appended to get pins array)
+ *
+ * A simple pin group is simply used for binding pins together so they can be
+ * referred to by a single name instead of having to list every pin
+ * individually.
+ */
+#define SIMPLE_PG(pg_name)                                     \
+       {                                                       \
+               .name = #pg_name,                               \
+               .pins = pg_name##_pins,                         \
+               .npins = ARRAY_SIZE(pg_name##_pins),            \
+       }
+
+/**
+ * DRV_PG() - Initialise a pin group with drive control
+ * @pg_name:   Pin group name (stringified, _pins appended to get pins array)
+ * @slw_b:     Slew register bit.
+ *             The same bit is used for Schmitt, and Drive (*2).
+ */
+#define DRV_PG(pg_name, slw_b)                                 \
+       {                                                       \
+               .name = #pg_name,                               \
+               .pins = pg_name##_pins,                         \
+               .npins = ARRAY_SIZE(pg_name##_pins),            \
+               .drv = true,                                    \
+               .slw_bit = (slw_b),                             \
+       }
+
+/*
+ * Define main muxing pin groups
+ */
+
+/* submuxes */
+
+/*            name     f0,  f1,            f2,        f3, f4, mux r/b/w */
+DEFINE_SUBMUX(ext_dac, DAC, NOT_IQADC_STB, IQDAC_STB, NA, NA, IF_CTL, 6, 2);
+
+/* bind submuxes to internal functions */
+static struct tz1090_muxdesc *tz1090_submux[] = {
+       SUBMUX(EXT_DAC, ext_dac),
+};
+
+/*
+ * These are the pin mux groups. Pin muxing can be enabled and disabled for each
+ * pin individually so these groups are internal. The mapping of pins to pin mux
+ * group is below (tz1090_mux_pins).
+ */
+static struct tz1090_pingroup tz1090_mux_groups[] = {
+       /* Muxing pin groups */
+       /*     pg_name,  f0,       f1,       f2,       f3,        f4,          mux r/b/w */
+       MUX_PG(sdh,      SDH,      SDIO,     NA,       NA,        NA,          IF_CTL, 20, 2),
+       MUX_PG(sdio,     SDIO,     SDH,      NA,       NA,        NA,          IF_CTL, 16, 2),
+       MUX_PG(spi1_cs2, SPI1_CS2, USB_VBUS, NA,       NA,        NA,          IF_CTL, 10, 2),
+       MUX_PG(pdm_d,    PDM_DAC,  USB_VBUS, NA,       NA,        NA,          IF_CTL,  8, 2),
+       MUX_PG(afe,      AFE,      TS_OUT_0, NA,       NA,        NA,          IF_CTL,  4, 2),
+       MUX_PG(tft,      TFT,      EXT_DAC,  TS_OUT_1, LCD_TRACE, PHY_RINGOSC, IF_CTL,  0, 3),
+};
+
+/*
+ * This is the mapping from GPIO pins to pin mux groups in tz1090_mux_groups[].
+ * Pins which aren't muxable to multiple peripherals are set to
+ * TZ1090_MUX_GROUP_MAX to enable the "perip" function to enable/disable
+ * peripheral control of the pin.
+ *
+ * This array is initialised in tz1090_init_mux_pins().
+ */
+static u8 tz1090_mux_pins[NUM_GPIOS];
+
+/* TZ1090_MUX_GROUP_MAX is used in tz1090_mux_pins[] for non-muxing pins */
+#define TZ1090_MUX_GROUP_MAX ARRAY_SIZE(tz1090_mux_groups)
+
+/**
+ * tz1090_init_mux_pins() - Initialise GPIO pin to mux group mapping.
+ *
+ * Initialises the tz1090_mux_pins[] array to be the inverse of the pin lists in
+ * each pin mux group in tz1090_mux_groups[].
+ *
+ * It is assumed that no pin mux groups overlap (share pins).
+ */
+static void __init tz1090_init_mux_pins(void)
+{
+       unsigned int g, p;
+       const struct tz1090_pingroup *grp;
+       const unsigned int *pin;
+
+       for (p = 0; p < NUM_GPIOS; ++p)
+               tz1090_mux_pins[p] = TZ1090_MUX_GROUP_MAX;
+
+       grp = tz1090_mux_groups;
+       for (g = 0, grp = tz1090_mux_groups;
+            g < ARRAY_SIZE(tz1090_mux_groups); ++g, ++grp)
+               for (pin = grp->pins, p = 0; p < grp->npins; ++p, ++pin)
+                       tz1090_mux_pins[*pin] = g;
+}
+
+/*
+ * These are the externally visible pin groups. Some of them allow group control
+ * of drive configuration. Some are just simple convenience pingroups. All the
+ * internal pin mux groups in tz1090_mux_groups[] are mirrored here with the
+ * same pins.
+ * Pseudo pin groups follow in the group numbers after this array for each GPIO
+ * pin. Any group used for muxing must have all pins belonging to the same pin
+ * mux group.
+ */
+static struct tz1090_pingroup tz1090_groups[] = {
+       /* Pin groups with drive control (with no out of place pins) */
+       /*     pg_name,         slw/schmitt/drv b */
+       DRV_PG(jtag,            11 /* 11, 22 */),
+       DRV_PG(tft,             10 /* 10, 20 */),
+       DRV_PG(scb2,            9  /*  9, 18 */),
+       DRV_PG(spi0,            7  /*  7, 14 */),
+       DRV_PG(uart,            5  /*  5, 10 */),
+       DRV_PG(scb1,            4  /*  4,  8 */),
+       DRV_PG(spi1,            3  /*  3,  6 */),
+       DRV_PG(afe,             0  /*  0,  0 */),
+
+       /*
+        * Drive specific pin groups (with odd combinations of pins which makes
+        * the pin group naming somewhat arbitrary)
+        */
+       /*     pg_name,         slw/schmitt/drv b */
+       DRV_PG(drive_sdio,      8  /*  8, 16 */), /* sdio_* + sdh_* */
+       DRV_PG(drive_i2s,       6  /*  6, 12 */), /* i2s_* + clk_out1 */
+       DRV_PG(drive_scb0,      2  /*  2,  4 */), /* scb0_* + pdm_{c,d} */
+       DRV_PG(drive_pdm,       1  /*  1,  2 */), /* pdm_{a,b} + clk_out0 */
+
+       /* Convenience pin groups */
+       /*        pg_name */
+       SIMPLE_PG(uart0),
+       SIMPLE_PG(uart1),
+       SIMPLE_PG(scb0),
+       SIMPLE_PG(i2s),
+       SIMPLE_PG(sdh),
+       SIMPLE_PG(sdio),
+
+       /* pseudo-pingroups for each GPIO pin follow */
+};
+
+/**
+ * struct tz1090_pmx - Private pinctrl data
+ * @dev:       Platform device
+ * @pctl:      Pin control device
+ * @regs:      Register region
+ * @lock:      Lock protecting coherency of pin_en, gpio_en, and SELECT regs
+ * @pin_en:    Pins that have been enabled (32 pins packed into each element)
+ * @gpio_en:   GPIOs that have been enabled (32 pins packed into each element)
+ */
+struct tz1090_pmx {
+       struct device           *dev;
+       struct pinctrl_dev      *pctl;
+       void __iomem            *regs;
+       spinlock_t              lock;
+       u32                     pin_en[3];
+       u32                     gpio_en[3];
+};
+
+static inline u32 pmx_read(struct tz1090_pmx *pmx, u32 reg)
+{
+       return ioread32(pmx->regs + reg);
+}
+
+static inline void pmx_write(struct tz1090_pmx *pmx, u32 val, u32 reg)
+{
+       iowrite32(val, pmx->regs + reg);
+}
+
+/*
+ * Pin control operations
+ */
+
+/* each GPIO pin has it's own pseudo pingroup containing only itself */
+
+static int tz1090_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       return ARRAY_SIZE(tz1090_groups) + NUM_GPIOS;
+}
+
+static const char *tz1090_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+                                                unsigned int group)
+{
+       if (group < ARRAY_SIZE(tz1090_groups)) {
+               /* normal pingroup */
+               return tz1090_groups[group].name;
+       } else {
+               /* individual gpio pin pseudo-pingroup */
+               unsigned int pin = group - ARRAY_SIZE(tz1090_groups);
+               return tz1090_pins[pin].name;
+       }
+}
+
+static int tz1090_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+                                        unsigned int group,
+                                        const unsigned int **pins,
+                                        unsigned int *num_pins)
+{
+       if (group < ARRAY_SIZE(tz1090_groups)) {
+               /* normal pingroup */
+               *pins = tz1090_groups[group].pins;
+               *num_pins = tz1090_groups[group].npins;
+       } else {
+               /* individual gpio pin pseudo-pingroup */
+               unsigned int pin = group - ARRAY_SIZE(tz1090_groups);
+               *pins = &tz1090_pins[pin].number;
+               *num_pins = 1;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void tz1090_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+                                       struct seq_file *s,
+                                       unsigned int offset)
+{
+       seq_printf(s, " %s", dev_name(pctldev->dev));
+}
+#endif
+
+static int reserve_map(struct device *dev, struct pinctrl_map **map,
+                      unsigned int *reserved_maps, unsigned int *num_maps,
+                      unsigned int reserve)
+{
+       unsigned int old_num = *reserved_maps;
+       unsigned int new_num = *num_maps + reserve;
+       struct pinctrl_map *new_map;
+
+       if (old_num >= new_num)
+               return 0;
+
+       new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
+       if (!new_map) {
+               dev_err(dev, "krealloc(map) failed\n");
+               return -ENOMEM;
+       }
+
+       memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
+
+       *map = new_map;
+       *reserved_maps = new_num;
+
+       return 0;
+}
+
+static int add_map_mux(struct pinctrl_map **map, unsigned int *reserved_maps,
+                      unsigned int *num_maps, const char *group,
+                      const char *function)
+{
+       if (WARN_ON(*num_maps == *reserved_maps))
+               return -ENOSPC;
+
+       (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+       (*map)[*num_maps].data.mux.group = group;
+       (*map)[*num_maps].data.mux.function = function;
+       (*num_maps)++;
+
+       return 0;
+}
+
+static int add_map_configs(struct device *dev,
+                          struct pinctrl_map **map,
+                          unsigned int *reserved_maps, unsigned int *num_maps,
+                          const char *group, unsigned long *configs,
+                          unsigned int num_configs)
+{
+       unsigned long *dup_configs;
+
+       if (WARN_ON(*num_maps == *reserved_maps))
+               return -ENOSPC;
+
+       dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
+                             GFP_KERNEL);
+       if (!dup_configs) {
+               dev_err(dev, "kmemdup(configs) failed\n");
+               return -ENOMEM;
+       }
+
+       (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
+       (*map)[*num_maps].data.configs.group_or_pin = group;
+       (*map)[*num_maps].data.configs.configs = dup_configs;
+       (*map)[*num_maps].data.configs.num_configs = num_configs;
+       (*num_maps)++;
+
+       return 0;
+}
+
+static void tz1090_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+                                      struct pinctrl_map *map,
+                                      unsigned int num_maps)
+{
+       int i;
+
+       for (i = 0; i < num_maps; i++)
+               if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
+                       kfree(map[i].data.configs.configs);
+
+       kfree(map);
+}
+
+static int tz1090_pinctrl_dt_subnode_to_map(struct device *dev,
+                                           struct device_node *np,
+                                           struct pinctrl_map **map,
+                                           unsigned int *reserved_maps,
+                                           unsigned int *num_maps)
+{
+       int ret;
+       const char *function;
+       unsigned long *configs = NULL;
+       unsigned int num_configs = 0;
+       unsigned int reserve;
+       struct property *prop;
+       const char *group;
+
+       ret = of_property_read_string(np, "tz1090,function", &function);
+       if (ret < 0) {
+               /* EINVAL=missing, which is fine since it's optional */
+               if (ret != -EINVAL)
+                       dev_err(dev, "could not parse property function\n");
+               function = NULL;
+       }
+
+       ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
+       if (ret)
+               return ret;
+
+       reserve = 0;
+       if (function != NULL)
+               reserve++;
+       if (num_configs)
+               reserve++;
+       ret = of_property_count_strings(np, "tz1090,pins");
+       if (ret < 0) {
+               dev_err(dev, "could not parse property pins\n");
+               goto exit;
+       }
+       reserve *= ret;
+
+       ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
+       if (ret < 0)
+               goto exit;
+
+       of_property_for_each_string(np, "tz1090,pins", prop, group) {
+               if (function) {
+                       ret = add_map_mux(map, reserved_maps, num_maps,
+                                         group, function);
+                       if (ret < 0)
+                               goto exit;
+               }
+
+               if (num_configs) {
+                       ret = add_map_configs(dev, map, reserved_maps,
+                                             num_maps, group, configs,
+                                             num_configs);
+                       if (ret < 0)
+                               goto exit;
+               }
+       }
+
+       ret = 0;
+
+exit:
+       kfree(configs);
+       return ret;
+}
+
+static int tz1090_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+                                        struct device_node *np_config,
+                                        struct pinctrl_map **map,
+                                        unsigned int *num_maps)
+{
+       unsigned int reserved_maps;
+       struct device_node *np;
+       int ret;
+
+       reserved_maps = 0;
+       *map = NULL;
+       *num_maps = 0;
+
+       for_each_child_of_node(np_config, np) {
+               ret = tz1090_pinctrl_dt_subnode_to_map(pctldev->dev, np, map,
+                                                      &reserved_maps,
+                                                      num_maps);
+               if (ret < 0) {
+                       tz1090_pinctrl_dt_free_map(pctldev, *map, *num_maps);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static struct pinctrl_ops tz1090_pinctrl_ops = {
+       .get_groups_count       = tz1090_pinctrl_get_groups_count,
+       .get_group_name         = tz1090_pinctrl_get_group_name,
+       .get_group_pins         = tz1090_pinctrl_get_group_pins,
+#ifdef CONFIG_DEBUG_FS
+       .pin_dbg_show           = tz1090_pinctrl_pin_dbg_show,
+#endif
+       .dt_node_to_map         = tz1090_pinctrl_dt_node_to_map,
+       .dt_free_map            = tz1090_pinctrl_dt_free_map,
+};
+
+/*
+ * Pin mux operations
+ */
+
+static int tz1090_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+       return ARRAY_SIZE(tz1090_functions);
+}
+
+static const char *tz1090_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+                                               unsigned int function)
+{
+       return tz1090_functions[function].name;
+}
+
+static int tz1090_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+                                         unsigned int function,
+                                         const char * const **groups,
+                                         unsigned int * const num_groups)
+{
+       /* pingroup functions */
+       *groups = tz1090_functions[function].groups;
+       *num_groups = tz1090_functions[function].ngroups;
+       return 0;
+}
+
+/**
+ * tz1090_pinctrl_select() - update bit in SELECT register
+ * @pmx:               Pinmux data
+ * @pin:               Pin number (must be within GPIO range)
+ */
+static void tz1090_pinctrl_select(struct tz1090_pmx *pmx,
+                                 unsigned int pin)
+{
+       u32 reg, reg_shift, select, val;
+       unsigned int pmx_index, pmx_shift;
+       unsigned long flags;
+
+       /* uses base 32 instead of base 30 */
+       pmx_index = pin >> 5;
+       pmx_shift = pin & 0x1f;
+
+       /* select = !perip || gpio */
+       select = ((~pmx->pin_en[pmx_index] |
+                  pmx->gpio_en[pmx_index]) >> pmx_shift) & 1;
+
+       /* find register and bit offset (base 30) */
+       reg = REG_PINCTRL_SELECT + 4*(pin / 30);
+       reg_shift = pin % 30;
+
+       /* modify gpio select bit */
+       __global_lock2(flags);
+       val = pmx_read(pmx, reg);
+       val &= ~BIT(reg_shift);
+       val |= select << reg_shift;
+       pmx_write(pmx, val, reg);
+       __global_unlock2(flags);
+}
+
+/**
+ * tz1090_pinctrl_gpio_select() - enable/disable GPIO usage for a pin
+ * @pmx:               Pinmux data
+ * @pin:               Pin number
+ * @gpio_select:       true to enable pin as GPIO,
+ *                     false to leave control to whatever function is enabled
+ *
+ * Records that GPIO usage is enabled/disabled so that enabling a function
+ * doesn't override the SELECT register bit.
+ */
+static void tz1090_pinctrl_gpio_select(struct tz1090_pmx *pmx,
+                                      unsigned int pin,
+                                      bool gpio_select)
+{
+       unsigned int index, shift;
+       u32 gpio_en;
+
+       if (pin >= NUM_GPIOS)
+               return;
+
+       /* uses base 32 instead of base 30 */
+       index = pin >> 5;
+       shift = pin & 0x1f;
+
+       spin_lock(&pmx->lock);
+
+       /* keep a record whether gpio is selected */
+       gpio_en = pmx->gpio_en[index];
+       gpio_en &= ~BIT(shift);
+       if (gpio_select)
+               gpio_en |= BIT(shift);
+       pmx->gpio_en[index] = gpio_en;
+
+       /* update the select bit */
+       tz1090_pinctrl_select(pmx, pin);
+
+       spin_unlock(&pmx->lock);
+}
+
+/**
+ * tz1090_pinctrl_perip_select() - enable/disable peripheral interface for a pin
+ * @pmx:               Pinmux data
+ * @pin:               Pin number
+ * @perip_select:      true to enable peripheral interface when not GPIO,
+ *                     false to leave pin in GPIO mode
+ *
+ * Records that peripheral usage is enabled/disabled so that SELECT register can
+ * be set appropriately when GPIO is disabled.
+ */
+static void tz1090_pinctrl_perip_select(struct tz1090_pmx *pmx,
+                                       unsigned int pin,
+                                       bool perip_select)
+{
+       unsigned int index, shift;
+       u32 pin_en;
+
+       if (pin >= NUM_GPIOS)
+               return;
+
+       /* uses base 32 instead of base 30 */
+       index = pin >> 5;
+       shift = pin & 0x1f;
+
+       spin_lock(&pmx->lock);
+
+       /* keep a record whether peripheral is selected */
+       pin_en = pmx->pin_en[index];
+       pin_en &= ~BIT(shift);
+       if (perip_select)
+               pin_en |= BIT(shift);
+       pmx->pin_en[index] = pin_en;
+
+       /* update the select bit */
+       tz1090_pinctrl_select(pmx, pin);
+
+       spin_unlock(&pmx->lock);
+}
+
+/**
+ * tz1090_pinctrl_enable_mux() - Switch a pin mux group to a function.
+ * @pmx:               Pinmux data
+ * @desc:              Pinmux description
+ * @function:          Function to switch to
+ *
+ * Enable a particular function on a pin mux group. Since pin mux descriptions
+ * are nested this function is recursive.
+ */
+static int tz1090_pinctrl_enable_mux(struct tz1090_pmx *pmx,
+                                    const struct tz1090_muxdesc *desc,
+                                    unsigned int function)
+{
+       const int *fit;
+       unsigned long flags;
+       int mux;
+       unsigned int func, ret;
+       u32 reg, mask;
+
+       /* find the mux value for this function, searching recursively */
+       for (mux = 0, fit = desc->funcs;
+            mux < ARRAY_SIZE(desc->funcs); ++mux, ++fit) {
+               func = *fit;
+               if (func == function)
+                       goto found_mux;
+
+               /* maybe it's a sub-mux */
+               if (func < ARRAY_SIZE(tz1090_submux) && tz1090_submux[func]) {
+                       ret = tz1090_pinctrl_enable_mux(pmx,
+                                                       tz1090_submux[func],
+                                                       function);
+                       if (!ret)
+                               goto found_mux;
+               }
+       }
+
+       return -EINVAL;
+found_mux:
+
+       /* Set up the mux */
+       if (desc->width) {
+               mask = (BIT(desc->width) - 1) << desc->bit;
+               __global_lock2(flags);
+               reg = pmx_read(pmx, desc->reg);
+               reg &= ~mask;
+               reg |= (mux << desc->bit) & mask;
+               pmx_write(pmx, reg, desc->reg);
+               __global_unlock2(flags);
+       }
+
+       return 0;
+}
+
+/**
+ * tz1090_pinctrl_enable() - Enable a function on a pin group.
+ * @pctldev:           Pin control data
+ * @function:          Function index to enable
+ * @group:             Group index to enable
+ *
+ * Enable a particular function on a group of pins. The per GPIO pin pseudo pin
+ * groups can be used (in which case the pin will be enabled in peripheral mode
+ * and if it belongs to a pin mux group the mux will be switched if it isn't
+ * already in use. Some convenience pin groups can also be used in which case
+ * the effect is the same as enabling the function on each individual pin in the
+ * group.
+ */
+static int tz1090_pinctrl_enable(struct pinctrl_dev *pctldev,
+                                unsigned int function, unsigned int group)
+{
+       struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       struct tz1090_pingroup *grp;
+       int ret;
+       unsigned int pin_num, mux_group, i, npins;
+       const unsigned int *pins;
+
+       /* group of pins? */
+       if (group < ARRAY_SIZE(tz1090_groups)) {
+               grp = &tz1090_groups[group];
+               npins = grp->npins;
+               pins = grp->pins;
+               /*
+                * All pins in the group must belong to the same mux group,
+                * which allows us to just use the mux group of the first pin.
+                * By explicitly listing permitted pingroups for each function
+                * the pinmux core should ensure this is always the case.
+                */
+       } else {
+               pin_num = group - ARRAY_SIZE(tz1090_groups);
+               npins = 1;
+               pins = &pin_num;
+       }
+       mux_group = tz1090_mux_pins[*pins];
+
+       /* no mux group, but can still be individually muxed to peripheral */
+       if (mux_group >= TZ1090_MUX_GROUP_MAX) {
+               if (function == TZ1090_MUX_PERIP)
+                       goto mux_pins;
+               return -EINVAL;
+       }
+
+       /* mux group already set to a different function? */
+       grp = &tz1090_mux_groups[mux_group];
+       if (grp->func_count && grp->func != function) {
+               dev_err(pctldev->dev,
+                       "%s: can't mux pin(s) to '%s', group already muxed to '%s'\n",
+                       __func__, tz1090_functions[function].name,
+                       tz1090_functions[grp->func].name);
+               return -EBUSY;
+       }
+
+       dev_dbg(pctldev->dev, "%s: muxing %u pin(s) in '%s' to '%s'\n",
+               __func__, npins, grp->name, tz1090_functions[function].name);
+
+       /* if first pin in mux group to be enabled, enable the group mux */
+       if (!grp->func_count) {
+               grp->func = function;
+               ret = tz1090_pinctrl_enable_mux(pmx, &grp->mux, function);
+               if (ret)
+                       return ret;
+       }
+       /* add pins to ref count and mux individually to peripheral */
+       grp->func_count += npins;
+mux_pins:
+       for (i = 0; i < npins; ++i)
+               tz1090_pinctrl_perip_select(pmx, pins[i], true);
+
+       return 0;
+}
+
+/**
+ * tz1090_pinctrl_disable() - Disable a function on a pin group.
+ * @pctldev:           Pin control data
+ * @function:          Function index to disable
+ * @group:             Group index to disable
+ *
+ * Disable a particular function on a group of pins. The per GPIO pin pseudo pin
+ * groups can be used (in which case the pin will be taken out of peripheral
+ * mode. Some convenience pin groups can also be used in which case the effect
+ * is the same as enabling the function on each individual pin in the group.
+ */
+static void tz1090_pinctrl_disable(struct pinctrl_dev *pctldev,
+                                  unsigned int function, unsigned int group)
+{
+       struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       struct tz1090_pingroup *grp;
+       unsigned int pin_num, mux_group, i, npins;
+       const unsigned int *pins;
+
+       /* group of pins? */
+       if (group < ARRAY_SIZE(tz1090_groups)) {
+               grp = &tz1090_groups[group];
+               npins = grp->npins;
+               pins = grp->pins;
+               /*
+                * All pins in the group must belong to the same mux group,
+                * which allows us to just use the mux group of the first pin.
+                * By explicitly listing permitted pingroups for each function
+                * the pinmux core should ensure this is always the case.
+                */
+       } else {
+               pin_num = group - ARRAY_SIZE(tz1090_groups);
+               npins = 1;
+               pins = &pin_num;
+       }
+       mux_group = tz1090_mux_pins[*pins];
+
+       /* no mux group, but can still be individually muxed to peripheral */
+       if (mux_group >= TZ1090_MUX_GROUP_MAX) {
+               if (function == TZ1090_MUX_PERIP)
+                       goto unmux_pins;
+               return;
+       }
+
+       /* mux group already set to a different function? */
+       grp = &tz1090_mux_groups[mux_group];
+       dev_dbg(pctldev->dev, "%s: unmuxing %u pin(s) in '%s' from '%s'\n",
+               __func__, npins, grp->name, tz1090_functions[function].name);
+
+       /* subtract pins from ref count and unmux individually */
+       WARN_ON(grp->func_count < npins);
+       grp->func_count -= npins;
+unmux_pins:
+       for (i = 0; i < npins; ++i)
+               tz1090_pinctrl_perip_select(pmx, pins[i], false);
+}
+
+/**
+ * tz1090_pinctrl_gpio_request_enable() - Put pin in GPIO mode.
+ * @pctldev:           Pin control data
+ * @range:             GPIO range
+ * @pin:               Pin number
+ *
+ * Puts a particular pin into GPIO mode, disabling peripheral control until it's
+ * disabled again.
+ */
+static int tz1090_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
+                                             struct pinctrl_gpio_range *range,
+                                             unsigned int pin)
+{
+       struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       tz1090_pinctrl_gpio_select(pmx, pin, true);
+       return 0;
+}
+
+/**
+ * tz1090_pinctrl_gpio_disable_free() - Take pin out of GPIO mode.
+ * @pctldev:           Pin control data
+ * @range:             GPIO range
+ * @pin:               Pin number
+ *
+ * Take a particular pin out of GPIO mode. If the pin is enabled for a
+ * peripheral it will return to peripheral mode.
+ */
+static void tz1090_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev,
+                                            struct pinctrl_gpio_range *range,
+                                            unsigned int pin)
+{
+       struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       tz1090_pinctrl_gpio_select(pmx, pin, false);
+}
+
+static struct pinmux_ops tz1090_pinmux_ops = {
+       .get_functions_count    = tz1090_pinctrl_get_funcs_count,
+       .get_function_name      = tz1090_pinctrl_get_func_name,
+       .get_function_groups    = tz1090_pinctrl_get_func_groups,
+       .enable                 = tz1090_pinctrl_enable,
+       .disable                = tz1090_pinctrl_disable,
+       .gpio_request_enable    = tz1090_pinctrl_gpio_request_enable,
+       .gpio_disable_free      = tz1090_pinctrl_gpio_disable_free,
+};
+
+/*
+ * Pin config operations
+ */
+
+struct tz1090_pinconf_pullup {
+       unsigned char index;
+       unsigned char shift;
+};
+
+/* The mapping of pin to pull up/down register index and shift */
+static struct tz1090_pinconf_pullup tz1090_pinconf_pullup[] = {
+       {5, 22}, /*  0 - TZ1090_PIN_SDIO_CLK */
+       {0, 14}, /*  1 - TZ1090_PIN_SDIO_CMD */
+       {0,  6}, /*  2 - TZ1090_PIN_SDIO_D0 */
+       {0,  8}, /*  3 - TZ1090_PIN_SDIO_D1 */
+       {0, 10}, /*  4 - TZ1090_PIN_SDIO_D2 */
+       {0, 12}, /*  5 - TZ1090_PIN_SDIO_D3 */
+       {0,  2}, /*  6 - TZ1090_PIN_SDH_CD */
+       {0,  4}, /*  7 - TZ1090_PIN_SDH_WP */
+       {0, 16}, /*  8 - TZ1090_PIN_SPI0_MCLK */
+       {0, 18}, /*  9 - TZ1090_PIN_SPI0_CS0 */
+       {0, 20}, /* 10 - TZ1090_PIN_SPI0_CS1 */
+       {0, 22}, /* 11 - TZ1090_PIN_SPI0_CS2 */
+       {0, 24}, /* 12 - TZ1090_PIN_SPI0_DOUT */
+       {0, 26}, /* 13 - TZ1090_PIN_SPI0_DIN */
+       {0, 28}, /* 14 - TZ1090_PIN_SPI1_MCLK */
+       {0, 30}, /* 15 - TZ1090_PIN_SPI1_CS0 */
+       {1,  0}, /* 16 - TZ1090_PIN_SPI1_CS1 */
+       {1,  2}, /* 17 - TZ1090_PIN_SPI1_CS2 */
+       {1,  4}, /* 18 - TZ1090_PIN_SPI1_DOUT */
+       {1,  6}, /* 19 - TZ1090_PIN_SPI1_DIN */
+       {1,  8}, /* 20 - TZ1090_PIN_UART0_RXD */
+       {1, 10}, /* 21 - TZ1090_PIN_UART0_TXD */
+       {1, 12}, /* 22 - TZ1090_PIN_UART0_CTS */
+       {1, 14}, /* 23 - TZ1090_PIN_UART0_RTS */
+       {1, 16}, /* 24 - TZ1090_PIN_UART1_RXD */
+       {1, 18}, /* 25 - TZ1090_PIN_UART1_TXD */
+       {1, 20}, /* 26 - TZ1090_PIN_SCB0_SDAT */
+       {1, 22}, /* 27 - TZ1090_PIN_SCB0_SCLK */
+       {1, 24}, /* 28 - TZ1090_PIN_SCB1_SDAT */
+       {1, 26}, /* 29 - TZ1090_PIN_SCB1_SCLK */
+
+       {1, 28}, /* 30 - TZ1090_PIN_SCB2_SDAT */
+       {1, 30}, /* 31 - TZ1090_PIN_SCB2_SCLK */
+       {2,  0}, /* 32 - TZ1090_PIN_I2S_MCLK */
+       {2,  2}, /* 33 - TZ1090_PIN_I2S_BCLK_OUT */
+       {2,  4}, /* 34 - TZ1090_PIN_I2S_LRCLK_OUT */
+       {2,  6}, /* 35 - TZ1090_PIN_I2S_DOUT0 */
+       {2,  8}, /* 36 - TZ1090_PIN_I2S_DOUT1 */
+       {2, 10}, /* 37 - TZ1090_PIN_I2S_DOUT2 */
+       {2, 12}, /* 38 - TZ1090_PIN_I2S_DIN */
+       {4, 12}, /* 39 - TZ1090_PIN_PDM_A */
+       {4, 14}, /* 40 - TZ1090_PIN_PDM_B */
+       {4, 18}, /* 41 - TZ1090_PIN_PDM_C */
+       {4, 20}, /* 42 - TZ1090_PIN_PDM_D */
+       {2, 14}, /* 43 - TZ1090_PIN_TFT_RED0 */
+       {2, 16}, /* 44 - TZ1090_PIN_TFT_RED1 */
+       {2, 18}, /* 45 - TZ1090_PIN_TFT_RED2 */
+       {2, 20}, /* 46 - TZ1090_PIN_TFT_RED3 */
+       {2, 22}, /* 47 - TZ1090_PIN_TFT_RED4 */
+       {2, 24}, /* 48 - TZ1090_PIN_TFT_RED5 */
+       {2, 26}, /* 49 - TZ1090_PIN_TFT_RED6 */
+       {2, 28}, /* 50 - TZ1090_PIN_TFT_RED7 */
+       {2, 30}, /* 51 - TZ1090_PIN_TFT_GREEN0 */
+       {3,  0}, /* 52 - TZ1090_PIN_TFT_GREEN1 */
+       {3,  2}, /* 53 - TZ1090_PIN_TFT_GREEN2 */
+       {3,  4}, /* 54 - TZ1090_PIN_TFT_GREEN3 */
+       {3,  6}, /* 55 - TZ1090_PIN_TFT_GREEN4 */
+       {3,  8}, /* 56 - TZ1090_PIN_TFT_GREEN5 */
+       {3, 10}, /* 57 - TZ1090_PIN_TFT_GREEN6 */
+       {3, 12}, /* 58 - TZ1090_PIN_TFT_GREEN7 */
+       {3, 14}, /* 59 - TZ1090_PIN_TFT_BLUE0 */
+
+       {3, 16}, /* 60 - TZ1090_PIN_TFT_BLUE1 */
+       {3, 18}, /* 61 - TZ1090_PIN_TFT_BLUE2 */
+       {3, 20}, /* 62 - TZ1090_PIN_TFT_BLUE3 */
+       {3, 22}, /* 63 - TZ1090_PIN_TFT_BLUE4 */
+       {3, 24}, /* 64 - TZ1090_PIN_TFT_BLUE5 */
+       {3, 26}, /* 65 - TZ1090_PIN_TFT_BLUE6 */
+       {3, 28}, /* 66 - TZ1090_PIN_TFT_BLUE7 */
+       {3, 30}, /* 67 - TZ1090_PIN_TFT_VDDEN_GD */
+       {4,  0}, /* 68 - TZ1090_PIN_TFT_PANELCLK */
+       {4,  2}, /* 69 - TZ1090_PIN_TFT_BLANK_LS */
+       {4,  4}, /* 70 - TZ1090_PIN_TFT_VSYNC_NS */
+       {4,  6}, /* 71 - TZ1090_PIN_TFT_HSYNC_NR */
+       {4,  8}, /* 72 - TZ1090_PIN_TFT_VD12ACB */
+       {4, 10}, /* 73 - TZ1090_PIN_TFT_PWRSAVE */
+       {4, 24}, /* 74 - TZ1090_PIN_TX_ON */
+       {4, 26}, /* 75 - TZ1090_PIN_RX_ON */
+       {4, 28}, /* 76 - TZ1090_PIN_PLL_ON */
+       {4, 30}, /* 77 - TZ1090_PIN_PA_ON */
+       {5,  0}, /* 78 - TZ1090_PIN_RX_HP */
+       {5,  6}, /* 79 - TZ1090_PIN_GAIN0 */
+       {5,  8}, /* 80 - TZ1090_PIN_GAIN1 */
+       {5, 10}, /* 81 - TZ1090_PIN_GAIN2 */
+       {5, 12}, /* 82 - TZ1090_PIN_GAIN3 */
+       {5, 14}, /* 83 - TZ1090_PIN_GAIN4 */
+       {5, 16}, /* 84 - TZ1090_PIN_GAIN5 */
+       {5, 18}, /* 85 - TZ1090_PIN_GAIN6 */
+       {5, 20}, /* 86 - TZ1090_PIN_GAIN7 */
+       {5,  2}, /* 87 - TZ1090_PIN_ANT_SEL0 */
+       {5,  4}, /* 88 - TZ1090_PIN_ANT_SEL1 */
+       {0,  0}, /* 89 - TZ1090_PIN_SDH_CLK_IN */
+
+       {5, 24}, /* 90 - TZ1090_PIN_TCK */
+       {5, 26}, /* 91 - TZ1090_PIN_TRST */
+       {5, 28}, /* 92 - TZ1090_PIN_TDI */
+       {5, 30}, /* 93 - TZ1090_PIN_TDO */
+       {6,  0}, /* 94 - TZ1090_PIN_TMS */
+       {4, 16}, /* 95 - TZ1090_PIN_CLK_OUT0 */
+       {4, 22}, /* 96 - TZ1090_PIN_CLK_OUT1 */
+};
+
+static int tz1090_pinconf_reg(struct pinctrl_dev *pctldev,
+                             unsigned int pin,
+                             enum pin_config_param param,
+                             bool report_err,
+                             u32 *reg, u32 *width, u32 *mask, u32 *shift,
+                             u32 *val)
+{
+       struct tz1090_pinconf_pullup *pu;
+
+       /* All supported pins have controllable input bias */
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+       case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+               *val = REG_PU_PD_TRISTATE;
+               break;
+       case PIN_CONFIG_BIAS_PULL_UP:
+               *val = REG_PU_PD_UP;
+               break;
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               *val = REG_PU_PD_DOWN;
+               break;
+       case PIN_CONFIG_BIAS_BUS_HOLD:
+               *val = REG_PU_PD_REPEATER;
+               break;
+       default:
+               return -ENOTSUPP;
+       };
+
+       /* Only input bias parameters supported */
+       pu = &tz1090_pinconf_pullup[pin];
+       *reg = REG_PINCTRL_PU_PD + 4*pu->index;
+       *shift = pu->shift;
+       *width = 2;
+
+       /* Calculate field information */
+       *mask = (BIT(*width) - 1) << *shift;
+
+       return 0;
+}
+
+static int tz1090_pinconf_get(struct pinctrl_dev *pctldev,
+                             unsigned int pin, unsigned long *config)
+{
+       struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       int ret;
+       u32 reg, width, mask, shift, val, tmp, arg;
+
+       /* Get register information */
+       ret = tz1090_pinconf_reg(pctldev, pin, param, true,
+                                &reg, &width, &mask, &shift, &val);
+       if (ret < 0)
+               return ret;
+
+       /* Extract field from register */
+       tmp = pmx_read(pmx, reg);
+       arg = ((tmp & mask) >> shift) == val;
+
+       /* Config not active */
+       if (!arg)
+               return -EINVAL;
+
+       /* And pack config */
+       *config = pinconf_to_config_packed(param, arg);
+
+       return 0;
+}
+
+static int tz1090_pinconf_set(struct pinctrl_dev *pctldev,
+                             unsigned int pin, unsigned long config)
+{
+       struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       enum pin_config_param param = pinconf_to_config_param(config);
+       unsigned int arg = pinconf_to_config_argument(config);
+       int ret;
+       u32 reg, width, mask, shift, val, tmp;
+       unsigned long flags;
+
+       dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n",
+               __func__, tz1090_pins[pin].name, config);
+
+       /* Get register information */
+       ret = tz1090_pinconf_reg(pctldev, pin, param, true,
+                                &reg, &width, &mask, &shift, &val);
+       if (ret < 0)
+               return ret;
+
+       /* Unpack argument and range check it */
+       if (arg > 1) {
+               dev_dbg(pctldev->dev, "%s: arg %u out of range\n",
+                       __func__, arg);
+               return -EINVAL;
+       }
+
+       /* Write register field */
+       __global_lock2(flags);
+       tmp = pmx_read(pmx, reg);
+       tmp &= ~mask;
+       if (arg)
+               tmp |= val << shift;
+       pmx_write(pmx, tmp, reg);
+       __global_unlock2(flags);
+
+       return 0;
+}
+
+static const int tz1090_boolean_map[] = {
+       [0]             = -EINVAL,
+       [1]             = 1,
+};
+
+static const int tz1090_dr_map[] = {
+       [REG_DR_2mA]    = 2,
+       [REG_DR_4mA]    = 4,
+       [REG_DR_8mA]    = 8,
+       [REG_DR_12mA]   = 12,
+};
+
+static int tz1090_pinconf_group_reg(struct pinctrl_dev *pctldev,
+                                   const struct tz1090_pingroup *g,
+                                   enum pin_config_param param,
+                                   bool report_err,
+                                   u32 *reg, u32 *width, u32 *mask, u32 *shift,
+                                   const int **map)
+{
+       /* Drive configuration applies in groups, but not to all groups. */
+       if (!g->drv) {
+               if (report_err)
+                       dev_dbg(pctldev->dev,
+                               "%s: group %s has no drive control\n",
+                               __func__, g->name);
+               return -ENOTSUPP;
+       }
+
+       /* Find information about drive parameter's register */
+       switch (param) {
+       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               *reg = REG_PINCTRL_SCHMITT;
+               *width = 1;
+               *map = tz1090_boolean_map;
+               break;
+       case PIN_CONFIG_DRIVE_STRENGTH:
+               *reg = REG_PINCTRL_DR;
+               *width = 2;
+               *map = tz1090_dr_map;
+               break;
+       default:
+               return -ENOTSUPP;
+       };
+
+       /* Calculate field information */
+       *shift = g->slw_bit * *width;
+       *mask = (BIT(*width) - 1) << *shift;
+
+       return 0;
+}
+
+static int tz1090_pinconf_group_get(struct pinctrl_dev *pctldev,
+                                   unsigned int group,
+                                   unsigned long *config)
+{
+       struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       const struct tz1090_pingroup *g;
+       enum pin_config_param param = pinconf_to_config_param(*config);
+       int ret, arg;
+       unsigned int pin;
+       u32 reg, width, mask, shift, val;
+       const int *map;
+
+       if (group >= ARRAY_SIZE(tz1090_groups)) {
+               pin = group - ARRAY_SIZE(tz1090_groups);
+               return tz1090_pinconf_get(pctldev, pin, config);
+       }
+
+       g = &tz1090_groups[group];
+       if (g->npins == 1) {
+               pin = g->pins[0];
+               ret = tz1090_pinconf_get(pctldev, pin, config);
+               if (ret != -ENOTSUPP)
+                       return ret;
+       }
+
+       /* Get register information */
+       ret = tz1090_pinconf_group_reg(pctldev, g, param, true,
+                                      &reg, &width, &mask, &shift, &map);
+       if (ret < 0)
+               return ret;
+
+       /* Extract field from register */
+       val = pmx_read(pmx, reg);
+       arg = map[(val & mask) >> shift];
+       if (arg < 0)
+               return arg;
+
+       /* And pack config */
+       *config = pinconf_to_config_packed(param, arg);
+
+       return 0;
+}
+
+static int tz1090_pinconf_group_set(struct pinctrl_dev *pctldev,
+                                   unsigned int group, unsigned long config)
+{
+       struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+       const struct tz1090_pingroup *g;
+       enum pin_config_param param = pinconf_to_config_param(config);
+       unsigned int arg, pin, i;
+       const unsigned int *pit;
+       int ret;
+       u32 reg, width, mask, shift, val;
+       unsigned long flags;
+       const int *map;
+
+       if (group >= ARRAY_SIZE(tz1090_groups)) {
+               pin = group - ARRAY_SIZE(tz1090_groups);
+               return tz1090_pinconf_set(pctldev, pin, config);
+       }
+
+       g = &tz1090_groups[group];
+       if (g->npins == 1) {
+               pin = g->pins[0];
+               ret = tz1090_pinconf_set(pctldev, pin, config);
+               if (ret != -ENOTSUPP)
+                       return ret;
+       }
+
+       dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n",
+               __func__, g->name, config);
+
+       /* Get register information */
+       ret = tz1090_pinconf_group_reg(pctldev, g, param, true,
+                                      &reg, &width, &mask, &shift, &map);
+       if (ret < 0) {
+               /*
+                * Maybe we're trying to set a per-pin configuration of a group,
+                * so do the pins one by one. This is mainly as a convenience.
+                */
+               for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) {
+                       ret = tz1090_pinconf_set(pctldev, *pit, config);
+                       if (ret)
+                               return ret;
+               }
+               return 0;
+       }
+
+       /* Unpack argument and map it to register value */
+       arg = pinconf_to_config_argument(config);
+       for (i = 0; i < BIT(width); ++i) {
+               if (map[i] == arg || (map[i] == -EINVAL && !arg)) {
+                       /* Write register field */
+                       __global_lock2(flags);
+                       val = pmx_read(pmx, reg);
+                       val &= ~mask;
+                       val |= i << shift;
+                       pmx_write(pmx, val, reg);
+                       __global_unlock2(flags);
+                       return 0;
+               }
+       }
+
+       dev_dbg(pctldev->dev, "%s: arg %u not supported\n",
+               __func__, arg);
+       return -EINVAL;
+}
+
+static struct pinconf_ops tz1090_pinconf_ops = {
+       .is_generic                     = true,
+       .pin_config_get                 = tz1090_pinconf_get,
+       .pin_config_set                 = tz1090_pinconf_set,
+       .pin_config_group_get           = tz1090_pinconf_group_get,
+       .pin_config_group_set           = tz1090_pinconf_group_set,
+       .pin_config_config_dbg_show     = pinconf_generic_dump_config,
+};
+
+/*
+ * Pin control driver setup
+ */
+
+static struct pinctrl_desc tz1090_pinctrl_desc = {
+       .pctlops        = &tz1090_pinctrl_ops,
+       .pmxops         = &tz1090_pinmux_ops,
+       .confops        = &tz1090_pinconf_ops,
+       .owner          = THIS_MODULE,
+};
+
+static int tz1090_pinctrl_probe(struct platform_device *pdev)
+{
+       struct tz1090_pmx *pmx;
+       struct resource *res;
+
+       pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
+       if (!pmx) {
+               dev_err(&pdev->dev, "Can't alloc tz1090_pmx\n");
+               return -ENOMEM;
+       }
+       pmx->dev = &pdev->dev;
+       spin_lock_init(&pmx->lock);
+
+       tz1090_pinctrl_desc.name = dev_name(&pdev->dev);
+       tz1090_pinctrl_desc.pins = tz1090_pins;
+       tz1090_pinctrl_desc.npins = ARRAY_SIZE(tz1090_pins);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Missing MEM resource\n");
+               return -ENODEV;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev, res->start,
+                                    resource_size(res),
+                                    dev_name(&pdev->dev))) {
+               dev_err(&pdev->dev,
+                       "Couldn't request MEM resource\n");
+               return -ENODEV;
+       }
+
+       pmx->regs = devm_ioremap(&pdev->dev, res->start,
+                                resource_size(res));
+       if (!pmx->regs) {
+               dev_err(&pdev->dev, "Couldn't ioremap regs\n");
+               return -ENODEV;
+       }
+
+       pmx->pctl = pinctrl_register(&tz1090_pinctrl_desc, &pdev->dev, pmx);
+       if (!pmx->pctl) {
+               dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+               return -ENODEV;
+       }
+
+       platform_set_drvdata(pdev, pmx);
+
+       dev_info(&pdev->dev, "TZ1090 pinctrl driver initialised\n");
+
+       return 0;
+}
+
+static int tz1090_pinctrl_remove(struct platform_device *pdev)
+{
+       struct tz1090_pmx *pmx = platform_get_drvdata(pdev);
+
+       pinctrl_unregister(pmx->pctl);
+
+       return 0;
+}
+
+static struct of_device_id tz1090_pinctrl_of_match[] = {
+       { .compatible = "img,tz1090-pinctrl", },
+       { },
+};
+
+static struct platform_driver tz1090_pinctrl_driver = {
+       .driver = {
+               .name           = "tz1090-pinctrl",
+               .owner          = THIS_MODULE,
+               .of_match_table = tz1090_pinctrl_of_match,
+       },
+       .probe  = tz1090_pinctrl_probe,
+       .remove = tz1090_pinctrl_remove,
+};
+
+static int __init tz1090_pinctrl_init(void)
+{
+       tz1090_init_mux_pins();
+       return platform_driver_register(&tz1090_pinctrl_driver);
+}
+arch_initcall(tz1090_pinctrl_init);
+
+static void __exit tz1090_pinctrl_exit(void)
+{
+       platform_driver_unregister(&tz1090_pinctrl_driver);
+}
+module_exit(tz1090_pinctrl_exit);
+
+MODULE_AUTHOR("Imagination Technologies Ltd.");
+MODULE_DESCRIPTION("Toumaz Xenif TZ1090 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, tz1090_pinctrl_of_match);
index 06bfa09bb15c1bfb9ba41cef0c5dfe2691ac8736..46a152d1735500fcb22320301fddd00d20f66c52 100644 (file)
@@ -1100,7 +1100,6 @@ static int u300_pmx_remove(struct platform_device *pdev)
        struct u300_pmx *upmx = platform_get_drvdata(pdev);
 
        pinctrl_unregister(upmx->pctl);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
diff --git a/drivers/pinctrl/pinctrl-vf610.c b/drivers/pinctrl/pinctrl-vf610.c
new file mode 100644 (file)
index 0000000..68a970b
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * VF610 pinctrl driver based on imx pinmux and pinconf core
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+enum vf610_pads {
+       VF610_PAD_PTA6 = 0,
+       VF610_PAD_PTA8 = 1,
+       VF610_PAD_PTA9 = 2,
+       VF610_PAD_PTA10 = 3,
+       VF610_PAD_PTA11 = 4,
+       VF610_PAD_PTA12 = 5,
+       VF610_PAD_PTA16 = 6,
+       VF610_PAD_PTA17 = 7,
+       VF610_PAD_PTA18 = 8,
+       VF610_PAD_PTA19 = 9,
+       VF610_PAD_PTA20 = 10,
+       VF610_PAD_PTA21 = 11,
+       VF610_PAD_PTA22 = 12,
+       VF610_PAD_PTA23 = 13,
+       VF610_PAD_PTA24 = 14,
+       VF610_PAD_PTA25 = 15,
+       VF610_PAD_PTA26 = 16,
+       VF610_PAD_PTA27 = 17,
+       VF610_PAD_PTA28 = 18,
+       VF610_PAD_PTA29 = 19,
+       VF610_PAD_PTA30 = 20,
+       VF610_PAD_PTA31 = 21,
+       VF610_PAD_PTB0 = 22,
+       VF610_PAD_PTB1 = 23,
+       VF610_PAD_PTB2 = 24,
+       VF610_PAD_PTB3 = 25,
+       VF610_PAD_PTB4 = 26,
+       VF610_PAD_PTB5 = 27,
+       VF610_PAD_PTB6 = 28,
+       VF610_PAD_PTB7 = 29,
+       VF610_PAD_PTB8 = 30,
+       VF610_PAD_PTB9 = 31,
+       VF610_PAD_PTB10 = 32,
+       VF610_PAD_PTB11 = 33,
+       VF610_PAD_PTB12 = 34,
+       VF610_PAD_PTB13 = 35,
+       VF610_PAD_PTB14 = 36,
+       VF610_PAD_PTB15 = 37,
+       VF610_PAD_PTB16 = 38,
+       VF610_PAD_PTB17 = 39,
+       VF610_PAD_PTB18 = 40,
+       VF610_PAD_PTB19 = 41,
+       VF610_PAD_PTB20 = 42,
+       VF610_PAD_PTB21 = 43,
+       VF610_PAD_PTB22 = 44,
+       VF610_PAD_PTC0 = 45,
+       VF610_PAD_PTC1 = 46,
+       VF610_PAD_PTC2 = 47,
+       VF610_PAD_PTC3 = 48,
+       VF610_PAD_PTC4 = 49,
+       VF610_PAD_PTC5 = 50,
+       VF610_PAD_PTC6 = 51,
+       VF610_PAD_PTC7 = 52,
+       VF610_PAD_PTC8 = 53,
+       VF610_PAD_PTC9 = 54,
+       VF610_PAD_PTC10 = 55,
+       VF610_PAD_PTC11 = 56,
+       VF610_PAD_PTC12 = 57,
+       VF610_PAD_PTC13 = 58,
+       VF610_PAD_PTC14 = 59,
+       VF610_PAD_PTC15 = 60,
+       VF610_PAD_PTC16 = 61,
+       VF610_PAD_PTC17 = 62,
+       VF610_PAD_PTD31 = 63,
+       VF610_PAD_PTD30 = 64,
+       VF610_PAD_PTD29 = 65,
+       VF610_PAD_PTD28 = 66,
+       VF610_PAD_PTD27 = 67,
+       VF610_PAD_PTD26 = 68,
+       VF610_PAD_PTD25 = 69,
+       VF610_PAD_PTD24 = 70,
+       VF610_PAD_PTD23 = 71,
+       VF610_PAD_PTD22 = 72,
+       VF610_PAD_PTD21 = 73,
+       VF610_PAD_PTD20 = 74,
+       VF610_PAD_PTD19 = 75,
+       VF610_PAD_PTD18 = 76,
+       VF610_PAD_PTD17 = 77,
+       VF610_PAD_PTD16 = 78,
+       VF610_PAD_PTD0 = 79,
+       VF610_PAD_PTD1 = 80,
+       VF610_PAD_PTD2 = 81,
+       VF610_PAD_PTD3 = 82,
+       VF610_PAD_PTD4 = 83,
+       VF610_PAD_PTD5 = 84,
+       VF610_PAD_PTD6 = 85,
+       VF610_PAD_PTD7 = 86,
+       VF610_PAD_PTD8 = 87,
+       VF610_PAD_PTD9 = 88,
+       VF610_PAD_PTD10 = 89,
+       VF610_PAD_PTD11 = 90,
+       VF610_PAD_PTD12 = 91,
+       VF610_PAD_PTD13 = 92,
+       VF610_PAD_PTB23 = 93,
+       VF610_PAD_PTB24 = 94,
+       VF610_PAD_PTB25 = 95,
+       VF610_PAD_PTB26 = 96,
+       VF610_PAD_PTB27 = 97,
+       VF610_PAD_PTB28 = 98,
+       VF610_PAD_PTC26 = 99,
+       VF610_PAD_PTC27 = 100,
+       VF610_PAD_PTC28 = 101,
+       VF610_PAD_PTC29 = 102,
+       VF610_PAD_PTC30 = 103,
+       VF610_PAD_PTC31 = 104,
+       VF610_PAD_PTE0 = 105,
+       VF610_PAD_PTE1 = 106,
+       VF610_PAD_PTE2 = 107,
+       VF610_PAD_PTE3 = 108,
+       VF610_PAD_PTE4 = 109,
+       VF610_PAD_PTE5 = 110,
+       VF610_PAD_PTE6 = 111,
+       VF610_PAD_PTE7 = 112,
+       VF610_PAD_PTE8 = 113,
+       VF610_PAD_PTE9 = 114,
+       VF610_PAD_PTE10 = 115,
+       VF610_PAD_PTE11 = 116,
+       VF610_PAD_PTE12 = 117,
+       VF610_PAD_PTE13 = 118,
+       VF610_PAD_PTE14 = 119,
+       VF610_PAD_PTE15 = 120,
+       VF610_PAD_PTE16 = 121,
+       VF610_PAD_PTE17 = 122,
+       VF610_PAD_PTE18 = 123,
+       VF610_PAD_PTE19 = 124,
+       VF610_PAD_PTE20 = 125,
+       VF610_PAD_PTE21 = 126,
+       VF610_PAD_PTE22 = 127,
+       VF610_PAD_PTE23 = 128,
+       VF610_PAD_PTE24 = 129,
+       VF610_PAD_PTE25 = 130,
+       VF610_PAD_PTE26 = 131,
+       VF610_PAD_PTE27 = 132,
+       VF610_PAD_PTE28 = 133,
+       VF610_PAD_PTA7 = 134,
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc vf610_pinctrl_pads[] = {
+       IMX_PINCTRL_PIN(VF610_PAD_PTA6),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA8),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA9),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA10),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA11),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA12),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA16),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA17),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA18),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA19),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA20),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA21),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA22),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA23),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA24),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA25),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA26),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA27),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA28),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA29),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA30),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA31),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB0),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB1),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB2),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB3),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB4),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB5),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB6),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB7),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB8),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB9),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB10),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB11),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB12),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB13),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB14),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB15),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB16),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB17),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB18),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB19),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB20),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB21),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB22),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC0),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC1),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC2),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC3),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC4),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC5),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC6),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC7),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC8),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC9),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC10),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC11),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC12),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC13),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC14),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC15),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC16),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC17),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD31),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD30),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD29),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD28),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD27),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD26),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD25),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD24),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD23),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD22),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD21),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD20),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD19),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD18),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD17),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD16),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD0),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD1),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD2),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD3),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD4),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD5),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD6),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD7),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD8),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD9),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD10),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD11),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD12),
+       IMX_PINCTRL_PIN(VF610_PAD_PTD13),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB23),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB24),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB25),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB26),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB27),
+       IMX_PINCTRL_PIN(VF610_PAD_PTB28),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC26),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC27),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC28),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC29),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC30),
+       IMX_PINCTRL_PIN(VF610_PAD_PTC31),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE0),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE1),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE2),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE3),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE4),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE5),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE6),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE7),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE8),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE9),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE10),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE11),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE12),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE13),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE14),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE15),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE16),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE17),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE18),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE19),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE20),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE21),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE22),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE23),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE24),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE25),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE26),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE27),
+       IMX_PINCTRL_PIN(VF610_PAD_PTE28),
+       IMX_PINCTRL_PIN(VF610_PAD_PTA7),
+};
+
+static struct imx_pinctrl_soc_info vf610_pinctrl_info = {
+       .pins = vf610_pinctrl_pads,
+       .npins = ARRAY_SIZE(vf610_pinctrl_pads),
+       .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG,
+};
+
+static struct of_device_id vf610_pinctrl_of_match[] = {
+       { .compatible = "fsl,vf610-iomuxc", },
+       { /* sentinel */ }
+};
+
+static int vf610_pinctrl_probe(struct platform_device *pdev)
+{
+       return imx_pinctrl_probe(pdev, &vf610_pinctrl_info);
+}
+
+static struct platform_driver vf610_pinctrl_driver = {
+       .driver = {
+               .name = "vf610-pinctrl",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(vf610_pinctrl_of_match),
+       },
+       .probe = vf610_pinctrl_probe,
+       .remove = imx_pinctrl_remove,
+};
+
+static int __init vf610_pinctrl_init(void)
+{
+       return platform_driver_register(&vf610_pinctrl_driver);
+}
+arch_initcall(vf610_pinctrl_init);
+
+static void __exit vf610_pinctrl_exit(void)
+{
+       platform_driver_unregister(&vf610_pinctrl_driver);
+}
+module_exit(vf610_pinctrl_exit);
+
+MODULE_DESCRIPTION("Freescale VF610 pinctrl driver");
+MODULE_LICENSE("GPL v2");
index 3b2fd43ff2944ced1e8af02f1c8da50728816d0b..f3fc66b243701acc55faa8659e702dc69157ff34 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -348,14 +350,72 @@ int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id sh_pfc_of_table[] = {
+#ifdef CONFIG_PINCTRL_PFC_R8A73A4
+       {
+               .compatible = "renesas,pfc-r8a73a4",
+               .data = &r8a73a4_pinmux_info,
+       },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A7740
+       {
+               .compatible = "renesas,pfc-r8a7740",
+               .data = &r8a7740_pinmux_info,
+       },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A7778
+       {
+               .compatible = "renesas,pfc-r8a7778",
+               .data = &r8a7778_pinmux_info,
+       },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A7779
+       {
+               .compatible = "renesas,pfc-r8a7779",
+               .data = &r8a7779_pinmux_info,
+       },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A7790
+       {
+               .compatible = "renesas,pfc-r8a7790",
+               .data = &r8a7790_pinmux_info,
+       },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH7372
+       {
+               .compatible = "renesas,pfc-sh7372",
+               .data = &sh7372_pinmux_info,
+       },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_SH73A0
+       {
+               .compatible = "renesas,pfc-sh73a0",
+               .data = &sh73a0_pinmux_info,
+       },
+#endif
+       { },
+};
+MODULE_DEVICE_TABLE(of, sh_pfc_of_table);
+#endif
+
 static int sh_pfc_probe(struct platform_device *pdev)
 {
+       const struct platform_device_id *platid = platform_get_device_id(pdev);
+#ifdef CONFIG_OF
+       struct device_node *np = pdev->dev.of_node;
+#endif
        const struct sh_pfc_soc_info *info;
        struct sh_pfc *pfc;
        int ret;
 
-       info = pdev->id_entry->driver_data
-             ? (void *)pdev->id_entry->driver_data : pdev->dev.platform_data;
+#ifdef CONFIG_OF
+       if (np)
+               info = of_match_device(sh_pfc_of_table, &pdev->dev)->data;
+       else
+#endif
+               info = platid ? (const void *)platid->driver_data : NULL;
+
        if (info == NULL)
                return -ENODEV;
 
@@ -501,6 +561,7 @@ static struct platform_driver sh_pfc_driver = {
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(sh_pfc_of_table),
        },
 };
 
index 3492ec9a33b78ec760561e3dc63f642e3ea84c4a..bc8b028bb5d21eab5ce24a9bc19f83ec36309e0d 100644 (file)
@@ -14,7 +14,9 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -72,11 +74,214 @@ static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
        seq_printf(s, "%s", DRV_NAME);
 }
 
+#ifdef CONFIG_OF
+static int sh_pfc_map_add_config(struct pinctrl_map *map,
+                                const char *group_or_pin,
+                                enum pinctrl_map_type type,
+                                unsigned long *configs,
+                                unsigned int num_configs)
+{
+       unsigned long *cfgs;
+
+       cfgs = kmemdup(configs, num_configs * sizeof(*cfgs),
+                      GFP_KERNEL);
+       if (cfgs == NULL)
+               return -ENOMEM;
+
+       map->type = type;
+       map->data.configs.group_or_pin = group_or_pin;
+       map->data.configs.configs = cfgs;
+       map->data.configs.num_configs = num_configs;
+
+       return 0;
+}
+
+static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
+                                   struct pinctrl_map **map,
+                                   unsigned int *num_maps, unsigned int *index)
+{
+       struct pinctrl_map *maps = *map;
+       unsigned int nmaps = *num_maps;
+       unsigned int idx = *index;
+       unsigned int num_configs;
+       const char *function = NULL;
+       unsigned long *configs;
+       struct property *prop;
+       unsigned int num_groups;
+       unsigned int num_pins;
+       const char *group;
+       const char *pin;
+       int ret;
+
+       /* Parse the function and configuration properties. At least a function
+        * or one configuration must be specified.
+        */
+       ret = of_property_read_string(np, "renesas,function", &function);
+       if (ret < 0 && ret != -EINVAL) {
+               dev_err(dev, "Invalid function in DT\n");
+               return ret;
+       }
+
+       ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
+       if (ret < 0)
+               return ret;
+
+       if (!function && num_configs == 0) {
+               dev_err(dev,
+                       "DT node must contain at least a function or config\n");
+               goto done;
+       }
+
+       /* Count the number of pins and groups and reallocate mappings. */
+       ret = of_property_count_strings(np, "renesas,pins");
+       if (ret == -EINVAL) {
+               num_pins = 0;
+       } else if (ret < 0) {
+               dev_err(dev, "Invalid pins list in DT\n");
+               goto done;
+       } else {
+               num_pins = ret;
+       }
+
+       ret = of_property_count_strings(np, "renesas,groups");
+       if (ret == -EINVAL) {
+               num_groups = 0;
+       } else if (ret < 0) {
+               dev_err(dev, "Invalid pin groups list in DT\n");
+               goto done;
+       } else {
+               num_groups = ret;
+       }
+
+       if (!num_pins && !num_groups) {
+               dev_err(dev, "No pin or group provided in DT node\n");
+               ret = -ENODEV;
+               goto done;
+       }
+
+       if (function)
+               nmaps += num_groups;
+       if (configs)
+               nmaps += num_pins + num_groups;
+
+       maps = krealloc(maps, sizeof(*maps) * nmaps, GFP_KERNEL);
+       if (maps == NULL) {
+               ret = -ENOMEM;
+               goto done;
+       }
+
+       *map = maps;
+       *num_maps = nmaps;
+
+       /* Iterate over pins and groups and create the mappings. */
+       of_property_for_each_string(np, "renesas,groups", prop, group) {
+               if (function) {
+                       maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
+                       maps[idx].data.mux.group = group;
+                       maps[idx].data.mux.function = function;
+                       idx++;
+               }
+
+               if (configs) {
+                       ret = sh_pfc_map_add_config(&maps[idx], group,
+                                                   PIN_MAP_TYPE_CONFIGS_GROUP,
+                                                   configs, num_configs);
+                       if (ret < 0)
+                               goto done;
+
+                       idx++;
+               }
+       }
+
+       if (!configs) {
+               ret = 0;
+               goto done;
+       }
+
+       of_property_for_each_string(np, "renesas,pins", prop, pin) {
+               ret = sh_pfc_map_add_config(&maps[idx], pin,
+                                           PIN_MAP_TYPE_CONFIGS_PIN,
+                                           configs, num_configs);
+               if (ret < 0)
+                       goto done;
+
+               idx++;
+       }
+
+done:
+       *index = idx;
+       kfree(configs);
+       return ret;
+}
+
+static void sh_pfc_dt_free_map(struct pinctrl_dev *pctldev,
+                              struct pinctrl_map *map, unsigned num_maps)
+{
+       unsigned int i;
+
+       if (map == NULL)
+               return;
+
+       for (i = 0; i < num_maps; ++i) {
+               if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP ||
+                   map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+                       kfree(map[i].data.configs.configs);
+       }
+
+       kfree(map);
+}
+
+static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev,
+                                struct device_node *np,
+                                struct pinctrl_map **map, unsigned *num_maps)
+{
+       struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
+       struct device *dev = pmx->pfc->dev;
+       struct device_node *child;
+       unsigned int index;
+       int ret;
+
+       *map = NULL;
+       *num_maps = 0;
+       index = 0;
+
+       for_each_child_of_node(np, child) {
+               ret = sh_pfc_dt_subnode_to_map(dev, child, map, num_maps,
+                                              &index);
+               if (ret < 0)
+                       goto done;
+       }
+
+       /* If no mapping has been found in child nodes try the config node. */
+       if (*num_maps == 0) {
+               ret = sh_pfc_dt_subnode_to_map(dev, np, map, num_maps, &index);
+               if (ret < 0)
+                       goto done;
+       }
+
+       if (*num_maps)
+               return 0;
+
+       dev_err(dev, "no mapping found in node %s\n", np->full_name);
+       ret = -EINVAL;
+
+done:
+       if (ret < 0)
+               sh_pfc_dt_free_map(pctldev, *map, *num_maps);
+
+       return ret;
+}
+#endif /* CONFIG_OF */
+
 static const struct pinctrl_ops sh_pfc_pinctrl_ops = {
        .get_groups_count       = sh_pfc_get_groups_count,
        .get_group_name         = sh_pfc_get_group_name,
        .get_group_pins         = sh_pfc_get_group_pins,
        .pin_dbg_show           = sh_pfc_pin_dbg_show,
+#ifdef CONFIG_OF
+       .dt_node_to_map         = sh_pfc_dt_node_to_map,
+       .dt_free_map            = sh_pfc_dt_free_map,
+#endif
 };
 
 static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev)
diff --git a/drivers/pinctrl/sirf/Makefile b/drivers/pinctrl/sirf/Makefile
new file mode 100644 (file)
index 0000000..3ffc475
--- /dev/null
@@ -0,0 +1,5 @@
+# CSR SiRFsoc pinmux support
+
+obj-y  += pinctrl-sirf.o
+obj-y  += pinctrl-prima2.o
+obj-y  += pinctrl-atlas6.o
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas6.c b/drivers/pinctrl/sirf/pinctrl-atlas6.c
new file mode 100644 (file)
index 0000000..1fa39a4
--- /dev/null
@@ -0,0 +1,947 @@
+/*
+ * pinctrl pads, groups, functions for CSR SiRFatlasVI
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/bitops.h>
+
+#include "pinctrl-sirf.h"
+
+/*
+ * pad list for the pinmux subsystem
+ * refer to atlasVI_io_table_v0.93.xls
+ */
+static const struct pinctrl_pin_desc sirfsoc_pads[] = {
+       PINCTRL_PIN(0, "gpio0-0"),
+       PINCTRL_PIN(1, "gpio0-1"),
+       PINCTRL_PIN(2, "gpio0-2"),
+       PINCTRL_PIN(3, "gpio0-3"),
+       PINCTRL_PIN(4, "pwm0"),
+       PINCTRL_PIN(5, "pwm1"),
+       PINCTRL_PIN(6, "pwm2"),
+       PINCTRL_PIN(7, "pwm3"),
+       PINCTRL_PIN(8, "warm_rst_b"),
+       PINCTRL_PIN(9, "odo_0"),
+       PINCTRL_PIN(10, "odo_1"),
+       PINCTRL_PIN(11, "dr_dir"),
+       PINCTRL_PIN(12, "rts_0"),
+       PINCTRL_PIN(13, "scl_1"),
+       PINCTRL_PIN(14, "ntrst"),
+       PINCTRL_PIN(15, "sda_1"),
+       PINCTRL_PIN(16, "x_ldd[16]"),
+       PINCTRL_PIN(17, "x_ldd[17]"),
+       PINCTRL_PIN(18, "x_ldd[18]"),
+       PINCTRL_PIN(19, "x_ldd[19]"),
+       PINCTRL_PIN(20, "x_ldd[20]"),
+       PINCTRL_PIN(21, "x_ldd[21]"),
+       PINCTRL_PIN(22, "x_ldd[22]"),
+       PINCTRL_PIN(23, "x_ldd[23]"),
+       PINCTRL_PIN(24, "gps_sgn"),
+       PINCTRL_PIN(25, "gps_mag"),
+       PINCTRL_PIN(26, "gps_clk"),
+       PINCTRL_PIN(27, "sd_cd_b_2"),
+       PINCTRL_PIN(28, "sd_vcc_on_2"),
+       PINCTRL_PIN(29, "sd_wp_b_2"),
+       PINCTRL_PIN(30, "sd_clk_3"),
+       PINCTRL_PIN(31, "sd_cmd_3"),
+
+       PINCTRL_PIN(32, "x_sd_dat_3[0]"),
+       PINCTRL_PIN(33, "x_sd_dat_3[1]"),
+       PINCTRL_PIN(34, "x_sd_dat_3[2]"),
+       PINCTRL_PIN(35, "x_sd_dat_3[3]"),
+       PINCTRL_PIN(36, "usb_clk"),
+       PINCTRL_PIN(37, "usb_dir"),
+       PINCTRL_PIN(38, "usb_nxt"),
+       PINCTRL_PIN(39, "usb_stp"),
+       PINCTRL_PIN(40, "usb_dat[7]"),
+       PINCTRL_PIN(41, "usb_dat[6]"),
+       PINCTRL_PIN(42, "x_cko_1"),
+       PINCTRL_PIN(43, "spi_clk_1"),
+       PINCTRL_PIN(44, "spi_dout_1"),
+       PINCTRL_PIN(45, "spi_din_1"),
+       PINCTRL_PIN(46, "spi_en_1"),
+       PINCTRL_PIN(47, "x_txd_1"),
+       PINCTRL_PIN(48, "x_txd_2"),
+       PINCTRL_PIN(49, "x_rxd_1"),
+       PINCTRL_PIN(50, "x_rxd_2"),
+       PINCTRL_PIN(51, "x_usclk_0"),
+       PINCTRL_PIN(52, "x_utxd_0"),
+       PINCTRL_PIN(53, "x_urxd_0"),
+       PINCTRL_PIN(54, "x_utfs_0"),
+       PINCTRL_PIN(55, "x_urfs_0"),
+       PINCTRL_PIN(56, "usb_dat5"),
+       PINCTRL_PIN(57, "usb_dat4"),
+       PINCTRL_PIN(58, "usb_dat3"),
+       PINCTRL_PIN(59, "usb_dat2"),
+       PINCTRL_PIN(60, "usb_dat1"),
+       PINCTRL_PIN(61, "usb_dat0"),
+       PINCTRL_PIN(62, "x_ldd[14]"),
+       PINCTRL_PIN(63, "x_ldd[15]"),
+
+       PINCTRL_PIN(64, "x_gps_gpio"),
+       PINCTRL_PIN(65, "x_ldd[13]"),
+       PINCTRL_PIN(66, "x_df_we_b"),
+       PINCTRL_PIN(67, "x_df_re_b"),
+       PINCTRL_PIN(68, "x_txd_0"),
+       PINCTRL_PIN(69, "x_rxd_0"),
+       PINCTRL_PIN(70, "x_l_lck"),
+       PINCTRL_PIN(71, "x_l_fck"),
+       PINCTRL_PIN(72, "x_l_de"),
+       PINCTRL_PIN(73, "x_ldd[0]"),
+       PINCTRL_PIN(74, "x_ldd[1]"),
+       PINCTRL_PIN(75, "x_ldd[2]"),
+       PINCTRL_PIN(76, "x_ldd[3]"),
+       PINCTRL_PIN(77, "x_ldd[4]"),
+       PINCTRL_PIN(78, "x_cko_0"),
+       PINCTRL_PIN(79, "x_ldd[5]"),
+       PINCTRL_PIN(80, "x_ldd[6]"),
+       PINCTRL_PIN(81, "x_ldd[7]"),
+       PINCTRL_PIN(82, "x_ldd[8]"),
+       PINCTRL_PIN(83, "x_ldd[9]"),
+       PINCTRL_PIN(84, "x_ldd[10]"),
+       PINCTRL_PIN(85, "x_ldd[11]"),
+       PINCTRL_PIN(86, "x_ldd[12]"),
+       PINCTRL_PIN(87, "x_vip_vsync"),
+       PINCTRL_PIN(88, "x_vip_hsync"),
+       PINCTRL_PIN(89, "x_vip_pxclk"),
+       PINCTRL_PIN(90, "x_sda_0"),
+       PINCTRL_PIN(91, "x_scl_0"),
+       PINCTRL_PIN(92, "x_df_ry_by"),
+       PINCTRL_PIN(93, "x_df_cs_b[1]"),
+       PINCTRL_PIN(94, "x_df_cs_b[0]"),
+       PINCTRL_PIN(95, "x_l_pclk"),
+
+       PINCTRL_PIN(96, "x_df_dqs"),
+       PINCTRL_PIN(97, "x_df_wp_b"),
+       PINCTRL_PIN(98, "ac97_sync"),
+       PINCTRL_PIN(99, "ac97_bit_clk "),
+       PINCTRL_PIN(100, "ac97_dout"),
+       PINCTRL_PIN(101, "ac97_din"),
+       PINCTRL_PIN(102, "x_rtc_io"),
+};
+
+static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(30) | BIT(31),
+       }, {
+               .group = 2,
+               .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) |
+                       BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) |
+                       BIT(20) | BIT(21) | BIT(22) | BIT(31),
+       },
+};
+
+static const struct sirfsoc_padmux lcd_16bits_padmux = {
+       .muxmask_counts = ARRAY_SIZE(lcd_16bits_sirfsoc_muxmask),
+       .muxmask = lcd_16bits_sirfsoc_muxmask,
+       .funcmask = BIT(4),
+       .funcval = 0,
+};
+
+static const unsigned lcd_16bits_pins[] = { 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83,
+       84, 85, 86, 95 };
+
+static const struct sirfsoc_muxmask lcd_18bits_muxmask[] = {
+       {
+               .group = 2,
+               .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) |
+                       BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) |
+                       BIT(20) | BIT(21) | BIT(22) | BIT(31),
+       }, {
+               .group = 1,
+               .mask = BIT(30) | BIT(31),
+       }, {
+               .group = 0,
+               .mask = BIT(16) | BIT(17),
+       },
+};
+
+static const struct sirfsoc_padmux lcd_18bits_padmux = {
+       .muxmask_counts = ARRAY_SIZE(lcd_18bits_muxmask),
+       .muxmask = lcd_18bits_muxmask,
+       .funcmask = BIT(4) | BIT(15),
+       .funcval = 0,
+};
+
+static const unsigned lcd_18bits_pins[] = { 16, 17, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83,
+       84, 85, 86, 95 };
+
+static const struct sirfsoc_muxmask lcd_24bits_muxmask[] = {
+       {
+               .group = 2,
+               .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) |
+                       BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) |
+                       BIT(20) | BIT(21) | BIT(22) | BIT(31),
+       }, {
+               .group = 1,
+               .mask = BIT(30) | BIT(31),
+       }, {
+               .group = 0,
+               .mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23),
+       },
+};
+
+static const struct sirfsoc_padmux lcd_24bits_padmux = {
+       .muxmask_counts = ARRAY_SIZE(lcd_24bits_muxmask),
+       .muxmask = lcd_24bits_muxmask,
+       .funcmask = BIT(4) | BIT(15),
+       .funcval = 0,
+};
+
+static const unsigned lcd_24bits_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79,
+       80, 81, 82, 83, 84, 85, 86, 95};
+
+static const struct sirfsoc_muxmask lcdrom_muxmask[] = {
+       {
+               .group = 2,
+               .mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) |
+                       BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) |
+                       BIT(20) | BIT(21) | BIT(22) | BIT(31),
+       }, {
+               .group = 1,
+               .mask = BIT(30) | BIT(31),
+       }, {
+               .group = 0,
+               .mask = BIT(8),
+       },
+};
+
+static const struct sirfsoc_padmux lcdrom_padmux = {
+       .muxmask_counts = ARRAY_SIZE(lcdrom_muxmask),
+       .muxmask = lcdrom_muxmask,
+       .funcmask = BIT(4),
+       .funcval = BIT(4),
+};
+
+static const unsigned lcdrom_pins[] = { 8, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83,
+       84, 85, 86, 95};
+
+static const struct sirfsoc_muxmask uart0_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(12),
+       }, {
+               .group = 1,
+               .mask = BIT(23),
+       }, {
+               .group = 2,
+               .mask = BIT(4) | BIT(5),
+       },
+};
+
+static const struct sirfsoc_padmux uart0_padmux = {
+       .muxmask_counts = ARRAY_SIZE(uart0_muxmask),
+       .muxmask = uart0_muxmask,
+       .funcmask = BIT(9),
+       .funcval = BIT(9),
+};
+
+static const unsigned uart0_pins[] = { 12, 55, 68, 69 };
+
+static const struct sirfsoc_muxmask uart0_nostreamctrl_muxmask[] = {
+       {
+               .group = 2,
+               .mask = BIT(4) | BIT(5),
+       },
+};
+
+static const struct sirfsoc_padmux uart0_nostreamctrl_padmux = {
+       .muxmask_counts = ARRAY_SIZE(uart0_nostreamctrl_muxmask),
+       .muxmask = uart0_nostreamctrl_muxmask,
+};
+
+static const unsigned uart0_nostreamctrl_pins[] = { 68, 69 };
+
+static const struct sirfsoc_muxmask uart1_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(15) | BIT(17),
+       },
+};
+
+static const struct sirfsoc_padmux uart1_padmux = {
+       .muxmask_counts = ARRAY_SIZE(uart1_muxmask),
+       .muxmask = uart1_muxmask,
+};
+
+static const unsigned uart1_pins[] = { 47, 49 };
+
+static const struct sirfsoc_muxmask uart2_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(10) | BIT(14),
+       }, {
+               .group = 1,
+               .mask = BIT(16) | BIT(18),
+       },
+};
+
+static const struct sirfsoc_padmux uart2_padmux = {
+       .muxmask_counts = ARRAY_SIZE(uart2_muxmask),
+       .muxmask = uart2_muxmask,
+       .funcmask = BIT(10),
+       .funcval = BIT(10),
+};
+
+static const unsigned uart2_pins[] = { 10, 14, 48, 50 };
+
+static const struct sirfsoc_muxmask uart2_nostreamctrl_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(16) | BIT(18),
+       },
+};
+
+static const struct sirfsoc_padmux uart2_nostreamctrl_padmux = {
+       .muxmask_counts = ARRAY_SIZE(uart2_nostreamctrl_muxmask),
+       .muxmask = uart2_nostreamctrl_muxmask,
+};
+
+static const unsigned uart2_nostreamctrl_pins[] = { 48, 50 };
+
+static const struct sirfsoc_muxmask sdmmc3_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(30) | BIT(31),
+       }, {
+               .group = 1,
+               .mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
+       },
+};
+
+static const struct sirfsoc_padmux sdmmc3_padmux = {
+       .muxmask_counts = ARRAY_SIZE(sdmmc3_muxmask),
+       .muxmask = sdmmc3_muxmask,
+       .funcmask = BIT(7),
+       .funcval = 0,
+};
+
+static const unsigned sdmmc3_pins[] = { 30, 31, 32, 33, 34, 35 };
+
+static const struct sirfsoc_muxmask spi0_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(30),
+       }, {
+               .group = 1,
+               .mask = BIT(0) | BIT(2) | BIT(3),
+       },
+};
+
+static const struct sirfsoc_padmux spi0_padmux = {
+       .muxmask_counts = ARRAY_SIZE(spi0_muxmask),
+       .muxmask = spi0_muxmask,
+       .funcmask = BIT(7),
+       .funcval = BIT(7),
+};
+
+static const unsigned spi0_pins[] = { 30, 32, 34, 35 };
+
+static const struct sirfsoc_muxmask cko1_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(10),
+       },
+};
+
+static const struct sirfsoc_padmux cko1_padmux = {
+       .muxmask_counts = ARRAY_SIZE(cko1_muxmask),
+       .muxmask = cko1_muxmask,
+       .funcmask = BIT(3),
+       .funcval = 0,
+};
+
+static const unsigned cko1_pins[] = { 42 };
+
+static const struct sirfsoc_muxmask i2s_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(10),
+       }, {
+               .group = 3,
+               .mask = BIT(2) | BIT(3) | BIT(4) | BIT(5),
+       },
+};
+
+static const struct sirfsoc_padmux i2s_padmux = {
+       .muxmask_counts = ARRAY_SIZE(i2s_muxmask),
+       .muxmask = i2s_muxmask,
+       .funcmask = BIT(3),
+       .funcval = BIT(3),
+};
+
+static const unsigned i2s_pins[] = { 42, 98, 99, 100, 101 };
+
+static const struct sirfsoc_muxmask i2s_no_din_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(10),
+       }, {
+               .group = 3,
+               .mask = BIT(2) | BIT(3) | BIT(4),
+       },
+};
+
+static const struct sirfsoc_padmux i2s_no_din_padmux = {
+       .muxmask_counts = ARRAY_SIZE(i2s_no_din_muxmask),
+       .muxmask = i2s_no_din_muxmask,
+       .funcmask = BIT(3),
+       .funcval = BIT(3),
+};
+
+static const unsigned i2s_no_din_pins[] = { 42, 98, 99, 100 };
+
+static const struct sirfsoc_muxmask i2s_6chn_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(10) | BIT(20) | BIT(23),
+       }, {
+               .group = 3,
+               .mask = BIT(2) | BIT(3) | BIT(4) | BIT(5),
+       },
+};
+
+static const struct sirfsoc_padmux i2s_6chn_padmux = {
+       .muxmask_counts = ARRAY_SIZE(i2s_6chn_muxmask),
+       .muxmask = i2s_6chn_muxmask,
+       .funcmask = BIT(1) | BIT(3) | BIT(9),
+       .funcval = BIT(1) | BIT(3) | BIT(9),
+};
+
+static const unsigned i2s_6chn_pins[] = { 42, 52, 55, 98, 99, 100, 101 };
+
+static const struct sirfsoc_muxmask ac97_muxmask[] = {
+       {
+               .group = 3,
+               .mask = BIT(2) | BIT(3) | BIT(4) | BIT(5),
+       },
+};
+
+static const struct sirfsoc_padmux ac97_padmux = {
+       .muxmask_counts = ARRAY_SIZE(ac97_muxmask),
+       .muxmask = ac97_muxmask,
+};
+
+static const unsigned ac97_pins[] = { 98, 99, 100, 101 };
+
+static const struct sirfsoc_muxmask spi1_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
+       },
+};
+
+static const struct sirfsoc_padmux spi1_padmux = {
+       .muxmask_counts = ARRAY_SIZE(spi1_muxmask),
+       .muxmask = spi1_muxmask,
+       .funcmask = BIT(16),
+       .funcval = 0,
+};
+
+static const unsigned spi1_pins[] = { 43, 44, 45, 46 };
+
+static const struct sirfsoc_muxmask sdmmc1_muxmask[] = {
+       {
+               .group = 2,
+               .mask = BIT(2) | BIT(3),
+       },
+};
+
+static const struct sirfsoc_padmux sdmmc1_padmux = {
+       .muxmask_counts = ARRAY_SIZE(sdmmc1_muxmask),
+       .muxmask = sdmmc1_muxmask,
+       .funcmask = BIT(5),
+       .funcval = BIT(5),
+};
+
+static const unsigned sdmmc1_pins[] = { 66, 67 };
+
+static const struct sirfsoc_muxmask gps_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(24) | BIT(25) | BIT(26),
+       },
+};
+
+static const struct sirfsoc_padmux gps_padmux = {
+       .muxmask_counts = ARRAY_SIZE(gps_muxmask),
+       .muxmask = gps_muxmask,
+       .funcmask = BIT(13),
+       .funcval = 0,
+};
+
+static const unsigned gps_pins[] = { 24, 25, 26 };
+
+static const struct sirfsoc_muxmask sdmmc5_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(24) | BIT(25) | BIT(26),
+       },
+};
+
+static const struct sirfsoc_padmux sdmmc5_padmux = {
+       .muxmask_counts = ARRAY_SIZE(sdmmc5_muxmask),
+       .muxmask = sdmmc5_muxmask,
+       .funcmask = BIT(13),
+       .funcval = BIT(13),
+};
+
+static const unsigned sdmmc5_pins[] = { 24, 25, 26 };
+
+static const struct sirfsoc_muxmask usp0_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(19) | BIT(20) | BIT(21) | BIT(22),
+       },
+};
+
+static const struct sirfsoc_padmux usp0_padmux = {
+       .muxmask_counts = ARRAY_SIZE(usp0_muxmask),
+       .muxmask = usp0_muxmask,
+       .funcmask = BIT(1) | BIT(2) | BIT(9),
+       .funcval = 0,
+};
+
+static const unsigned usp0_pins[] = { 51, 52, 53, 54 };
+
+static const struct sirfsoc_muxmask usp1_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(15),
+       }, {
+               .group = 1,
+               .mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
+       },
+};
+
+static const struct sirfsoc_padmux usp1_padmux = {
+       .muxmask_counts = ARRAY_SIZE(usp1_muxmask),
+       .muxmask = usp1_muxmask,
+       .funcmask = BIT(16),
+       .funcval = BIT(16),
+};
+
+static const unsigned usp1_pins[] = { 15, 43, 44, 45, 46 };
+
+static const struct sirfsoc_muxmask nand_muxmask[] = {
+       {
+               .group = 2,
+               .mask = BIT(2) | BIT(3) | BIT(28) | BIT(29) | BIT(30),
+       }, {
+               .group = 3,
+               .mask = BIT(0) | BIT(1),
+       },
+};
+
+static const struct sirfsoc_padmux nand_padmux = {
+       .muxmask_counts = ARRAY_SIZE(nand_muxmask),
+       .muxmask = nand_muxmask,
+       .funcmask = BIT(5) | BIT(19),
+       .funcval = 0,
+};
+
+static const unsigned nand_pins[] = { 66, 67, 92, 93, 94, 96, 97 };
+
+static const struct sirfsoc_muxmask sdmmc0_muxmask[] = {
+       {
+               .group = 3,
+               .mask = BIT(1),
+       },
+};
+
+static const struct sirfsoc_padmux sdmmc0_padmux = {
+       .muxmask_counts = ARRAY_SIZE(sdmmc0_muxmask),
+       .muxmask = sdmmc0_muxmask,
+       .funcmask = BIT(5) | BIT(19),
+       .funcval = BIT(19),
+};
+
+static const unsigned sdmmc0_pins[] = { 97 };
+
+static const struct sirfsoc_muxmask sdmmc2_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(27) | BIT(28) | BIT(29),
+       },
+};
+
+static const struct sirfsoc_padmux sdmmc2_padmux = {
+       .muxmask_counts = ARRAY_SIZE(sdmmc2_muxmask),
+       .muxmask = sdmmc2_muxmask,
+       .funcmask = BIT(11),
+       .funcval = 0,
+};
+
+static const unsigned sdmmc2_pins[] = { 27, 28, 29 };
+
+static const struct sirfsoc_muxmask sdmmc2_nowp_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(27) | BIT(28),
+       },
+};
+
+static const struct sirfsoc_padmux sdmmc2_nowp_padmux = {
+       .muxmask_counts = ARRAY_SIZE(sdmmc2_nowp_muxmask),
+       .muxmask = sdmmc2_nowp_muxmask,
+       .funcmask = BIT(11),
+       .funcval = 0,
+};
+
+static const unsigned sdmmc2_nowp_pins[] = { 27, 28 };
+
+static const struct sirfsoc_muxmask cko0_muxmask[] = {
+       {
+               .group = 2,
+               .mask = BIT(14),
+       },
+};
+
+static const struct sirfsoc_padmux cko0_padmux = {
+       .muxmask_counts = ARRAY_SIZE(cko0_muxmask),
+       .muxmask = cko0_muxmask,
+};
+
+static const unsigned cko0_pins[] = { 78 };
+
+static const struct sirfsoc_muxmask vip_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(4) | BIT(5) | BIT(6) | BIT(8) | BIT(9)
+                       | BIT(24) | BIT(25) | BIT(26) | BIT(27) | BIT(28) |
+                       BIT(29),
+       },
+};
+
+static const struct sirfsoc_padmux vip_padmux = {
+       .muxmask_counts = ARRAY_SIZE(vip_muxmask),
+       .muxmask = vip_muxmask,
+       .funcmask = BIT(18),
+       .funcval = BIT(18),
+};
+
+static const unsigned vip_pins[] = { 36, 37, 38, 40, 41, 56, 57, 58, 59, 60, 61 };
+
+static const struct sirfsoc_muxmask vip_noupli_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20)
+                       | BIT(21) | BIT(22) | BIT(23),
+       }, {
+               .group = 2,
+               .mask = BIT(23) | BIT(24) | BIT(25),
+       },
+};
+
+static const struct sirfsoc_padmux vip_noupli_padmux = {
+       .muxmask_counts = ARRAY_SIZE(vip_noupli_muxmask),
+       .muxmask = vip_noupli_muxmask,
+       .funcmask = BIT(15),
+       .funcval = BIT(15),
+};
+
+static const unsigned vip_noupli_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 87, 88, 89 };
+
+static const struct sirfsoc_muxmask i2c0_muxmask[] = {
+       {
+               .group = 2,
+               .mask = BIT(26) | BIT(27),
+       },
+};
+
+static const struct sirfsoc_padmux i2c0_padmux = {
+       .muxmask_counts = ARRAY_SIZE(i2c0_muxmask),
+       .muxmask = i2c0_muxmask,
+};
+
+static const unsigned i2c0_pins[] = { 90, 91 };
+
+static const struct sirfsoc_muxmask i2c1_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(13) | BIT(15),
+       },
+};
+
+static const struct sirfsoc_padmux i2c1_padmux = {
+       .muxmask_counts = ARRAY_SIZE(i2c1_muxmask),
+       .muxmask = i2c1_muxmask,
+       .funcmask = BIT(16),
+       .funcval = 0,
+};
+
+static const unsigned i2c1_pins[] = { 13, 15 };
+
+static const struct sirfsoc_muxmask pwm0_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(4),
+       },
+};
+
+static const struct sirfsoc_padmux pwm0_padmux = {
+       .muxmask_counts = ARRAY_SIZE(pwm0_muxmask),
+       .muxmask = pwm0_muxmask,
+       .funcmask = BIT(12),
+       .funcval = 0,
+};
+
+static const unsigned pwm0_pins[] = { 4 };
+
+static const struct sirfsoc_muxmask pwm1_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(5),
+       },
+};
+
+static const struct sirfsoc_padmux pwm1_padmux = {
+       .muxmask_counts = ARRAY_SIZE(pwm1_muxmask),
+       .muxmask = pwm1_muxmask,
+};
+
+static const unsigned pwm1_pins[] = { 5 };
+
+static const struct sirfsoc_muxmask pwm2_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(6),
+       },
+};
+
+static const struct sirfsoc_padmux pwm2_padmux = {
+       .muxmask_counts = ARRAY_SIZE(pwm2_muxmask),
+       .muxmask = pwm2_muxmask,
+};
+
+static const unsigned pwm2_pins[] = { 6 };
+
+static const struct sirfsoc_muxmask pwm3_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(7),
+       },
+};
+
+static const struct sirfsoc_padmux pwm3_padmux = {
+       .muxmask_counts = ARRAY_SIZE(pwm3_muxmask),
+       .muxmask = pwm3_muxmask,
+};
+
+static const unsigned pwm3_pins[] = { 7 };
+
+static const struct sirfsoc_muxmask pwm4_muxmask[] = {
+       {
+               .group = 2,
+               .mask = BIT(14),
+       },
+};
+
+static const struct sirfsoc_padmux pwm4_padmux = {
+       .muxmask_counts = ARRAY_SIZE(pwm4_muxmask),
+       .muxmask = pwm4_muxmask,
+};
+
+static const unsigned pwm4_pins[] = { 78 };
+
+static const struct sirfsoc_muxmask warm_rst_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(8),
+       },
+};
+
+static const struct sirfsoc_padmux warm_rst_padmux = {
+       .muxmask_counts = ARRAY_SIZE(warm_rst_muxmask),
+       .muxmask = warm_rst_muxmask,
+       .funcmask = BIT(4),
+       .funcval = 0,
+};
+
+static const unsigned warm_rst_pins[] = { 8 };
+
+static const struct sirfsoc_muxmask usb0_upli_drvbus_muxmask[] = {
+       {
+               .group = 1,
+               .mask = BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8)
+                       | BIT(9) | BIT(24) | BIT(25) | BIT(26) |
+                       BIT(27) | BIT(28) | BIT(29),
+       },
+};
+static const struct sirfsoc_padmux usb0_upli_drvbus_padmux = {
+       .muxmask_counts = ARRAY_SIZE(usb0_upli_drvbus_muxmask),
+       .muxmask = usb0_upli_drvbus_muxmask,
+       .funcmask = BIT(18),
+       .funcval = 0,
+};
+
+static const unsigned usb0_upli_drvbus_pins[] = { 36, 37, 38, 39, 40, 41, 56, 57, 58, 59, 60, 61 };
+
+static const struct sirfsoc_muxmask usb1_utmi_drvbus_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(28),
+       },
+};
+
+static const struct sirfsoc_padmux usb1_utmi_drvbus_padmux = {
+       .muxmask_counts = ARRAY_SIZE(usb1_utmi_drvbus_muxmask),
+       .muxmask = usb1_utmi_drvbus_muxmask,
+       .funcmask = BIT(11),
+       .funcval = BIT(11), /* refer to PAD_UTMI_DRVVBUS1_ENABLE */
+};
+
+static const unsigned usb1_utmi_drvbus_pins[] = { 28 };
+
+static const struct sirfsoc_muxmask pulse_count_muxmask[] = {
+       {
+               .group = 0,
+               .mask = BIT(9) | BIT(10) | BIT(11),
+       },
+};
+
+static const struct sirfsoc_padmux pulse_count_padmux = {
+       .muxmask_counts = ARRAY_SIZE(pulse_count_muxmask),
+       .muxmask = pulse_count_muxmask,
+};
+
+static const unsigned pulse_count_pins[] = { 9, 10, 11 };
+
+static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
+       SIRFSOC_PIN_GROUP("lcd_16bitsgrp", lcd_16bits_pins),
+       SIRFSOC_PIN_GROUP("lcd_18bitsgrp", lcd_18bits_pins),
+       SIRFSOC_PIN_GROUP("lcd_24bitsgrp", lcd_24bits_pins),
+       SIRFSOC_PIN_GROUP("lcdrom_grp", lcdrom_pins),
+       SIRFSOC_PIN_GROUP("uart0grp", uart0_pins),
+       SIRFSOC_PIN_GROUP("uart1grp", uart1_pins),
+       SIRFSOC_PIN_GROUP("uart2grp", uart2_pins),
+       SIRFSOC_PIN_GROUP("uart2_nostreamctrlgrp", uart2_nostreamctrl_pins),
+       SIRFSOC_PIN_GROUP("usp0grp", usp0_pins),
+       SIRFSOC_PIN_GROUP("usp1grp", usp1_pins),
+       SIRFSOC_PIN_GROUP("i2c0grp", i2c0_pins),
+       SIRFSOC_PIN_GROUP("i2c1grp", i2c1_pins),
+       SIRFSOC_PIN_GROUP("pwm0grp", pwm0_pins),
+       SIRFSOC_PIN_GROUP("pwm1grp", pwm1_pins),
+       SIRFSOC_PIN_GROUP("pwm2grp", pwm2_pins),
+       SIRFSOC_PIN_GROUP("pwm3grp", pwm3_pins),
+       SIRFSOC_PIN_GROUP("pwm4grp", pwm4_pins),
+       SIRFSOC_PIN_GROUP("vipgrp", vip_pins),
+       SIRFSOC_PIN_GROUP("vip_noupligrp", vip_noupli_pins),
+       SIRFSOC_PIN_GROUP("warm_rstgrp", warm_rst_pins),
+       SIRFSOC_PIN_GROUP("cko0grp", cko0_pins),
+       SIRFSOC_PIN_GROUP("cko1grp", cko1_pins),
+       SIRFSOC_PIN_GROUP("sdmmc0grp", sdmmc0_pins),
+       SIRFSOC_PIN_GROUP("sdmmc1grp", sdmmc1_pins),
+       SIRFSOC_PIN_GROUP("sdmmc2grp", sdmmc2_pins),
+       SIRFSOC_PIN_GROUP("sdmmc2_nowpgrp", sdmmc2_nowp_pins),
+       SIRFSOC_PIN_GROUP("sdmmc3grp", sdmmc3_pins),
+       SIRFSOC_PIN_GROUP("sdmmc5grp", sdmmc5_pins),
+       SIRFSOC_PIN_GROUP("usb0_upli_drvbusgrp", usb0_upli_drvbus_pins),
+       SIRFSOC_PIN_GROUP("usb1_utmi_drvbusgrp", usb1_utmi_drvbus_pins),
+       SIRFSOC_PIN_GROUP("pulse_countgrp", pulse_count_pins),
+       SIRFSOC_PIN_GROUP("i2sgrp", i2s_pins),
+       SIRFSOC_PIN_GROUP("i2s_no_dingrp", i2s_no_din_pins),
+       SIRFSOC_PIN_GROUP("i2s_6chngrp", i2s_6chn_pins),
+       SIRFSOC_PIN_GROUP("ac97grp", ac97_pins),
+       SIRFSOC_PIN_GROUP("nandgrp", nand_pins),
+       SIRFSOC_PIN_GROUP("spi0grp", spi0_pins),
+       SIRFSOC_PIN_GROUP("spi1grp", spi1_pins),
+       SIRFSOC_PIN_GROUP("gpsgrp", gps_pins),
+};
+
+static const char * const lcd_16bitsgrp[] = { "lcd_16bitsgrp" };
+static const char * const lcd_18bitsgrp[] = { "lcd_18bitsgrp" };
+static const char * const lcd_24bitsgrp[] = { "lcd_24bitsgrp" };
+static const char * const lcdromgrp[] = { "lcdromgrp" };
+static const char * const uart0grp[] = { "uart0grp" };
+static const char * const uart1grp[] = { "uart1grp" };
+static const char * const uart2grp[] = { "uart2grp" };
+static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" };
+static const char * const usp0grp[] = { "usp0grp" };
+static const char * const usp1grp[] = { "usp1grp" };
+static const char * const i2c0grp[] = { "i2c0grp" };
+static const char * const i2c1grp[] = { "i2c1grp" };
+static const char * const pwm0grp[] = { "pwm0grp" };
+static const char * const pwm1grp[] = { "pwm1grp" };
+static const char * const pwm2grp[] = { "pwm2grp" };
+static const char * const pwm3grp[] = { "pwm3grp" };
+static const char * const pwm4grp[] = { "pwm4grp" };
+static const char * const vipgrp[] = { "vipgrp" };
+static const char * const vip_noupligrp[] = { "vip_noupligrp" };
+static const char * const warm_rstgrp[] = { "warm_rstgrp" };
+static const char * const cko0grp[] = { "cko0grp" };
+static const char * const cko1grp[] = { "cko1grp" };
+static const char * const sdmmc0grp[] = { "sdmmc0grp" };
+static const char * const sdmmc1grp[] = { "sdmmc1grp" };
+static const char * const sdmmc2grp[] = { "sdmmc2grp" };
+static const char * const sdmmc3grp[] = { "sdmmc3grp" };
+static const char * const sdmmc5grp[] = { "sdmmc5grp" };
+static const char * const sdmmc2_nowpgrp[] = { "sdmmc2_nowpgrp" };
+static const char * const usb0_upli_drvbusgrp[] = { "usb0_upli_drvbusgrp" };
+static const char * const usb1_utmi_drvbusgrp[] = { "usb1_utmi_drvbusgrp" };
+static const char * const pulse_countgrp[] = { "pulse_countgrp" };
+static const char * const i2sgrp[] = { "i2sgrp" };
+static const char * const i2s_no_dingrp[] = { "i2s_no_dingrp" };
+static const char * const i2s_6chngrp[] = { "i2s_6chngrp" };
+static const char * const ac97grp[] = { "ac97grp" };
+static const char * const nandgrp[] = { "nandgrp" };
+static const char * const spi0grp[] = { "spi0grp" };
+static const char * const spi1grp[] = { "spi1grp" };
+static const char * const gpsgrp[] = { "gpsgrp" };
+
+static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = {
+       SIRFSOC_PMX_FUNCTION("lcd_16bits", lcd_16bitsgrp, lcd_16bits_padmux),
+       SIRFSOC_PMX_FUNCTION("lcd_18bits", lcd_18bitsgrp, lcd_18bits_padmux),
+       SIRFSOC_PMX_FUNCTION("lcd_24bits", lcd_24bitsgrp, lcd_24bits_padmux),
+       SIRFSOC_PMX_FUNCTION("lcdrom", lcdromgrp, lcdrom_padmux),
+       SIRFSOC_PMX_FUNCTION("uart0", uart0grp, uart0_padmux),
+       SIRFSOC_PMX_FUNCTION("uart1", uart1grp, uart1_padmux),
+       SIRFSOC_PMX_FUNCTION("uart2", uart2grp, uart2_padmux),
+       SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux),
+       SIRFSOC_PMX_FUNCTION("usp0", usp0grp, usp0_padmux),
+       SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux),
+       SIRFSOC_PMX_FUNCTION("i2c0", i2c0grp, i2c0_padmux),
+       SIRFSOC_PMX_FUNCTION("i2c1", i2c1grp, i2c1_padmux),
+       SIRFSOC_PMX_FUNCTION("pwm0", pwm0grp, pwm0_padmux),
+       SIRFSOC_PMX_FUNCTION("pwm1", pwm1grp, pwm1_padmux),
+       SIRFSOC_PMX_FUNCTION("pwm2", pwm2grp, pwm2_padmux),
+       SIRFSOC_PMX_FUNCTION("pwm3", pwm3grp, pwm3_padmux),
+       SIRFSOC_PMX_FUNCTION("pwm4", pwm4grp, pwm4_padmux),
+       SIRFSOC_PMX_FUNCTION("vip", vipgrp, vip_padmux),
+       SIRFSOC_PMX_FUNCTION("vip_noupli", vip_noupligrp, vip_noupli_padmux),
+       SIRFSOC_PMX_FUNCTION("warm_rst", warm_rstgrp, warm_rst_padmux),
+       SIRFSOC_PMX_FUNCTION("cko0", cko0grp, cko0_padmux),
+       SIRFSOC_PMX_FUNCTION("cko1", cko1grp, cko1_padmux),
+       SIRFSOC_PMX_FUNCTION("sdmmc0", sdmmc0grp, sdmmc0_padmux),
+       SIRFSOC_PMX_FUNCTION("sdmmc1", sdmmc1grp, sdmmc1_padmux),
+       SIRFSOC_PMX_FUNCTION("sdmmc2", sdmmc2grp, sdmmc2_padmux),
+       SIRFSOC_PMX_FUNCTION("sdmmc3", sdmmc3grp, sdmmc3_padmux),
+       SIRFSOC_PMX_FUNCTION("sdmmc5", sdmmc5grp, sdmmc5_padmux),
+       SIRFSOC_PMX_FUNCTION("sdmmc2_nowp", sdmmc2_nowpgrp, sdmmc2_nowp_padmux),
+       SIRFSOC_PMX_FUNCTION("usb0_upli_drvbus", usb0_upli_drvbusgrp, usb0_upli_drvbus_padmux),
+       SIRFSOC_PMX_FUNCTION("usb1_utmi_drvbus", usb1_utmi_drvbusgrp, usb1_utmi_drvbus_padmux),
+       SIRFSOC_PMX_FUNCTION("pulse_count", pulse_countgrp, pulse_count_padmux),
+       SIRFSOC_PMX_FUNCTION("i2s", i2sgrp, i2s_padmux),
+       SIRFSOC_PMX_FUNCTION("i2s_no_din", i2s_no_dingrp, i2s_no_din_padmux),
+       SIRFSOC_PMX_FUNCTION("i2s_6chn", i2s_6chngrp, i2s_6chn_padmux),
+       SIRFSOC_PMX_FUNCTION("ac97", ac97grp, ac97_padmux),
+       SIRFSOC_PMX_FUNCTION("nand", nandgrp, nand_padmux),
+       SIRFSOC_PMX_FUNCTION("spi0", spi0grp, spi0_padmux),
+       SIRFSOC_PMX_FUNCTION("spi1", spi1grp, spi1_padmux),
+       SIRFSOC_PMX_FUNCTION("gps", gpsgrp, gps_padmux),
+};
+
+struct sirfsoc_pinctrl_data atlas6_pinctrl_data = {
+       (struct pinctrl_pin_desc *)sirfsoc_pads,
+       ARRAY_SIZE(sirfsoc_pads),
+       (struct sirfsoc_pin_group *)sirfsoc_pin_groups,
+       ARRAY_SIZE(sirfsoc_pin_groups),
+       (struct sirfsoc_pmx_func *)sirfsoc_pmx_functions,
+       ARRAY_SIZE(sirfsoc_pmx_functions),
+};
+
similarity index 50%
rename from drivers/pinctrl/pinctrl-sirf.c
rename to drivers/pinctrl/sirf/pinctrl-prima2.c
index bc9d1be27fb09c49ed52ba972c055605af4ff19a..1f0ad1ef5a3a5cb049afbd355f5635774fbec87b 100644 (file)
@@ -1,70 +1,15 @@
 /*
- * pinmux driver for CSR SiRFprimaII
+ * pinctrl pads, groups, functions for CSR SiRFprimaII
  *
  * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
  *
  * Licensed under GPLv2 or later.
  */
 
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/irqdomain.h>
-#include <linux/irqchip/chained_irq.h>
 #include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
-#include <linux/pinctrl/consumer.h>
-#include <linux/pinctrl/machine.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
 #include <linux/bitops.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-
-#define DRIVER_NAME "pinmux-sirf"
-
-#define SIRFSOC_NUM_PADS    622
-#define SIRFSOC_RSC_PIN_MUX 0x4
-
-#define SIRFSOC_GPIO_PAD_EN(g)         ((g)*0x100 + 0x84)
-#define SIRFSOC_GPIO_PAD_EN_CLR(g)     ((g)*0x100 + 0x90)
-#define SIRFSOC_GPIO_CTRL(g, i)                        ((g)*0x100 + (i)*4)
-#define SIRFSOC_GPIO_DSP_EN0                   (0x80)
-#define SIRFSOC_GPIO_INT_STATUS(g)             ((g)*0x100 + 0x8C)
-
-#define SIRFSOC_GPIO_CTL_INTR_LOW_MASK         0x1
-#define SIRFSOC_GPIO_CTL_INTR_HIGH_MASK                0x2
-#define SIRFSOC_GPIO_CTL_INTR_TYPE_MASK                0x4
-#define SIRFSOC_GPIO_CTL_INTR_EN_MASK          0x8
-#define SIRFSOC_GPIO_CTL_INTR_STS_MASK         0x10
-#define SIRFSOC_GPIO_CTL_OUT_EN_MASK           0x20
-#define SIRFSOC_GPIO_CTL_DATAOUT_MASK          0x40
-#define SIRFSOC_GPIO_CTL_DATAIN_MASK           0x80
-#define SIRFSOC_GPIO_CTL_PULL_MASK             0x100
-#define SIRFSOC_GPIO_CTL_PULL_HIGH             0x200
-#define SIRFSOC_GPIO_CTL_DSP_INT               0x400
-
-#define SIRFSOC_GPIO_NO_OF_BANKS        5
-#define SIRFSOC_GPIO_BANK_SIZE          32
-#define SIRFSOC_GPIO_NUM(bank, index)  (((bank)*(32)) + (index))
-
-struct sirfsoc_gpio_bank {
-       struct of_mm_gpio_chip chip;
-       struct irq_domain *domain;
-       int id;
-       int parent_irq;
-       spinlock_t lock;
-       bool is_marco; /* for marco, some registers are different with prima2 */
-};
-
-static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS];
-static DEFINE_SPINLOCK(sgpio_lock);
+
+#include "pinctrl-sirf.h"
 
 /*
  * pad list for the pinmux subsystem
@@ -183,46 +128,6 @@ static const struct pinctrl_pin_desc sirfsoc_pads[] = {
        PINCTRL_PIN(114, "x_ldd[15]"),
 };
 
-/**
- * @dev: a pointer back to containing device
- * @virtbase: the offset to the controller in virtual memory
- */
-struct sirfsoc_pmx {
-       struct device *dev;
-       struct pinctrl_dev *pmx;
-       void __iomem *gpio_virtbase;
-       void __iomem *rsc_virtbase;
-       bool is_marco;
-};
-
-/* SIRFSOC_GPIO_PAD_EN set */
-struct sirfsoc_muxmask {
-       unsigned long group;
-       unsigned long mask;
-};
-
-struct sirfsoc_padmux {
-       unsigned long muxmask_counts;
-       const struct sirfsoc_muxmask *muxmask;
-       /* RSC_PIN_MUX set */
-       unsigned long funcmask;
-       unsigned long funcval;
-};
-
- /**
- * struct sirfsoc_pin_group - describes a SiRFprimaII pin group
- * @name: the name of this specific pin group
- * @pins: an array of discrete physical pins used in this group, taken
- *     from the driver-local pin enumeration space
- * @num_pins: the number of pins in this group array, i.e. the number of
- *     elements in .pins so we can iterate over that array
- */
-struct sirfsoc_pin_group {
-       const char *name;
-       const unsigned int *pins;
-       const unsigned num_pins;
-};
-
 static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = {
        {
                .group = 3,
@@ -351,7 +256,7 @@ static const struct sirfsoc_padmux uart0_nostreamctrl_padmux = {
        .muxmask = uart0_nostreamctrl_muxmask,
 };
 
-static const unsigned uart0_nostreamctrl_pins[] = { 68, 39 };
+static const unsigned uart0_nostreamctrl_pins[] = { 68, 69 };
 
 static const struct sirfsoc_muxmask uart1_muxmask[] = {
        {
@@ -853,13 +758,6 @@ static const struct sirfsoc_padmux pulse_count_padmux = {
 
 static const unsigned pulse_count_pins[] = { 9, 10, 11 };
 
-#define SIRFSOC_PIN_GROUP(n, p)  \
-       {                       \
-               .name = n,      \
-               .pins = p,      \
-               .num_pins = ARRAY_SIZE(p),      \
-       }
-
 static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
        SIRFSOC_PIN_GROUP("lcd_16bitsgrp", lcd_16bits_pins),
        SIRFSOC_PIN_GROUP("lcd_18bitsgrp", lcd_18bits_pins),
@@ -881,8 +779,8 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
        SIRFSOC_PIN_GROUP("vipgrp", vip_pins),
        SIRFSOC_PIN_GROUP("vipromgrp", viprom_pins),
        SIRFSOC_PIN_GROUP("warm_rstgrp", warm_rst_pins),
-       SIRFSOC_PIN_GROUP("cko0_rstgrp", cko0_pins),
-       SIRFSOC_PIN_GROUP("cko1_rstgrp", cko1_pins),
+       SIRFSOC_PIN_GROUP("cko0grp", cko0_pins),
+       SIRFSOC_PIN_GROUP("cko1grp", cko1_pins),
        SIRFSOC_PIN_GROUP("sdmmc0grp", sdmmc0_pins),
        SIRFSOC_PIN_GROUP("sdmmc1grp", sdmmc1_pins),
        SIRFSOC_PIN_GROUP("sdmmc2grp", sdmmc2_pins),
@@ -900,101 +798,6 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
        SIRFSOC_PIN_GROUP("gpsgrp", gps_pins),
 };
 
-static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev)
-{
-       return ARRAY_SIZE(sirfsoc_pin_groups);
-}
-
-static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev,
-                                      unsigned selector)
-{
-       return sirfsoc_pin_groups[selector].name;
-}
-
-static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
-                              const unsigned **pins,
-                              unsigned *num_pins)
-{
-       *pins = sirfsoc_pin_groups[selector].pins;
-       *num_pins = sirfsoc_pin_groups[selector].num_pins;
-       return 0;
-}
-
-static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
-                  unsigned offset)
-{
-       seq_printf(s, " " DRIVER_NAME);
-}
-
-static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev,
-                                struct device_node *np_config,
-                                struct pinctrl_map **map, unsigned *num_maps)
-{
-       struct sirfsoc_pmx *spmx = pinctrl_dev_get_drvdata(pctldev);
-       struct device_node *np;
-       struct property *prop;
-       const char *function, *group;
-       int ret, index = 0, count = 0;
-
-       /* 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)
-                       return ret;
-
-               ret = of_property_count_strings(np, "sirf,pins");
-               if (ret < 0)
-                       return ret;
-
-               count += ret;
-       }
-
-       if (!count) {
-               dev_err(spmx->dev, "No child nodes passed via DT\n");
-               return -ENODEV;
-       }
-
-       *map = kzalloc(sizeof(**map) * count, GFP_KERNEL);
-       if (!*map)
-               return -ENOMEM;
-
-       for_each_child_of_node(np_config, np) {
-               of_property_read_string(np, "sirf,function", &function);
-               of_property_for_each_string(np, "sirf,pins", prop, group) {
-                       (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP;
-                       (*map)[index].data.mux.group = group;
-                       (*map)[index].data.mux.function = function;
-                       index++;
-               }
-       }
-
-       *num_maps = count;
-
-       return 0;
-}
-
-static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev,
-               struct pinctrl_map *map, unsigned num_maps)
-{
-       kfree(map);
-}
-
-static const struct pinctrl_ops sirfsoc_pctrl_ops = {
-       .get_groups_count = sirfsoc_get_groups_count,
-       .get_group_name = sirfsoc_get_group_name,
-       .get_group_pins = sirfsoc_get_group_pins,
-       .pin_dbg_show = sirfsoc_pin_dbg_show,
-       .dt_node_to_map = sirfsoc_dt_node_to_map,
-       .dt_free_map = sirfsoc_dt_free_map,
-};
-
-struct sirfsoc_pmx_func {
-       const char *name;
-       const char * const *groups;
-       const unsigned num_groups;
-       const struct sirfsoc_padmux *padmux;
-};
-
 static const char * const lcd_16bitsgrp[] = { "lcd_16bitsgrp" };
 static const char * const lcd_18bitsgrp[] = { "lcd_18bitsgrp" };
 static const char * const lcd_24bitsgrp[] = { "lcd_24bitsgrp" };
@@ -1033,14 +836,6 @@ static const char * const spi0grp[] = { "spi0grp" };
 static const char * const spi1grp[] = { "spi1grp" };
 static const char * const gpsgrp[] = { "gpsgrp" };
 
-#define SIRFSOC_PMX_FUNCTION(n, g, m)          \
-       {                                       \
-               .name = n,                      \
-               .groups = g,                    \
-               .num_groups = ARRAY_SIZE(g),    \
-               .padmux = &m,                   \
-       }
-
 static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = {
        SIRFSOC_PMX_FUNCTION("lcd_16bits", lcd_16bitsgrp, lcd_16bits_padmux),
        SIRFSOC_PMX_FUNCTION("lcd_18bits", lcd_18bitsgrp, lcd_18bits_padmux),
@@ -1081,730 +876,12 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = {
        SIRFSOC_PMX_FUNCTION("gps", gpsgrp, gps_padmux),
 };
 
-static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector,
-       bool enable)
-{
-       int i;
-       const struct sirfsoc_padmux *mux = sirfsoc_pmx_functions[selector].padmux;
-       const struct sirfsoc_muxmask *mask = mux->muxmask;
-
-       for (i = 0; i < mux->muxmask_counts; i++) {
-               u32 muxval;
-               if (!spmx->is_marco) {
-                       muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
-                       if (enable)
-                               muxval = muxval & ~mask[i].mask;
-                       else
-                               muxval = muxval | mask[i].mask;
-                       writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
-               } else {
-                       if (enable)
-                               writel(mask[i].mask, spmx->gpio_virtbase +
-                                       SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group));
-                       else
-                               writel(mask[i].mask, spmx->gpio_virtbase +
-                                       SIRFSOC_GPIO_PAD_EN(mask[i].group));
-               }
-       }
-
-       if (mux->funcmask && enable) {
-               u32 func_en_val;
-               func_en_val =
-                       readl(spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX);
-               func_en_val =
-                       (func_en_val & ~mux->funcmask) | (mux->
-                               funcval);
-               writel(func_en_val, spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX);
-       }
-}
-
-static int sirfsoc_pinmux_enable(struct pinctrl_dev *pmxdev, unsigned selector,
-       unsigned group)
-{
-       struct sirfsoc_pmx *spmx;
-
-       spmx = pinctrl_dev_get_drvdata(pmxdev);
-       sirfsoc_pinmux_endisable(spmx, selector, true);
-
-       return 0;
-}
-
-static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector,
-       unsigned group)
-{
-       struct sirfsoc_pmx *spmx;
-
-       spmx = pinctrl_dev_get_drvdata(pmxdev);
-       sirfsoc_pinmux_endisable(spmx, selector, false);
-}
-
-static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev)
-{
-       return ARRAY_SIZE(sirfsoc_pmx_functions);
-}
-
-static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev,
-                                         unsigned selector)
-{
-       return sirfsoc_pmx_functions[selector].name;
-}
-
-static int sirfsoc_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
-                              const char * const **groups,
-                              unsigned * const num_groups)
-{
-       *groups = sirfsoc_pmx_functions[selector].groups;
-       *num_groups = sirfsoc_pmx_functions[selector].num_groups;
-       return 0;
-}
-
-static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
-       struct pinctrl_gpio_range *range, unsigned offset)
-{
-       struct sirfsoc_pmx *spmx;
-
-       int group = range->id;
-
-       u32 muxval;
-
-       spmx = pinctrl_dev_get_drvdata(pmxdev);
-
-       if (!spmx->is_marco) {
-               muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
-               muxval = muxval | (1 << (offset - range->pin_base));
-               writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
-       } else {
-               writel(1 << (offset - range->pin_base), spmx->gpio_virtbase +
-                       SIRFSOC_GPIO_PAD_EN(group));
-       }
-
-       return 0;
-}
-
-static const struct pinmux_ops sirfsoc_pinmux_ops = {
-       .enable = sirfsoc_pinmux_enable,
-       .disable = sirfsoc_pinmux_disable,
-       .get_functions_count = sirfsoc_pinmux_get_funcs_count,
-       .get_function_name = sirfsoc_pinmux_get_func_name,
-       .get_function_groups = sirfsoc_pinmux_get_groups,
-       .gpio_request_enable = sirfsoc_pinmux_request_gpio,
-};
-
-static struct pinctrl_desc sirfsoc_pinmux_desc = {
-       .name = DRIVER_NAME,
-       .pins = sirfsoc_pads,
-       .npins = ARRAY_SIZE(sirfsoc_pads),
-       .pctlops = &sirfsoc_pctrl_ops,
-       .pmxops = &sirfsoc_pinmux_ops,
-       .owner = THIS_MODULE,
-};
-
-/*
- * Todo: bind irq_chip to every pinctrl_gpio_range
- */
-static struct pinctrl_gpio_range sirfsoc_gpio_ranges[] = {
-       {
-               .name = "sirfsoc-gpio*",
-               .id = 0,
-               .base = 0,
-               .pin_base = 0,
-               .npins = 32,
-       }, {
-               .name = "sirfsoc-gpio*",
-               .id = 1,
-               .base = 32,
-               .pin_base = 32,
-               .npins = 32,
-       }, {
-               .name = "sirfsoc-gpio*",
-               .id = 2,
-               .base = 64,
-               .pin_base = 64,
-               .npins = 32,
-       }, {
-               .name = "sirfsoc-gpio*",
-               .id = 3,
-               .base = 96,
-               .pin_base = 96,
-               .npins = 19,
-       },
-};
-
-static void __iomem *sirfsoc_rsc_of_iomap(void)
-{
-       const struct of_device_id rsc_ids[]  = {
-               { .compatible = "sirf,prima2-rsc" },
-               { .compatible = "sirf,marco-rsc" },
-               {}
-       };
-       struct device_node *np;
-
-       np = of_find_matching_node(NULL, rsc_ids);
-       if (!np)
-               panic("unable to find compatible rsc node in dtb\n");
-
-       return of_iomap(np, 0);
-}
-
-static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc,
-       const struct of_phandle_args *gpiospec,
-       u32 *flags)
-{
-       if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE)
-               return -EINVAL;
-
-       if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc)
-               return -EINVAL;
-
-       if (flags)
-               *flags = gpiospec->args[1];
-
-       return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE;
-}
-
-static int sirfsoc_pinmux_probe(struct platform_device *pdev)
-{
-       int ret;
-       struct sirfsoc_pmx *spmx;
-       struct device_node *np = pdev->dev.of_node;
-       int i;
-
-       /* Create state holders etc for this driver */
-       spmx = devm_kzalloc(&pdev->dev, sizeof(*spmx), GFP_KERNEL);
-       if (!spmx)
-               return -ENOMEM;
-
-       spmx->dev = &pdev->dev;
-
-       platform_set_drvdata(pdev, spmx);
-
-       spmx->gpio_virtbase = of_iomap(np, 0);
-       if (!spmx->gpio_virtbase) {
-               ret = -ENOMEM;
-               dev_err(&pdev->dev, "can't map gpio registers\n");
-               goto out_no_gpio_remap;
-       }
-
-       spmx->rsc_virtbase = sirfsoc_rsc_of_iomap();
-       if (!spmx->rsc_virtbase) {
-               ret = -ENOMEM;
-               dev_err(&pdev->dev, "can't map rsc registers\n");
-               goto out_no_rsc_remap;
-       }
-
-       if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
-               spmx->is_marco = 1;
-
-       /* Now register the pin controller and all pins it handles */
-       spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx);
-       if (!spmx->pmx) {
-               dev_err(&pdev->dev, "could not register SIRFSOC pinmux driver\n");
-               ret = -EINVAL;
-               goto out_no_pmx;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(sirfsoc_gpio_ranges); i++) {
-               sirfsoc_gpio_ranges[i].gc = &sgpio_bank[i].chip.gc;
-               pinctrl_add_gpio_range(spmx->pmx, &sirfsoc_gpio_ranges[i]);
-       }
-
-       dev_info(&pdev->dev, "initialized SIRFSOC pinmux driver\n");
-
-       return 0;
-
-out_no_pmx:
-       iounmap(spmx->rsc_virtbase);
-out_no_rsc_remap:
-       iounmap(spmx->gpio_virtbase);
-out_no_gpio_remap:
-       platform_set_drvdata(pdev, NULL);
-       return ret;
-}
-
-static const struct of_device_id pinmux_ids[] = {
-       { .compatible = "sirf,prima2-pinctrl" },
-       { .compatible = "sirf,marco-pinctrl" },
-       {}
-};
-
-static struct platform_driver sirfsoc_pinmux_driver = {
-       .driver = {
-               .name = DRIVER_NAME,
-               .owner = THIS_MODULE,
-               .of_match_table = pinmux_ids,
-       },
-       .probe = sirfsoc_pinmux_probe,
+struct sirfsoc_pinctrl_data prima2_pinctrl_data = {
+       (struct pinctrl_pin_desc *)sirfsoc_pads,
+       ARRAY_SIZE(sirfsoc_pads),
+       (struct sirfsoc_pin_group *)sirfsoc_pin_groups,
+       ARRAY_SIZE(sirfsoc_pin_groups),
+       (struct sirfsoc_pmx_func *)sirfsoc_pmx_functions,
+       ARRAY_SIZE(sirfsoc_pmx_functions),
 };
 
-static int __init sirfsoc_pinmux_init(void)
-{
-       return platform_driver_register(&sirfsoc_pinmux_driver);
-}
-arch_initcall(sirfsoc_pinmux_init);
-
-static inline int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-       struct sirfsoc_gpio_bank *bank = container_of(to_of_mm_gpio_chip(chip),
-               struct sirfsoc_gpio_bank, chip);
-
-       return irq_create_mapping(bank->domain, offset);
-}
-
-static inline int sirfsoc_gpio_to_offset(unsigned int gpio)
-{
-       return gpio % SIRFSOC_GPIO_BANK_SIZE;
-}
-
-static inline struct sirfsoc_gpio_bank *sirfsoc_gpio_to_bank(unsigned int gpio)
-{
-       return &sgpio_bank[gpio / SIRFSOC_GPIO_BANK_SIZE];
-}
-
-static inline struct sirfsoc_gpio_bank *sirfsoc_irqchip_to_bank(struct gpio_chip *chip)
-{
-       return container_of(to_of_mm_gpio_chip(chip), struct sirfsoc_gpio_bank, chip);
-}
-
-static void sirfsoc_gpio_irq_ack(struct irq_data *d)
-{
-       struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-       int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
-       u32 val, offset;
-       unsigned long flags;
-
-       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
-
-       spin_lock_irqsave(&sgpio_lock, flags);
-
-       val = readl(bank->chip.regs + offset);
-
-       writel(val, bank->chip.regs + offset);
-
-       spin_unlock_irqrestore(&sgpio_lock, flags);
-}
-
-static void __sirfsoc_gpio_irq_mask(struct sirfsoc_gpio_bank *bank, int idx)
-{
-       u32 val, offset;
-       unsigned long flags;
-
-       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
-
-       spin_lock_irqsave(&sgpio_lock, flags);
-
-       val = readl(bank->chip.regs + offset);
-       val &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK;
-       val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
-       writel(val, bank->chip.regs + offset);
-
-       spin_unlock_irqrestore(&sgpio_lock, flags);
-}
-
-static void sirfsoc_gpio_irq_mask(struct irq_data *d)
-{
-       struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-
-       __sirfsoc_gpio_irq_mask(bank, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
-}
-
-static void sirfsoc_gpio_irq_unmask(struct irq_data *d)
-{
-       struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-       int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
-       u32 val, offset;
-       unsigned long flags;
-
-       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
-
-       spin_lock_irqsave(&sgpio_lock, flags);
-
-       val = readl(bank->chip.regs + offset);
-       val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
-       val |= SIRFSOC_GPIO_CTL_INTR_EN_MASK;
-       writel(val, bank->chip.regs + offset);
-
-       spin_unlock_irqrestore(&sgpio_lock, flags);
-}
-
-static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type)
-{
-       struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
-       int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
-       u32 val, offset;
-       unsigned long flags;
-
-       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
-
-       spin_lock_irqsave(&sgpio_lock, flags);
-
-       val = readl(bank->chip.regs + offset);
-       val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
-
-       switch (type) {
-       case IRQ_TYPE_NONE:
-               break;
-       case IRQ_TYPE_EDGE_RISING:
-               val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
-               val &= ~SIRFSOC_GPIO_CTL_INTR_LOW_MASK;
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               val &= ~SIRFSOC_GPIO_CTL_INTR_HIGH_MASK;
-               val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_LOW_MASK |
-                        SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               val &= ~(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
-               val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK;
-               break;
-       case IRQ_TYPE_LEVEL_HIGH:
-               val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK;
-               val &= ~(SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
-               break;
-       }
-
-       writel(val, bank->chip.regs + offset);
-
-       spin_unlock_irqrestore(&sgpio_lock, flags);
-
-       return 0;
-}
-
-static struct irq_chip sirfsoc_irq_chip = {
-       .name = "sirf-gpio-irq",
-       .irq_ack = sirfsoc_gpio_irq_ack,
-       .irq_mask = sirfsoc_gpio_irq_mask,
-       .irq_unmask = sirfsoc_gpio_irq_unmask,
-       .irq_set_type = sirfsoc_gpio_irq_type,
-};
-
-static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc)
-{
-       struct sirfsoc_gpio_bank *bank = irq_get_handler_data(irq);
-       u32 status, ctrl;
-       int idx = 0;
-       struct irq_chip *chip = irq_get_chip(irq);
-
-       chained_irq_enter(chip, desc);
-
-       status = readl(bank->chip.regs + SIRFSOC_GPIO_INT_STATUS(bank->id));
-       if (!status) {
-               printk(KERN_WARNING
-                       "%s: gpio id %d status %#x no interrupt is flaged\n",
-                       __func__, bank->id, status);
-               handle_bad_irq(irq, desc);
-               return;
-       }
-
-       while (status) {
-               ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, idx));
-
-               /*
-                * Here we must check whether the corresponding GPIO's interrupt
-                * has been enabled, otherwise just skip it
-                */
-               if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) {
-                       pr_debug("%s: gpio id %d idx %d happens\n",
-                               __func__, bank->id, idx);
-                       generic_handle_irq(irq_find_mapping(bank->domain, idx));
-               }
-
-               idx++;
-               status = status >> 1;
-       }
-
-       chained_irq_exit(chip, desc);
-}
-
-static inline void sirfsoc_gpio_set_input(struct sirfsoc_gpio_bank *bank, unsigned ctrl_offset)
-{
-       u32 val;
-
-       val = readl(bank->chip.regs + ctrl_offset);
-       val &= ~SIRFSOC_GPIO_CTL_OUT_EN_MASK;
-       writel(val, bank->chip.regs + ctrl_offset);
-}
-
-static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
-       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
-       unsigned long flags;
-
-       if (pinctrl_request_gpio(chip->base + offset))
-               return -ENODEV;
-
-       spin_lock_irqsave(&bank->lock, flags);
-
-       /*
-        * default status:
-        * set direction as input and mask irq
-        */
-       sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset));
-       __sirfsoc_gpio_irq_mask(bank, offset);
-
-       spin_unlock_irqrestore(&bank->lock, flags);
-
-       return 0;
-}
-
-static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
-       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
-       unsigned long flags;
-
-       spin_lock_irqsave(&bank->lock, flags);
-
-       __sirfsoc_gpio_irq_mask(bank, offset);
-       sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset));
-
-       spin_unlock_irqrestore(&bank->lock, flags);
-
-       pinctrl_free_gpio(chip->base + offset);
-}
-
-static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-{
-       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
-       int idx = sirfsoc_gpio_to_offset(gpio);
-       unsigned long flags;
-       unsigned offset;
-
-       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
-
-       spin_lock_irqsave(&bank->lock, flags);
-
-       sirfsoc_gpio_set_input(bank, offset);
-
-       spin_unlock_irqrestore(&bank->lock, flags);
-
-       return 0;
-}
-
-static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_bank *bank, unsigned offset,
-       int value)
-{
-       u32 out_ctrl;
-       unsigned long flags;
-
-       spin_lock_irqsave(&bank->lock, flags);
-
-       out_ctrl = readl(bank->chip.regs + offset);
-       if (value)
-               out_ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK;
-       else
-               out_ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK;
-
-       out_ctrl &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK;
-       out_ctrl |= SIRFSOC_GPIO_CTL_OUT_EN_MASK;
-       writel(out_ctrl, bank->chip.regs + offset);
-
-       spin_unlock_irqrestore(&bank->lock, flags);
-}
-
-static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
-{
-       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
-       int idx = sirfsoc_gpio_to_offset(gpio);
-       u32 offset;
-       unsigned long flags;
-
-       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
-
-       spin_lock_irqsave(&sgpio_lock, flags);
-
-       sirfsoc_gpio_set_output(bank, offset, value);
-
-       spin_unlock_irqrestore(&sgpio_lock, flags);
-
-       return 0;
-}
-
-static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset)
-{
-       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
-       u32 val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&bank->lock, flags);
-
-       val = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
-
-       spin_unlock_irqrestore(&bank->lock, flags);
-
-       return !!(val & SIRFSOC_GPIO_CTL_DATAIN_MASK);
-}
-
-static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
-       int value)
-{
-       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
-       u32 ctrl;
-       unsigned long flags;
-
-       spin_lock_irqsave(&bank->lock, flags);
-
-       ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
-       if (value)
-               ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK;
-       else
-               ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK;
-       writel(ctrl, bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
-
-       spin_unlock_irqrestore(&bank->lock, flags);
-}
-
-static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
-                               irq_hw_number_t hwirq)
-{
-       struct sirfsoc_gpio_bank *bank = d->host_data;
-
-       if (!bank)
-               return -EINVAL;
-
-       irq_set_chip(irq, &sirfsoc_irq_chip);
-       irq_set_handler(irq, handle_level_irq);
-       irq_set_chip_data(irq, bank);
-       set_irq_flags(irq, IRQF_VALID);
-
-       return 0;
-}
-
-const struct irq_domain_ops sirfsoc_gpio_irq_simple_ops = {
-       .map = sirfsoc_gpio_irq_map,
-       .xlate = irq_domain_xlate_twocell,
-};
-
-static void sirfsoc_gpio_set_pullup(const u32 *pullups)
-{
-       int i, n;
-       const unsigned long *p = (const unsigned long *)pullups;
-
-       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
-               for_each_set_bit(n, p + i, BITS_PER_LONG) {
-                       u32 offset = SIRFSOC_GPIO_CTRL(i, n);
-                       u32 val = readl(sgpio_bank[i].chip.regs + offset);
-                       val |= SIRFSOC_GPIO_CTL_PULL_MASK;
-                       val |= SIRFSOC_GPIO_CTL_PULL_HIGH;
-                       writel(val, sgpio_bank[i].chip.regs + offset);
-               }
-       }
-}
-
-static void sirfsoc_gpio_set_pulldown(const u32 *pulldowns)
-{
-       int i, n;
-       const unsigned long *p = (const unsigned long *)pulldowns;
-
-       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
-               for_each_set_bit(n, p + i, BITS_PER_LONG) {
-                       u32 offset = SIRFSOC_GPIO_CTRL(i, n);
-                       u32 val = readl(sgpio_bank[i].chip.regs + offset);
-                       val |= SIRFSOC_GPIO_CTL_PULL_MASK;
-                       val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH;
-                       writel(val, sgpio_bank[i].chip.regs + offset);
-               }
-       }
-}
-
-static int sirfsoc_gpio_probe(struct device_node *np)
-{
-       int i, err = 0;
-       struct sirfsoc_gpio_bank *bank;
-       void *regs;
-       struct platform_device *pdev;
-       bool is_marco = false;
-
-       u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS];
-
-       pdev = of_find_device_by_node(np);
-       if (!pdev)
-               return -ENODEV;
-
-       regs = of_iomap(np, 0);
-       if (!regs)
-               return -ENOMEM;
-
-       if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
-               is_marco = 1;
-
-       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
-               bank = &sgpio_bank[i];
-               spin_lock_init(&bank->lock);
-               bank->chip.gc.request = sirfsoc_gpio_request;
-               bank->chip.gc.free = sirfsoc_gpio_free;
-               bank->chip.gc.direction_input = sirfsoc_gpio_direction_input;
-               bank->chip.gc.get = sirfsoc_gpio_get_value;
-               bank->chip.gc.direction_output = sirfsoc_gpio_direction_output;
-               bank->chip.gc.set = sirfsoc_gpio_set_value;
-               bank->chip.gc.to_irq = sirfsoc_gpio_to_irq;
-               bank->chip.gc.base = i * SIRFSOC_GPIO_BANK_SIZE;
-               bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE;
-               bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL);
-               bank->chip.gc.of_node = np;
-               bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate;
-               bank->chip.gc.of_gpio_n_cells = 2;
-               bank->chip.regs = regs;
-               bank->id = i;
-               bank->is_marco = is_marco;
-               bank->parent_irq = platform_get_irq(pdev, i);
-               if (bank->parent_irq < 0) {
-                       err = bank->parent_irq;
-                       goto out;
-               }
-
-               err = gpiochip_add(&bank->chip.gc);
-               if (err) {
-                       pr_err("%s: error in probe function with status %d\n",
-                               np->full_name, err);
-                       goto out;
-               }
-
-               bank->domain = irq_domain_add_linear(np, SIRFSOC_GPIO_BANK_SIZE,
-                                               &sirfsoc_gpio_irq_simple_ops, bank);
-
-               if (!bank->domain) {
-                       pr_err("%s: Failed to create irqdomain\n", np->full_name);
-                       err = -ENOSYS;
-                       goto out;
-               }
-
-               irq_set_chained_handler(bank->parent_irq, sirfsoc_gpio_handle_irq);
-               irq_set_handler_data(bank->parent_irq, bank);
-       }
-
-       if (!of_property_read_u32_array(np, "sirf,pullups", pullups,
-               SIRFSOC_GPIO_NO_OF_BANKS))
-               sirfsoc_gpio_set_pullup(pullups);
-
-       if (!of_property_read_u32_array(np, "sirf,pulldowns", pulldowns,
-               SIRFSOC_GPIO_NO_OF_BANKS))
-               sirfsoc_gpio_set_pulldown(pulldowns);
-
-       return 0;
-
-out:
-       iounmap(regs);
-       return err;
-}
-
-static int __init sirfsoc_gpio_init(void)
-{
-
-       struct device_node *np;
-
-       np = of_find_matching_node(NULL, pinmux_ids);
-
-       if (!np)
-               return -ENODEV;
-
-       return sirfsoc_gpio_probe(np);
-}
-subsys_initcall(sirfsoc_gpio_init);
-
-MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, "
-       "Yuping Luo <yuping.luo@csr.com>, "
-       "Barry Song <baohua.song@csr.com>");
-MODULE_DESCRIPTION("SIRFSOC pin control driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
new file mode 100644 (file)
index 0000000..0677e19
--- /dev/null
@@ -0,0 +1,929 @@
+/*
+ * pinmux driver for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <asm/mach/irq.h>
+
+#include "pinctrl-sirf.h"
+
+#define DRIVER_NAME "pinmux-sirf"
+
+struct sirfsoc_gpio_bank {
+       struct of_mm_gpio_chip chip;
+       struct irq_domain *domain;
+       int id;
+       int parent_irq;
+       spinlock_t lock;
+       bool is_marco; /* for marco, some registers are different with prima2 */
+};
+
+static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS];
+static DEFINE_SPINLOCK(sgpio_lock);
+
+static struct sirfsoc_pin_group *sirfsoc_pin_groups;
+static int sirfsoc_pingrp_cnt;
+
+static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       return sirfsoc_pingrp_cnt;
+}
+
+static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev,
+                                      unsigned selector)
+{
+       return sirfsoc_pin_groups[selector].name;
+}
+
+static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+                              const unsigned **pins,
+                              unsigned *num_pins)
+{
+       *pins = sirfsoc_pin_groups[selector].pins;
+       *num_pins = sirfsoc_pin_groups[selector].num_pins;
+       return 0;
+}
+
+static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+                  unsigned offset)
+{
+       seq_printf(s, " " DRIVER_NAME);
+}
+
+static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev,
+                                struct device_node *np_config,
+                                struct pinctrl_map **map, unsigned *num_maps)
+{
+       struct sirfsoc_pmx *spmx = pinctrl_dev_get_drvdata(pctldev);
+       struct device_node *np;
+       struct property *prop;
+       const char *function, *group;
+       int ret, index = 0, count = 0;
+
+       /* 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)
+                       return ret;
+
+               ret = of_property_count_strings(np, "sirf,pins");
+               if (ret < 0)
+                       return ret;
+
+               count += ret;
+       }
+
+       if (!count) {
+               dev_err(spmx->dev, "No child nodes passed via DT\n");
+               return -ENODEV;
+       }
+
+       *map = kzalloc(sizeof(**map) * count, GFP_KERNEL);
+       if (!*map)
+               return -ENOMEM;
+
+       for_each_child_of_node(np_config, np) {
+               of_property_read_string(np, "sirf,function", &function);
+               of_property_for_each_string(np, "sirf,pins", prop, group) {
+                       (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP;
+                       (*map)[index].data.mux.group = group;
+                       (*map)[index].data.mux.function = function;
+                       index++;
+               }
+       }
+
+       *num_maps = count;
+
+       return 0;
+}
+
+static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev,
+               struct pinctrl_map *map, unsigned num_maps)
+{
+       kfree(map);
+}
+
+static struct pinctrl_ops sirfsoc_pctrl_ops = {
+       .get_groups_count = sirfsoc_get_groups_count,
+       .get_group_name = sirfsoc_get_group_name,
+       .get_group_pins = sirfsoc_get_group_pins,
+       .pin_dbg_show = sirfsoc_pin_dbg_show,
+       .dt_node_to_map = sirfsoc_dt_node_to_map,
+       .dt_free_map = sirfsoc_dt_free_map,
+};
+
+static struct sirfsoc_pmx_func *sirfsoc_pmx_functions;
+static int sirfsoc_pmxfunc_cnt;
+
+static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector,
+       bool enable)
+{
+       int i;
+       const struct sirfsoc_padmux *mux = sirfsoc_pmx_functions[selector].padmux;
+       const struct sirfsoc_muxmask *mask = mux->muxmask;
+
+       for (i = 0; i < mux->muxmask_counts; i++) {
+               u32 muxval;
+               if (!spmx->is_marco) {
+                       muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+                       if (enable)
+                               muxval = muxval & ~mask[i].mask;
+                       else
+                               muxval = muxval | mask[i].mask;
+                       writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+               } else {
+                       if (enable)
+                               writel(mask[i].mask, spmx->gpio_virtbase +
+                                       SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group));
+                       else
+                               writel(mask[i].mask, spmx->gpio_virtbase +
+                                       SIRFSOC_GPIO_PAD_EN(mask[i].group));
+               }
+       }
+
+       if (mux->funcmask && enable) {
+               u32 func_en_val;
+               func_en_val =
+                       readl(spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX);
+               func_en_val =
+                       (func_en_val & ~mux->funcmask) | (mux->
+                               funcval);
+               writel(func_en_val, spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX);
+       }
+}
+
+static int sirfsoc_pinmux_enable(struct pinctrl_dev *pmxdev, unsigned selector,
+       unsigned group)
+{
+       struct sirfsoc_pmx *spmx;
+
+       spmx = pinctrl_dev_get_drvdata(pmxdev);
+       sirfsoc_pinmux_endisable(spmx, selector, true);
+
+       return 0;
+}
+
+static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector,
+       unsigned group)
+{
+       struct sirfsoc_pmx *spmx;
+
+       spmx = pinctrl_dev_get_drvdata(pmxdev);
+       sirfsoc_pinmux_endisable(spmx, selector, false);
+}
+
+static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev)
+{
+       return sirfsoc_pmxfunc_cnt;
+}
+
+static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev,
+                                         unsigned selector)
+{
+       return sirfsoc_pmx_functions[selector].name;
+}
+
+static int sirfsoc_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+                              const char * const **groups,
+                              unsigned * const num_groups)
+{
+       *groups = sirfsoc_pmx_functions[selector].groups;
+       *num_groups = sirfsoc_pmx_functions[selector].num_groups;
+       return 0;
+}
+
+static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
+       struct pinctrl_gpio_range *range, unsigned offset)
+{
+       struct sirfsoc_pmx *spmx;
+
+       int group = range->id;
+
+       u32 muxval;
+
+       spmx = pinctrl_dev_get_drvdata(pmxdev);
+
+       if (!spmx->is_marco) {
+               muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+               muxval = muxval | (1 << (offset - range->pin_base));
+               writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+       } else {
+               writel(1 << (offset - range->pin_base), spmx->gpio_virtbase +
+                       SIRFSOC_GPIO_PAD_EN(group));
+       }
+
+       return 0;
+}
+
+static struct pinmux_ops sirfsoc_pinmux_ops = {
+       .enable = sirfsoc_pinmux_enable,
+       .disable = sirfsoc_pinmux_disable,
+       .get_functions_count = sirfsoc_pinmux_get_funcs_count,
+       .get_function_name = sirfsoc_pinmux_get_func_name,
+       .get_function_groups = sirfsoc_pinmux_get_groups,
+       .gpio_request_enable = sirfsoc_pinmux_request_gpio,
+};
+
+static struct pinctrl_desc sirfsoc_pinmux_desc = {
+       .name = DRIVER_NAME,
+       .pctlops = &sirfsoc_pctrl_ops,
+       .pmxops = &sirfsoc_pinmux_ops,
+       .owner = THIS_MODULE,
+};
+
+/*
+ * Todo: bind irq_chip to every pinctrl_gpio_range
+ */
+static struct pinctrl_gpio_range sirfsoc_gpio_ranges[] = {
+       {
+               .name = "sirfsoc-gpio*",
+               .id = 0,
+               .base = 0,
+               .pin_base = 0,
+               .npins = 32,
+       }, {
+               .name = "sirfsoc-gpio*",
+               .id = 1,
+               .base = 32,
+               .pin_base = 32,
+               .npins = 32,
+       }, {
+               .name = "sirfsoc-gpio*",
+               .id = 2,
+               .base = 64,
+               .pin_base = 64,
+               .npins = 32,
+       }, {
+               .name = "sirfsoc-gpio*",
+               .id = 3,
+               .base = 96,
+               .pin_base = 96,
+               .npins = 19,
+       },
+};
+
+static void __iomem *sirfsoc_rsc_of_iomap(void)
+{
+       const struct of_device_id rsc_ids[]  = {
+               { .compatible = "sirf,prima2-rsc" },
+               { .compatible = "sirf,marco-rsc" },
+               {}
+       };
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, rsc_ids);
+       if (!np)
+               panic("unable to find compatible rsc node in dtb\n");
+
+       return of_iomap(np, 0);
+}
+
+static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc,
+       const struct of_phandle_args *gpiospec,
+       u32 *flags)
+{
+       if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE)
+               return -EINVAL;
+
+       if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc)
+               return -EINVAL;
+
+       if (flags)
+               *flags = gpiospec->args[1];
+
+       return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE;
+}
+
+static const struct of_device_id pinmux_ids[] = {
+       { .compatible = "sirf,prima2-pinctrl", .data = &prima2_pinctrl_data, },
+       { .compatible = "sirf,atlas6-pinctrl", .data = &atlas6_pinctrl_data, },
+       { .compatible = "sirf,marco-pinctrl", .data = &prima2_pinctrl_data, },
+       {}
+};
+
+static int sirfsoc_pinmux_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct sirfsoc_pmx *spmx;
+       struct device_node *np = pdev->dev.of_node;
+       const struct sirfsoc_pinctrl_data *pdata;
+       int i;
+
+       /* Create state holders etc for this driver */
+       spmx = devm_kzalloc(&pdev->dev, sizeof(*spmx), GFP_KERNEL);
+       if (!spmx)
+               return -ENOMEM;
+
+       spmx->dev = &pdev->dev;
+
+       platform_set_drvdata(pdev, spmx);
+
+       spmx->gpio_virtbase = of_iomap(np, 0);
+       if (!spmx->gpio_virtbase) {
+               dev_err(&pdev->dev, "can't map gpio registers\n");
+               return -ENOMEM;
+       }
+
+       spmx->rsc_virtbase = sirfsoc_rsc_of_iomap();
+       if (!spmx->rsc_virtbase) {
+               ret = -ENOMEM;
+               dev_err(&pdev->dev, "can't map rsc registers\n");
+               goto out_no_rsc_remap;
+       }
+
+       if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
+               spmx->is_marco = 1;
+
+       pdata = of_match_node(pinmux_ids, np)->data;
+       sirfsoc_pin_groups = pdata->grps;
+       sirfsoc_pingrp_cnt = pdata->grps_cnt;
+       sirfsoc_pmx_functions = pdata->funcs;
+       sirfsoc_pmxfunc_cnt = pdata->funcs_cnt;
+       sirfsoc_pinmux_desc.pins = pdata->pads;
+       sirfsoc_pinmux_desc.npins = pdata->pads_cnt;
+
+
+       /* Now register the pin controller and all pins it handles */
+       spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx);
+       if (!spmx->pmx) {
+               dev_err(&pdev->dev, "could not register SIRFSOC pinmux driver\n");
+               ret = -EINVAL;
+               goto out_no_pmx;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(sirfsoc_gpio_ranges); i++) {
+               sirfsoc_gpio_ranges[i].gc = &sgpio_bank[i].chip.gc;
+               pinctrl_add_gpio_range(spmx->pmx, &sirfsoc_gpio_ranges[i]);
+       }
+
+       dev_info(&pdev->dev, "initialized SIRFSOC pinmux driver\n");
+
+       return 0;
+
+out_no_pmx:
+       iounmap(spmx->rsc_virtbase);
+out_no_rsc_remap:
+       iounmap(spmx->gpio_virtbase);
+       return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int sirfsoc_pinmux_suspend_noirq(struct device *dev)
+{
+       int i, j;
+       struct sirfsoc_pmx *spmx = dev_get_drvdata(dev);
+
+       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+               for (j = 0; j < SIRFSOC_GPIO_BANK_SIZE; j++) {
+                       spmx->gpio_regs[i][j] = readl(spmx->gpio_virtbase +
+                               SIRFSOC_GPIO_CTRL(i, j));
+               }
+               spmx->ints_regs[i] = readl(spmx->gpio_virtbase +
+                       SIRFSOC_GPIO_INT_STATUS(i));
+               spmx->paden_regs[i] = readl(spmx->gpio_virtbase +
+                       SIRFSOC_GPIO_PAD_EN(i));
+       }
+       spmx->dspen_regs = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_DSP_EN0);
+
+       for (i = 0; i < 3; i++)
+               spmx->rsc_regs[i] = readl(spmx->rsc_virtbase + 4 * i);
+
+       return 0;
+}
+
+static int sirfsoc_pinmux_resume_noirq(struct device *dev)
+{
+       int i, j;
+       struct sirfsoc_pmx *spmx = dev_get_drvdata(dev);
+
+       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+               for (j = 0; j < SIRFSOC_GPIO_BANK_SIZE; j++) {
+                       writel(spmx->gpio_regs[i][j], spmx->gpio_virtbase +
+                               SIRFSOC_GPIO_CTRL(i, j));
+               }
+               writel(spmx->ints_regs[i], spmx->gpio_virtbase +
+                       SIRFSOC_GPIO_INT_STATUS(i));
+               writel(spmx->paden_regs[i], spmx->gpio_virtbase +
+                       SIRFSOC_GPIO_PAD_EN(i));
+       }
+       writel(spmx->dspen_regs, spmx->gpio_virtbase + SIRFSOC_GPIO_DSP_EN0);
+
+       for (i = 0; i < 3; i++)
+               writel(spmx->rsc_regs[i], spmx->rsc_virtbase + 4 * i);
+
+       return 0;
+}
+
+static const struct dev_pm_ops sirfsoc_pinmux_pm_ops = {
+       .suspend_noirq = sirfsoc_pinmux_suspend_noirq,
+       .resume_noirq = sirfsoc_pinmux_resume_noirq,
+};
+#endif
+
+static struct platform_driver sirfsoc_pinmux_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = pinmux_ids,
+#ifdef CONFIG_PM_SLEEP
+               .pm = &sirfsoc_pinmux_pm_ops,
+#endif
+       },
+       .probe = sirfsoc_pinmux_probe,
+};
+
+static int __init sirfsoc_pinmux_init(void)
+{
+       return platform_driver_register(&sirfsoc_pinmux_driver);
+}
+arch_initcall(sirfsoc_pinmux_init);
+
+static inline int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct sirfsoc_gpio_bank *bank = container_of(to_of_mm_gpio_chip(chip),
+               struct sirfsoc_gpio_bank, chip);
+
+       return irq_create_mapping(bank->domain, offset);
+}
+
+static inline int sirfsoc_gpio_to_offset(unsigned int gpio)
+{
+       return gpio % SIRFSOC_GPIO_BANK_SIZE;
+}
+
+static inline struct sirfsoc_gpio_bank *sirfsoc_gpio_to_bank(unsigned int gpio)
+{
+       return &sgpio_bank[gpio / SIRFSOC_GPIO_BANK_SIZE];
+}
+
+static inline struct sirfsoc_gpio_bank *sirfsoc_irqchip_to_bank(struct gpio_chip *chip)
+{
+       return container_of(to_of_mm_gpio_chip(chip), struct sirfsoc_gpio_bank, chip);
+}
+
+static void sirfsoc_gpio_irq_ack(struct irq_data *d)
+{
+       struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
+       u32 val, offset;
+       unsigned long flags;
+
+       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+       spin_lock_irqsave(&sgpio_lock, flags);
+
+       val = readl(bank->chip.regs + offset);
+
+       writel(val, bank->chip.regs + offset);
+
+       spin_unlock_irqrestore(&sgpio_lock, flags);
+}
+
+static void __sirfsoc_gpio_irq_mask(struct sirfsoc_gpio_bank *bank, int idx)
+{
+       u32 val, offset;
+       unsigned long flags;
+
+       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+       spin_lock_irqsave(&sgpio_lock, flags);
+
+       val = readl(bank->chip.regs + offset);
+       val &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK;
+       val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
+       writel(val, bank->chip.regs + offset);
+
+       spin_unlock_irqrestore(&sgpio_lock, flags);
+}
+
+static void sirfsoc_gpio_irq_mask(struct irq_data *d)
+{
+       struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+
+       __sirfsoc_gpio_irq_mask(bank, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
+}
+
+static void sirfsoc_gpio_irq_unmask(struct irq_data *d)
+{
+       struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
+       u32 val, offset;
+       unsigned long flags;
+
+       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+       spin_lock_irqsave(&sgpio_lock, flags);
+
+       val = readl(bank->chip.regs + offset);
+       val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
+       val |= SIRFSOC_GPIO_CTL_INTR_EN_MASK;
+       writel(val, bank->chip.regs + offset);
+
+       spin_unlock_irqrestore(&sgpio_lock, flags);
+}
+
+static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type)
+{
+       struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+       int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
+       u32 val, offset;
+       unsigned long flags;
+
+       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+       spin_lock_irqsave(&sgpio_lock, flags);
+
+       val = readl(bank->chip.regs + offset);
+       val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
+
+       switch (type) {
+       case IRQ_TYPE_NONE:
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
+               val &= ~SIRFSOC_GPIO_CTL_INTR_LOW_MASK;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               val &= ~SIRFSOC_GPIO_CTL_INTR_HIGH_MASK;
+               val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_LOW_MASK |
+                        SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               val &= ~(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
+               val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK;
+               val &= ~(SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
+               break;
+       }
+
+       writel(val, bank->chip.regs + offset);
+
+       spin_unlock_irqrestore(&sgpio_lock, flags);
+
+       return 0;
+}
+
+static struct irq_chip sirfsoc_irq_chip = {
+       .name = "sirf-gpio-irq",
+       .irq_ack = sirfsoc_gpio_irq_ack,
+       .irq_mask = sirfsoc_gpio_irq_mask,
+       .irq_unmask = sirfsoc_gpio_irq_unmask,
+       .irq_set_type = sirfsoc_gpio_irq_type,
+};
+
+static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc)
+{
+       struct sirfsoc_gpio_bank *bank = irq_get_handler_data(irq);
+       u32 status, ctrl;
+       int idx = 0;
+       struct irq_chip *chip = irq_get_chip(irq);
+
+       chained_irq_enter(chip, desc);
+
+       status = readl(bank->chip.regs + SIRFSOC_GPIO_INT_STATUS(bank->id));
+       if (!status) {
+               printk(KERN_WARNING
+                       "%s: gpio id %d status %#x no interrupt is flaged\n",
+                       __func__, bank->id, status);
+               handle_bad_irq(irq, desc);
+               return;
+       }
+
+       while (status) {
+               ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, idx));
+
+               /*
+                * Here we must check whether the corresponding GPIO's interrupt
+                * has been enabled, otherwise just skip it
+                */
+               if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) {
+                       pr_debug("%s: gpio id %d idx %d happens\n",
+                               __func__, bank->id, idx);
+                       generic_handle_irq(irq_find_mapping(bank->domain, idx));
+               }
+
+               idx++;
+               status = status >> 1;
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static inline void sirfsoc_gpio_set_input(struct sirfsoc_gpio_bank *bank, unsigned ctrl_offset)
+{
+       u32 val;
+
+       val = readl(bank->chip.regs + ctrl_offset);
+       val &= ~SIRFSOC_GPIO_CTL_OUT_EN_MASK;
+       writel(val, bank->chip.regs + ctrl_offset);
+}
+
+static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+       unsigned long flags;
+
+       if (pinctrl_request_gpio(chip->base + offset))
+               return -ENODEV;
+
+       spin_lock_irqsave(&bank->lock, flags);
+
+       /*
+        * default status:
+        * set direction as input and mask irq
+        */
+       sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset));
+       __sirfsoc_gpio_irq_mask(bank, offset);
+
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       return 0;
+}
+
+static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+       unsigned long flags;
+
+       spin_lock_irqsave(&bank->lock, flags);
+
+       __sirfsoc_gpio_irq_mask(bank, offset);
+       sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset));
+
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       pinctrl_free_gpio(chip->base + offset);
+}
+
+static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+       int idx = sirfsoc_gpio_to_offset(gpio);
+       unsigned long flags;
+       unsigned offset;
+
+       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+       spin_lock_irqsave(&bank->lock, flags);
+
+       sirfsoc_gpio_set_input(bank, offset);
+
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       return 0;
+}
+
+static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_bank *bank, unsigned offset,
+       int value)
+{
+       u32 out_ctrl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bank->lock, flags);
+
+       out_ctrl = readl(bank->chip.regs + offset);
+       if (value)
+               out_ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+       else
+               out_ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+
+       out_ctrl &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK;
+       out_ctrl |= SIRFSOC_GPIO_CTL_OUT_EN_MASK;
+       writel(out_ctrl, bank->chip.regs + offset);
+
+       spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
+{
+       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+       int idx = sirfsoc_gpio_to_offset(gpio);
+       u32 offset;
+       unsigned long flags;
+
+       offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
+
+       spin_lock_irqsave(&sgpio_lock, flags);
+
+       sirfsoc_gpio_set_output(bank, offset, value);
+
+       spin_unlock_irqrestore(&sgpio_lock, flags);
+
+       return 0;
+}
+
+static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bank->lock, flags);
+
+       val = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
+
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       return !!(val & SIRFSOC_GPIO_CTL_DATAIN_MASK);
+}
+
+static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
+       int value)
+{
+       struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
+       u32 ctrl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bank->lock, flags);
+
+       ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
+       if (value)
+               ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+       else
+               ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK;
+       writel(ctrl, bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
+
+       spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+                               irq_hw_number_t hwirq)
+{
+       struct sirfsoc_gpio_bank *bank = d->host_data;
+
+       if (!bank)
+               return -EINVAL;
+
+       irq_set_chip(irq, &sirfsoc_irq_chip);
+       irq_set_handler(irq, handle_level_irq);
+       irq_set_chip_data(irq, bank);
+       set_irq_flags(irq, IRQF_VALID);
+
+       return 0;
+}
+
+static const struct irq_domain_ops sirfsoc_gpio_irq_simple_ops = {
+       .map = sirfsoc_gpio_irq_map,
+       .xlate = irq_domain_xlate_twocell,
+};
+
+static void sirfsoc_gpio_set_pullup(const u32 *pullups)
+{
+       int i, n;
+       const unsigned long *p = (const unsigned long *)pullups;
+
+       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+               for_each_set_bit(n, p + i, BITS_PER_LONG) {
+                       u32 offset = SIRFSOC_GPIO_CTRL(i, n);
+                       u32 val = readl(sgpio_bank[i].chip.regs + offset);
+                       val |= SIRFSOC_GPIO_CTL_PULL_MASK;
+                       val |= SIRFSOC_GPIO_CTL_PULL_HIGH;
+                       writel(val, sgpio_bank[i].chip.regs + offset);
+               }
+       }
+}
+
+static void sirfsoc_gpio_set_pulldown(const u32 *pulldowns)
+{
+       int i, n;
+       const unsigned long *p = (const unsigned long *)pulldowns;
+
+       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+               for_each_set_bit(n, p + i, BITS_PER_LONG) {
+                       u32 offset = SIRFSOC_GPIO_CTRL(i, n);
+                       u32 val = readl(sgpio_bank[i].chip.regs + offset);
+                       val |= SIRFSOC_GPIO_CTL_PULL_MASK;
+                       val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH;
+                       writel(val, sgpio_bank[i].chip.regs + offset);
+               }
+       }
+}
+
+static int sirfsoc_gpio_probe(struct device_node *np)
+{
+       int i, err = 0;
+       struct sirfsoc_gpio_bank *bank;
+       void *regs;
+       struct platform_device *pdev;
+       bool is_marco = false;
+
+       u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS];
+
+       pdev = of_find_device_by_node(np);
+       if (!pdev)
+               return -ENODEV;
+
+       regs = of_iomap(np, 0);
+       if (!regs)
+               return -ENOMEM;
+
+       if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
+               is_marco = 1;
+
+       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+               bank = &sgpio_bank[i];
+               spin_lock_init(&bank->lock);
+               bank->chip.gc.request = sirfsoc_gpio_request;
+               bank->chip.gc.free = sirfsoc_gpio_free;
+               bank->chip.gc.direction_input = sirfsoc_gpio_direction_input;
+               bank->chip.gc.get = sirfsoc_gpio_get_value;
+               bank->chip.gc.direction_output = sirfsoc_gpio_direction_output;
+               bank->chip.gc.set = sirfsoc_gpio_set_value;
+               bank->chip.gc.to_irq = sirfsoc_gpio_to_irq;
+               bank->chip.gc.base = i * SIRFSOC_GPIO_BANK_SIZE;
+               bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE;
+               bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL);
+               bank->chip.gc.of_node = np;
+               bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate;
+               bank->chip.gc.of_gpio_n_cells = 2;
+               bank->chip.regs = regs;
+               bank->id = i;
+               bank->is_marco = is_marco;
+               bank->parent_irq = platform_get_irq(pdev, i);
+               if (bank->parent_irq < 0) {
+                       err = bank->parent_irq;
+                       goto out;
+               }
+
+               err = gpiochip_add(&bank->chip.gc);
+               if (err) {
+                       pr_err("%s: error in probe function with status %d\n",
+                               np->full_name, err);
+                       goto out;
+               }
+
+               bank->domain = irq_domain_add_linear(np, SIRFSOC_GPIO_BANK_SIZE,
+                                               &sirfsoc_gpio_irq_simple_ops, bank);
+
+               if (!bank->domain) {
+                       pr_err("%s: Failed to create irqdomain\n", np->full_name);
+                       err = -ENOSYS;
+                       goto out;
+               }
+
+               irq_set_chained_handler(bank->parent_irq, sirfsoc_gpio_handle_irq);
+               irq_set_handler_data(bank->parent_irq, bank);
+       }
+
+       if (!of_property_read_u32_array(np, "sirf,pullups", pullups,
+               SIRFSOC_GPIO_NO_OF_BANKS))
+               sirfsoc_gpio_set_pullup(pullups);
+
+       if (!of_property_read_u32_array(np, "sirf,pulldowns", pulldowns,
+               SIRFSOC_GPIO_NO_OF_BANKS))
+               sirfsoc_gpio_set_pulldown(pulldowns);
+
+       return 0;
+
+out:
+       iounmap(regs);
+       return err;
+}
+
+static int __init sirfsoc_gpio_init(void)
+{
+
+       struct device_node *np;
+
+       np = of_find_matching_node(NULL, pinmux_ids);
+
+       if (!np)
+               return -ENODEV;
+
+       return sirfsoc_gpio_probe(np);
+}
+subsys_initcall(sirfsoc_gpio_init);
+
+MODULE_AUTHOR("Rongjun Ying <rongjun.ying@csr.com>, "
+       "Yuping Luo <yuping.luo@csr.com>, "
+       "Barry Song <baohua.song@csr.com>");
+MODULE_DESCRIPTION("SIRFSOC pin control driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.h b/drivers/pinctrl/sirf/pinctrl-sirf.h
new file mode 100644 (file)
index 0000000..17cc108
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * pinmux driver shared headfile for CSR SiRFsoc
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __PINMUX_SIRF_H__
+#define __PINMUX_SIRF_H__
+
+#define SIRFSOC_NUM_PADS    622
+#define SIRFSOC_RSC_PIN_MUX 0x4
+
+#define SIRFSOC_GPIO_PAD_EN(g)         ((g)*0x100 + 0x84)
+#define SIRFSOC_GPIO_PAD_EN_CLR(g)     ((g)*0x100 + 0x90)
+#define SIRFSOC_GPIO_CTRL(g, i)                        ((g)*0x100 + (i)*4)
+#define SIRFSOC_GPIO_DSP_EN0                   (0x80)
+#define SIRFSOC_GPIO_INT_STATUS(g)             ((g)*0x100 + 0x8C)
+
+#define SIRFSOC_GPIO_CTL_INTR_LOW_MASK         0x1
+#define SIRFSOC_GPIO_CTL_INTR_HIGH_MASK                0x2
+#define SIRFSOC_GPIO_CTL_INTR_TYPE_MASK                0x4
+#define SIRFSOC_GPIO_CTL_INTR_EN_MASK          0x8
+#define SIRFSOC_GPIO_CTL_INTR_STS_MASK         0x10
+#define SIRFSOC_GPIO_CTL_OUT_EN_MASK           0x20
+#define SIRFSOC_GPIO_CTL_DATAOUT_MASK          0x40
+#define SIRFSOC_GPIO_CTL_DATAIN_MASK           0x80
+#define SIRFSOC_GPIO_CTL_PULL_MASK             0x100
+#define SIRFSOC_GPIO_CTL_PULL_HIGH             0x200
+#define SIRFSOC_GPIO_CTL_DSP_INT               0x400
+
+#define SIRFSOC_GPIO_NO_OF_BANKS        5
+#define SIRFSOC_GPIO_BANK_SIZE          32
+#define SIRFSOC_GPIO_NUM(bank, index)  (((bank)*(32)) + (index))
+
+/**
+ * @dev: a pointer back to containing device
+ * @virtbase: the offset to the controller in virtual memory
+ */
+struct sirfsoc_pmx {
+       struct device *dev;
+       struct pinctrl_dev *pmx;
+       void __iomem *gpio_virtbase;
+       void __iomem *rsc_virtbase;
+       u32 gpio_regs[SIRFSOC_GPIO_NO_OF_BANKS][SIRFSOC_GPIO_BANK_SIZE];
+       u32 ints_regs[SIRFSOC_GPIO_NO_OF_BANKS];
+       u32 paden_regs[SIRFSOC_GPIO_NO_OF_BANKS];
+       u32 dspen_regs;
+       u32 rsc_regs[3];
+       bool is_marco;
+};
+
+/* SIRFSOC_GPIO_PAD_EN set */
+struct sirfsoc_muxmask {
+       unsigned long group;
+       unsigned long mask;
+};
+
+struct sirfsoc_padmux {
+       unsigned long muxmask_counts;
+       const struct sirfsoc_muxmask *muxmask;
+       /* RSC_PIN_MUX set */
+       unsigned long funcmask;
+       unsigned long funcval;
+};
+
+ /**
+ * struct sirfsoc_pin_group - describes a SiRFprimaII pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ *     from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ *     elements in .pins so we can iterate over that array
+ */
+struct sirfsoc_pin_group {
+       const char *name;
+       const unsigned int *pins;
+       const unsigned num_pins;
+};
+
+#define SIRFSOC_PIN_GROUP(n, p)  \
+       {                       \
+               .name = n,      \
+               .pins = p,      \
+               .num_pins = ARRAY_SIZE(p),      \
+       }
+
+struct sirfsoc_pmx_func {
+       const char *name;
+       const char * const *groups;
+       const unsigned num_groups;
+       const struct sirfsoc_padmux *padmux;
+};
+
+#define SIRFSOC_PMX_FUNCTION(n, g, m)          \
+       {                                       \
+               .name = n,                      \
+               .groups = g,                    \
+               .num_groups = ARRAY_SIZE(g),    \
+               .padmux = &m,                   \
+       }
+
+struct sirfsoc_pinctrl_data {
+       struct pinctrl_pin_desc *pads;
+       int pads_cnt;
+       struct sirfsoc_pin_group *grps;
+       int grps_cnt;
+       struct sirfsoc_pmx_func *funcs;
+       int funcs_cnt;
+};
+
+extern struct sirfsoc_pinctrl_data prima2_pinctrl_data;
+extern struct sirfsoc_pinctrl_data atlas6_pinctrl_data;
+
+#endif
index 3e5a887216b8ae8688cb4a32b38a4beeeef1b118..0a7f0bdbaa7d0c335c4c53e96d27b78f53526419 100644 (file)
@@ -441,7 +441,7 @@ static int spear310_p2o(int pin)
        return offset;
 }
 
-int spear310_o2p(int offset)
+static int spear310_o2p(int offset)
 {
        if (offset <= 3)
                return 101 - offset;
@@ -528,18 +528,13 @@ static int plgpio_probe(struct platform_device *pdev)
        struct resource *res;
        int ret, irq, i;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n");
-               return -EBUSY;
-       }
-
        plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL);
        if (!plgpio) {
                dev_err(&pdev->dev, "memory allocation fail\n");
                return -ENOMEM;
        }
 
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        plgpio->base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(plgpio->base))
                return PTR_ERR(plgpio->base);
index 70d986e04afb205d6b908fb95d25b87b0d0c6804..0cc4335bc0f232bf7021cb72e48ed0ff639f1491 100644 (file)
@@ -569,11 +569,9 @@ int wmt_pinctrl_probe(struct platform_device *pdev,
        struct resource *res;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       data->base = devm_request_and_ioremap(&pdev->dev, res);
-       if (!data->base) {
-               dev_err(&pdev->dev, "failed to map memory resource\n");
-               return -EBUSY;
-       }
+       data->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(data->base))
+               return PTR_ERR(data->base);
 
        wmt_desc.pins = data->pins;
        wmt_desc.npins = data->npins;
index e4ac38aca5802ef995ad84fc9d191749075771ff..b13344c59808a50b984fdd275810a531f3515a73 100644 (file)
@@ -743,7 +743,7 @@ static int wmi_create_device(const struct guid_block *gblock,
        wblock->dev.class = &wmi_class;
 
        wmi_gtoa(gblock->guid, guid_string);
-       dev_set_name(&wblock->dev, guid_string);
+       dev_set_name(&wblock->dev, "%s", guid_string);
 
        dev_set_drvdata(&wblock->dev, wblock);
 
index 2365ef37ae2466b18620fff5e209c3352a6e08f6..5edee645d890e6037578da6f26aa0be5daaf61d0 100644 (file)
@@ -29,27 +29,7 @@ static struct proc_dir_entry *isapnp_proc_bus_dir = NULL;
 
 static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
 {
-       loff_t new = -1;
-       struct inode *inode = file_inode(file);
-
-       mutex_lock(&inode->i_mutex);
-       switch (whence) {
-       case 0:
-               new = off;
-               break;
-       case 1:
-               new = file->f_pos + off;
-               break;
-       case 2:
-               new = 256 + off;
-               break;
-       }
-       if (new < 0 || new > 256)
-               new = -EINVAL;
-       else
-               file->f_pos = new;
-       mutex_unlock(&inode->i_mutex);
-       return new;
+       return fixed_size_llseek(file, off, whence, 256);
 }
 
 static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf,
index 95cebf0185decdd48134892b43f5d45928ab3515..9357aa779048a241e6dafe6bbaa1058b9eabb89f 100644 (file)
@@ -211,6 +211,12 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
        res->start = -1;
        res->end = -1;
 
+       if (!rule->map) {
+               res->flags |= IORESOURCE_DISABLED;
+               pnp_dbg(&dev->dev, "  dma %d disabled\n", idx);
+               goto __add;
+       }
+
        for (i = 0; i < 8; i++) {
                if (rule->map & (1 << xtab[i])) {
                        res->start = res->end = xtab[i];
@@ -218,11 +224,9 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
                                goto __add;
                }
        }
-#ifdef MAX_DMA_CHANNELS
-       res->start = res->end = MAX_DMA_CHANNELS;
-#endif
-       res->flags |= IORESOURCE_DISABLED;
-       pnp_dbg(&dev->dev, "  disable dma %d\n", idx);
+
+       pnp_dbg(&dev->dev, "  couldn't assign dma %d\n", idx);
+       return -EBUSY;
 
 __add:
        pnp_add_dma_resource(dev, res->start, res->flags);
index 6b2238bb6a8111d1362ea00733f25787354efad6..db9973bb53f19efbf691bd12c87042b2246a374f 100644 (file)
@@ -27,7 +27,8 @@
 #include <linux/pm_runtime.h>
 #include <linux/power/smartreflex.h>
 
-#define SMARTREFLEX_NAME_LEN   16
+#define DRIVER_NAME    "smartreflex"
+#define SMARTREFLEX_NAME_LEN   32
 #define NVALUE_NAME_LEN                40
 #define SR_DISABLE_TIMEOUT     200
 
@@ -207,12 +208,11 @@ static void sr_stop_vddautocomp(struct omap_sr *sr)
 static int sr_late_init(struct omap_sr *sr_info)
 {
        struct omap_sr_data *pdata = sr_info->pdev->dev.platform_data;
-       struct resource *mem;
        int ret = 0;
 
        if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
-               ret = request_irq(sr_info->irq, sr_interrupt,
-                                 0, sr_info->name, sr_info);
+               ret = devm_request_irq(&sr_info->pdev->dev, sr_info->irq,
+                                      sr_interrupt, 0, sr_info->name, sr_info);
                if (ret)
                        goto error;
                disable_irq(sr_info->irq);
@@ -224,14 +224,10 @@ static int sr_late_init(struct omap_sr *sr_info)
        return ret;
 
 error:
-       iounmap(sr_info->base);
-       mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem->start, resource_size(mem));
        list_del(&sr_info->node);
        dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
                "interrupt handler. Smartreflex will"
                "not function as desired\n", __func__);
-       kfree(sr_info);
 
        return ret;
 }
@@ -341,9 +337,9 @@ static struct omap_sr_nvalue_table *sr_retrieve_nvalue_row(
 /* Public Functions */
 
 /**
- * sr_configure_errgen() - Configures the smrtreflex to perform AVS using the
+ * sr_configure_errgen() - Configures the SmartReflex to perform AVS using the
  *                      error generator module.
- * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
+ * @sr:                        SR module to be configured.
  *
  * This API is to be called from the smartreflex class driver to
  * configure the error generator module inside the smartreflex module.
@@ -352,17 +348,17 @@ static struct omap_sr_nvalue_table *sr_retrieve_nvalue_row(
  * SR CLASS 2 can choose between ERROR module and MINMAXAVG
  * module. Returns 0 on success and error value in case of failure.
  */
-int sr_configure_errgen(struct voltagedomain *voltdm)
+int sr_configure_errgen(struct omap_sr *sr)
 {
        u32 sr_config, sr_errconfig, errconfig_offs;
        u32 vpboundint_en, vpboundint_st;
        u32 senp_en = 0, senn_en = 0;
        u8 senp_shift, senn_shift;
-       struct omap_sr *sr = _sr_lookup(voltdm);
 
-       if (IS_ERR(sr)) {
-               pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
-               return PTR_ERR(sr);
+       if (!sr) {
+               pr_warn("%s: NULL omap_sr from %pF\n", __func__,
+                       (void *)_RET_IP_);
+               return -EINVAL;
        }
 
        if (!sr->clk_length)
@@ -414,22 +410,22 @@ int sr_configure_errgen(struct voltagedomain *voltdm)
 
 /**
  * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component
- * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
+ * @sr:                        SR module to be configured.
  *
  * This API is to be called from the smartreflex class driver to
  * disable the error generator module inside the smartreflex module.
  *
  * Returns 0 on success and error value in case of failure.
  */
-int sr_disable_errgen(struct voltagedomain *voltdm)
+int sr_disable_errgen(struct omap_sr *sr)
 {
        u32 errconfig_offs;
        u32 vpboundint_en, vpboundint_st;
-       struct omap_sr *sr = _sr_lookup(voltdm);
 
-       if (IS_ERR(sr)) {
-               pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
-               return PTR_ERR(sr);
+       if (!sr) {
+               pr_warn("%s: NULL omap_sr from %pF\n", __func__,
+                       (void *)_RET_IP_);
+               return -EINVAL;
        }
 
        switch (sr->ip_type) {
@@ -449,19 +445,24 @@ int sr_disable_errgen(struct voltagedomain *voltdm)
                return -EINVAL;
        }
 
-       /* Disable the interrupts of ERROR module */
-       sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0);
-
        /* Disable the Sensor and errorgen */
        sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0);
 
+       /*
+        * Disable the interrupts of ERROR module
+        * NOTE: modify is a read, modify,write - an implicit OCP barrier
+        * which is required is present here - sequencing is critical
+        * at this point (after errgen is disabled, vpboundint disable)
+        */
+       sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0);
+
        return 0;
 }
 
 /**
- * sr_configure_minmax() - Configures the smrtreflex to perform AVS using the
+ * sr_configure_minmax() - Configures the SmartReflex to perform AVS using the
  *                      minmaxavg module.
- * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
+ * @sr:                        SR module to be configured.
  *
  * This API is to be called from the smartreflex class driver to
  * configure the minmaxavg module inside the smartreflex module.
@@ -470,16 +471,16 @@ int sr_disable_errgen(struct voltagedomain *voltdm)
  * SR CLASS 2 can choose between ERROR module and MINMAXAVG
  * module. Returns 0 on success and error value in case of failure.
  */
-int sr_configure_minmax(struct voltagedomain *voltdm)
+int sr_configure_minmax(struct omap_sr *sr)
 {
        u32 sr_config, sr_avgwt;
        u32 senp_en = 0, senn_en = 0;
        u8 senp_shift, senn_shift;
-       struct omap_sr *sr = _sr_lookup(voltdm);
 
-       if (IS_ERR(sr)) {
-               pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
-               return PTR_ERR(sr);
+       if (!sr) {
+               pr_warn("%s: NULL omap_sr from %pF\n", __func__,
+                       (void *)_RET_IP_);
+               return -EINVAL;
        }
 
        if (!sr->clk_length)
@@ -546,7 +547,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm)
 
 /**
  * sr_enable() - Enables the smartreflex module.
- * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
+ * @sr:                pointer to which the SR module to be configured belongs to.
  * @volt:      The voltage at which the Voltage domain associated with
  *             the smartreflex module is operating at.
  *             This is required only to program the correct Ntarget value.
@@ -555,16 +556,16 @@ int sr_configure_minmax(struct voltagedomain *voltdm)
  * enable a smartreflex module. Returns 0 on success. Returns error
  * value if the voltage passed is wrong or if ntarget value is wrong.
  */
-int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
+int sr_enable(struct omap_sr *sr, unsigned long volt)
 {
        struct omap_volt_data *volt_data;
-       struct omap_sr *sr = _sr_lookup(voltdm);
        struct omap_sr_nvalue_table *nvalue_row;
        int ret;
 
-       if (IS_ERR(sr)) {
-               pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
-               return PTR_ERR(sr);
+       if (!sr) {
+               pr_warn("%s: NULL omap_sr from %pF\n", __func__,
+                       (void *)_RET_IP_);
+               return -EINVAL;
        }
 
        volt_data = omap_voltage_get_voltdata(sr->voltdm, volt);
@@ -606,17 +607,16 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt)
 
 /**
  * sr_disable() - Disables the smartreflex module.
- * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
+ * @sr:                pointer to which the SR module to be configured belongs to.
  *
  * This API is to be called from the smartreflex class driver to
  * disable a smartreflex module.
  */
-void sr_disable(struct voltagedomain *voltdm)
+void sr_disable(struct omap_sr *sr)
 {
-       struct omap_sr *sr = _sr_lookup(voltdm);
-
-       if (IS_ERR(sr)) {
-               pr_warning("%s: omap_sr struct for voltdm not found\n", __func__);
+       if (!sr) {
+               pr_warn("%s: NULL omap_sr from %pF\n", __func__,
+                       (void *)_RET_IP_);
                return;
        }
 
@@ -847,34 +847,33 @@ static int __init omap_sr_probe(struct platform_device *pdev)
        struct dentry *nvalue_dir;
        int i, ret = 0;
 
-       sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
+       sr_info = devm_kzalloc(&pdev->dev, sizeof(struct omap_sr), GFP_KERNEL);
        if (!sr_info) {
                dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
                        __func__);
                return -ENOMEM;
        }
 
+       sr_info->name = devm_kzalloc(&pdev->dev,
+                                    SMARTREFLEX_NAME_LEN, GFP_KERNEL);
+       if (!sr_info->name) {
+               dev_err(&pdev->dev, "%s: unable to allocate SR instance name\n",
+                       __func__);
+               return -ENOMEM;
+       }
+
        platform_set_drvdata(pdev, sr_info);
 
        if (!pdata) {
                dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
-               ret = -EINVAL;
-               goto err_free_devinfo;
+               return -EINVAL;
        }
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
-               ret = -ENODEV;
-               goto err_free_devinfo;
-       }
-
-       mem = request_mem_region(mem->start, resource_size(mem),
-                                       dev_name(&pdev->dev));
-       if (!mem) {
-               dev_err(&pdev->dev, "%s: no mem region\n", __func__);
-               ret = -EBUSY;
-               goto err_free_devinfo;
+       sr_info->base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(sr_info->base)) {
+               dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
+               return PTR_ERR(sr_info->base);
        }
 
        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -882,13 +881,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_irq_safe(&pdev->dev);
 
-       sr_info->name = kasprintf(GFP_KERNEL, "%s", pdata->name);
-       if (!sr_info->name) {
-               dev_err(&pdev->dev, "%s: Unable to alloc SR instance name\n",
-                       __func__);
-               ret = -ENOMEM;
-               goto err_release_region;
-       }
+       snprintf(sr_info->name, SMARTREFLEX_NAME_LEN, "%s", pdata->name);
 
        sr_info->pdev = pdev;
        sr_info->srid = pdev->id;
@@ -905,13 +898,6 @@ static int __init omap_sr_probe(struct platform_device *pdev)
        sr_info->autocomp_active = false;
        sr_info->ip_type = pdata->ip_type;
 
-       sr_info->base = ioremap(mem->start, resource_size(mem));
-       if (!sr_info->base) {
-               dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
-               ret = -ENOMEM;
-               goto err_free_name;
-       }
-
        if (irq)
                sr_info->irq = irq->start;
 
@@ -927,7 +913,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                ret = sr_late_init(sr_info);
                if (ret) {
                        pr_warning("%s: Error in SR late init\n", __func__);
-                       goto err_iounmap;
+                       goto err_list_del;
                }
        }
 
@@ -938,7 +924,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                        ret = PTR_ERR(sr_dbg_dir);
                        pr_err("%s:sr debugfs dir creation failed(%d)\n",
                                __func__, ret);
-                       goto err_iounmap;
+                       goto err_list_del;
                }
        }
 
@@ -991,16 +977,8 @@ static int __init omap_sr_probe(struct platform_device *pdev)
 
 err_debugfs:
        debugfs_remove_recursive(sr_info->dbg_dir);
-err_iounmap:
+err_list_del:
        list_del(&sr_info->node);
-       iounmap(sr_info->base);
-err_free_name:
-       kfree(sr_info->name);
-err_release_region:
-       release_mem_region(mem->start, resource_size(mem));
-err_free_devinfo:
-       kfree(sr_info);
-
        return ret;
 }
 
@@ -1008,7 +986,6 @@ static int omap_sr_remove(struct platform_device *pdev)
 {
        struct omap_sr_data *pdata = pdev->dev.platform_data;
        struct omap_sr *sr_info;
-       struct resource *mem;
 
        if (!pdata) {
                dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
@@ -1027,13 +1004,8 @@ static int omap_sr_remove(struct platform_device *pdev)
        if (sr_info->dbg_dir)
                debugfs_remove_recursive(sr_info->dbg_dir);
 
+       pm_runtime_disable(&pdev->dev);
        list_del(&sr_info->node);
-       iounmap(sr_info->base);
-       kfree(sr_info->name);
-       kfree(sr_info);
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem->start, resource_size(mem));
-
        return 0;
 }
 
@@ -1064,7 +1036,7 @@ static struct platform_driver smartreflex_driver = {
        .remove         = omap_sr_remove,
        .shutdown       = omap_sr_shutdown,
        .driver         = {
-               .name   = "smartreflex",
+               .name   = DRIVER_NAME,
        },
 };
 
index d3db26e46489425a2da8cc548c01cba34b5f1aeb..eae0eda9ff39cc2c933be97b4bc5c349d76da020 100644 (file)
 #include <linux/pps-gpio.h>
 #include <linux/gpio.h>
 #include <linux/list.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
 /* Info for each registered platform device */
 struct pps_gpio_device_data {
        int irq;                        /* IRQ used as PPS source */
        struct pps_device *pps;         /* PPS source device */
        struct pps_source_info info;    /* PPS source information */
-       const struct pps_gpio_platform_data *pdata;
+       bool assert_falling_edge;
+       bool capture_clear;
+       unsigned int gpio_pin;
 };
 
 /*
@@ -57,46 +61,25 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
 
        info = data;
 
-       rising_edge = gpio_get_value(info->pdata->gpio_pin);
-       if ((rising_edge && !info->pdata->assert_falling_edge) ||
-                       (!rising_edge && info->pdata->assert_falling_edge))
+       rising_edge = gpio_get_value(info->gpio_pin);
+       if ((rising_edge && !info->assert_falling_edge) ||
+                       (!rising_edge && info->assert_falling_edge))
                pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
-       else if (info->pdata->capture_clear &&
-                       ((rising_edge && info->pdata->assert_falling_edge) ||
-                        (!rising_edge && !info->pdata->assert_falling_edge)))
+       else if (info->capture_clear &&
+                       ((rising_edge && info->assert_falling_edge) ||
+                        (!rising_edge && !info->assert_falling_edge)))
                pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
 
        return IRQ_HANDLED;
 }
 
-static int pps_gpio_setup(struct platform_device *pdev)
-{
-       int ret;
-       const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
-
-       ret = gpio_request(pdata->gpio_pin, pdata->gpio_label);
-       if (ret) {
-               pr_warning("failed to request GPIO %u\n", pdata->gpio_pin);
-               return -EINVAL;
-       }
-
-       ret = gpio_direction_input(pdata->gpio_pin);
-       if (ret) {
-               pr_warning("failed to set pin direction\n");
-               gpio_free(pdata->gpio_pin);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static unsigned long
-get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata)
+get_irqf_trigger_flags(const struct pps_gpio_device_data *data)
 {
-       unsigned long flags = pdata->assert_falling_edge ?
+       unsigned long flags = data->assert_falling_edge ?
                IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
 
-       if (pdata->capture_clear) {
+       if (data->capture_clear) {
                flags |= ((flags & IRQF_TRIGGER_RISING) ?
                                IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
        }
@@ -107,38 +90,63 @@ get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata)
 static int pps_gpio_probe(struct platform_device *pdev)
 {
        struct pps_gpio_device_data *data;
-       int irq;
+       const char *gpio_label;
        int ret;
-       int err;
        int pps_default_params;
        const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
+       struct device_node *np = pdev->dev.of_node;
 
+       /* allocate space for device info */
+       data = devm_kzalloc(&pdev->dev, sizeof(struct pps_gpio_device_data),
+                       GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       if (pdata) {
+               data->gpio_pin = pdata->gpio_pin;
+               gpio_label = pdata->gpio_label;
+
+               data->assert_falling_edge = pdata->assert_falling_edge;
+               data->capture_clear = pdata->capture_clear;
+       } else {
+               ret = of_get_gpio(np, 0);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to get GPIO from device tree\n");
+                       return ret;
+               }
+               data->gpio_pin = ret;
+               gpio_label = PPS_GPIO_NAME;
+
+               if (of_get_property(np, "assert-falling-edge", NULL))
+                       data->assert_falling_edge = true;
+       }
 
        /* GPIO setup */
-       ret = pps_gpio_setup(pdev);
-       if (ret)
-               return -EINVAL;
+       ret = devm_gpio_request(&pdev->dev, data->gpio_pin, gpio_label);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request GPIO %u\n",
+                       data->gpio_pin);
+               return ret;
+       }
 
-       /* IRQ setup */
-       irq = gpio_to_irq(pdata->gpio_pin);
-       if (irq < 0) {
-               pr_err("failed to map GPIO to IRQ: %d\n", irq);
-               err = -EINVAL;
-               goto return_error;
+       ret = gpio_direction_input(data->gpio_pin);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to set pin direction\n");
+               return -EINVAL;
        }
 
-       /* allocate space for device info */
-       data = devm_kzalloc(&pdev->dev, sizeof(struct pps_gpio_device_data),
-                           GFP_KERNEL);
-       if (data == NULL) {
-               err = -ENOMEM;
-               goto return_error;
+       /* IRQ setup */
+       ret = gpio_to_irq(data->gpio_pin);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret);
+               return -EINVAL;
        }
+       data->irq = ret;
 
        /* initialize PPS specific parts of the bookkeeping data structure. */
        data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
                PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
-       if (pdata->capture_clear)
+       if (data->capture_clear)
                data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
                        PPS_ECHOCLEAR;
        data->info.owner = THIS_MODULE;
@@ -147,77 +155,58 @@ static int pps_gpio_probe(struct platform_device *pdev)
 
        /* register PPS source */
        pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
-       if (pdata->capture_clear)
+       if (data->capture_clear)
                pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
        data->pps = pps_register_source(&data->info, pps_default_params);
        if (data->pps == NULL) {
-               pr_err("failed to register IRQ %d as PPS source\n", irq);
-               err = -EINVAL;
-               goto return_error;
+               dev_err(&pdev->dev, "failed to register IRQ %d as PPS source\n",
+                       data->irq);
+               return -EINVAL;
        }
 
-       data->irq = irq;
-       data->pdata = pdata;
-
        /* register IRQ interrupt handler */
-       ret = request_irq(irq, pps_gpio_irq_handler,
-                       get_irqf_trigger_flags(pdata), data->info.name, data);
+       ret = devm_request_irq(&pdev->dev, data->irq, pps_gpio_irq_handler,
+                       get_irqf_trigger_flags(data), data->info.name, data);
        if (ret) {
                pps_unregister_source(data->pps);
-               pr_err("failed to acquire IRQ %d\n", irq);
-               err = -EINVAL;
-               goto return_error;
+               dev_err(&pdev->dev, "failed to acquire IRQ %d\n", data->irq);
+               return -EINVAL;
        }
 
        platform_set_drvdata(pdev, data);
-       dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n", irq);
+       dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n",
+                data->irq);
 
        return 0;
-
-return_error:
-       gpio_free(pdata->gpio_pin);
-       return err;
 }
 
 static int pps_gpio_remove(struct platform_device *pdev)
 {
        struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
-       const struct pps_gpio_platform_data *pdata = data->pdata;
 
        platform_set_drvdata(pdev, NULL);
-       free_irq(data->irq, data);
-       gpio_free(pdata->gpio_pin);
        pps_unregister_source(data->pps);
-       pr_info("removed IRQ %d as PPS source\n", data->irq);
+       dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);
        return 0;
 }
 
+static const struct of_device_id pps_gpio_dt_ids[] = {
+       { .compatible = "pps-gpio", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pps_gpio_dt_ids);
+
 static struct platform_driver pps_gpio_driver = {
        .probe          = pps_gpio_probe,
        .remove         = pps_gpio_remove,
        .driver         = {
                .name   = PPS_GPIO_NAME,
-               .owner  = THIS_MODULE
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(pps_gpio_dt_ids),
        },
 };
 
-static int __init pps_gpio_init(void)
-{
-       int ret = platform_driver_register(&pps_gpio_driver);
-       if (ret < 0)
-               pr_err("failed to register platform driver\n");
-       return ret;
-}
-
-static void __exit pps_gpio_exit(void)
-{
-       platform_driver_unregister(&pps_gpio_driver);
-       pr_debug("unregistered platform driver\n");
-}
-
-module_init(pps_gpio_init);
-module_exit(pps_gpio_exit);
-
+module_platform_driver(pps_gpio_driver);
 MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
 MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
 MODULE_DESCRIPTION("Use GPIO pin as PPS source");
index 5ab056494bbefc63d3e3a0a3daffcedd7c0a9ef4..3e3be57e9a1a1a6aaa9af2f11066827e8be3cbea 100644 (file)
@@ -67,4 +67,9 @@ config RAPIDIO_ENUM_BASIC
 
 endchoice
 
+menu "RapidIO Switch drivers"
+       depends on RAPIDIO
+
 source "drivers/rapidio/switches/Kconfig"
+
+endmenu
index 3036702ffe8b5950e83c9979c6e596fb9aa57db3..6271ada6993fb21f4c7d493784eec94c58742044 100644 (file)
@@ -1,7 +1,9 @@
 #
 # Makefile for RapidIO interconnect services
 #
-obj-y += rio.o rio-access.o rio-driver.o rio-sysfs.o
+obj-$(CONFIG_RAPIDIO) += rapidio.o
+rapidio-y := rio.o rio-access.o rio-driver.o rio-sysfs.o
+
 obj-$(CONFIG_RAPIDIO_ENUM_BASIC) += rio-scan.o
 
 obj-$(CONFIG_RAPIDIO)          += switches/
index 12a9d7f7040b6c5cd89d454d60a91cef2d2bc50e..c4cb0877592b4a8c4af223682364bddb7952ce53 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 config RAPIDIO_TSI721
-       bool "IDT Tsi721 PCI Express SRIO Controller support"
+       tristate "IDT Tsi721 PCI Express SRIO Controller support"
        depends on RAPIDIO && PCIEPORTBUS
        default "n"
        ---help---
index 7b62860f34f805842ab9fbe28ea35a6909f029b3..9432c494cf576f7b56f3497a770c4c1ab5a9677b 100644 (file)
@@ -2,7 +2,6 @@
 # Makefile for RapidIO devices
 #
 
-obj-$(CONFIG_RAPIDIO_TSI721)   += tsi721.o
-ifeq ($(CONFIG_RAPIDIO_DMA_ENGINE),y)
-obj-$(CONFIG_RAPIDIO_TSI721)   += tsi721_dma.o
-endif
+obj-$(CONFIG_RAPIDIO_TSI721)   += tsi721_mport.o
+tsi721_mport-y                 := tsi721.o
+tsi721_mport-$(CONFIG_RAPIDIO_DMA_ENGINE) += tsi721_dma.o
index a8b2c23a7ef4b7acbe4a771fbf72a2ddffded52f..ff7cbf2d28e3aca513a21999334ae01352208600 100644 (file)
@@ -2515,9 +2515,8 @@ static int __init tsi721_init(void)
        return pci_register_driver(&tsi721_driver);
 }
 
-static void __exit tsi721_exit(void)
-{
-       pci_unregister_driver(&tsi721_driver);
-}
-
 device_initcall(tsi721_init);
+
+MODULE_DESCRIPTION("IDT Tsi721 PCIExpress-to-SRIO bridge driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
index a0c875563d7669fbf69916c95bd0b0219417d985..3e9b6a78ad18a4dcff861886d0828b5622aad267 100644 (file)
@@ -199,6 +199,23 @@ static int rio_match_bus(struct device *dev, struct device_driver *drv)
       out:return 0;
 }
 
+static int rio_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct rio_dev *rdev;
+
+       if (!dev)
+               return -ENODEV;
+
+       rdev = to_rio_dev(dev);
+       if (!rdev)
+               return -ENODEV;
+
+       if (add_uevent_var(env, "MODALIAS=rapidio:v%04Xd%04Xav%04Xad%04X",
+                          rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did))
+               return -ENOMEM;
+       return 0;
+}
+
 struct device rio_bus = {
        .init_name = "rapidio",
 };
@@ -210,6 +227,7 @@ struct bus_type rio_bus_type = {
        .bus_attrs = rio_bus_attrs,
        .probe = rio_device_probe,
        .remove = rio_device_remove,
+       .uevent = rio_uevent,
 };
 
 /**
index 4c15dbf810871e04f55bb28d30d0f7e2d1cc826d..d3a6539a77cce19ef7ba6f311aed249c8e1cf87d 100644 (file)
@@ -406,6 +406,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
                rio_mport_write_config_32(port, destid, hopcount,
                                          RIO_COMPONENT_TAG_CSR, next_comptag);
                rdev->comp_tag = next_comptag++;
+               rdev->do_enum = true;
        }  else {
                rio_mport_read_config_32(port, destid, hopcount,
                                         RIO_COMPONENT_TAG_CSR,
@@ -432,8 +433,8 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
        /* If a PE has both switch and other functions, show it as a switch */
        if (rio_is_switch(rdev)) {
                rswitch = rdev->rswitch;
-               rswitch->switchid = rdev->comp_tag & RIO_CTAG_UDEVID;
                rswitch->port_ok = 0;
+               spin_lock_init(&rswitch->lock);
                rswitch->route_table = kzalloc(sizeof(u8)*
                                        RIO_MAX_ROUTE_ENTRIES(port->sys_size),
                                        GFP_KERNEL);
@@ -444,12 +445,10 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
                                rdid++)
                        rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
                dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
-                            rswitch->switchid);
-               rio_switch_init(rdev, do_enum);
+                            rdev->comp_tag & RIO_CTAG_UDEVID);
 
-               if (do_enum && rswitch->clr_table)
-                       rswitch->clr_table(port, destid, hopcount,
-                                          RIO_GLOBAL_TABLE);
+               if (do_enum)
+                       rio_route_clr_table(rdev, RIO_GLOBAL_TABLE, 0);
 
                list_add_tail(&rswitch->node, &net->switches);
 
@@ -459,7 +458,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
                        rio_enable_rx_tx_port(port, 0, destid, hopcount, 0);
 
                dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id,
-                            rdev->destid);
+                            rdev->comp_tag & RIO_CTAG_UDEVID);
        }
 
        rio_attach_device(rdev);
@@ -532,156 +531,6 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
        return result & RIO_PORT_N_ERR_STS_PORT_OK;
 }
 
-/**
- * rio_lock_device - Acquires host device lock for specified device
- * @port: Master port to send transaction
- * @destid: Destination ID for device/switch
- * @hopcount: Hopcount to reach switch
- * @wait_ms: Max wait time in msec (0 = no timeout)
- *
- * Attepts to acquire host device lock for specified device
- * Returns 0 if device lock acquired or EINVAL if timeout expires.
- */
-static int
-rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms)
-{
-       u32 result;
-       int tcnt = 0;
-
-       /* Attempt to acquire device lock */
-       rio_mport_write_config_32(port, destid, hopcount,
-                                 RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
-       rio_mport_read_config_32(port, destid, hopcount,
-                                RIO_HOST_DID_LOCK_CSR, &result);
-
-       while (result != port->host_deviceid) {
-               if (wait_ms != 0 && tcnt == wait_ms) {
-                       pr_debug("RIO: timeout when locking device %x:%x\n",
-                               destid, hopcount);
-                       return -EINVAL;
-               }
-
-               /* Delay a bit */
-               mdelay(1);
-               tcnt++;
-               /* Try to acquire device lock again */
-               rio_mport_write_config_32(port, destid,
-                       hopcount,
-                       RIO_HOST_DID_LOCK_CSR,
-                       port->host_deviceid);
-               rio_mport_read_config_32(port, destid,
-                       hopcount,
-                       RIO_HOST_DID_LOCK_CSR, &result);
-       }
-
-       return 0;
-}
-
-/**
- * rio_unlock_device - Releases host device lock for specified device
- * @port: Master port to send transaction
- * @destid: Destination ID for device/switch
- * @hopcount: Hopcount to reach switch
- *
- * Returns 0 if device lock released or EINVAL if fails.
- */
-static int
-rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
-{
-       u32 result;
-
-       /* Release device lock */
-       rio_mport_write_config_32(port, destid,
-                                 hopcount,
-                                 RIO_HOST_DID_LOCK_CSR,
-                                 port->host_deviceid);
-       rio_mport_read_config_32(port, destid, hopcount,
-               RIO_HOST_DID_LOCK_CSR, &result);
-       if ((result & 0xffff) != 0xffff) {
-               pr_debug("RIO: badness when releasing device lock %x:%x\n",
-                        destid, hopcount);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/**
- * rio_route_add_entry- Add a route entry to a switch routing table
- * @rdev: RIO device
- * @table: Routing table ID
- * @route_destid: Destination ID to be routed
- * @route_port: Port number to be routed
- * @lock: lock switch device flag
- *
- * Calls the switch specific add_entry() method to add a route entry
- * on a switch. The route table can be specified using the @table
- * argument if a switch has per port routing tables or the normal
- * use is to specific all tables (or the global table) by passing
- * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
- * on failure.
- */
-static int
-rio_route_add_entry(struct rio_dev *rdev,
-                   u16 table, u16 route_destid, u8 route_port, int lock)
-{
-       int rc;
-
-       if (lock) {
-               rc = rio_lock_device(rdev->net->hport, rdev->destid,
-                                    rdev->hopcount, 1000);
-               if (rc)
-                       return rc;
-       }
-
-       rc = rdev->rswitch->add_entry(rdev->net->hport, rdev->destid,
-                                     rdev->hopcount, table,
-                                     route_destid, route_port);
-       if (lock)
-               rio_unlock_device(rdev->net->hport, rdev->destid,
-                                 rdev->hopcount);
-
-       return rc;
-}
-
-/**
- * rio_route_get_entry- Read a route entry in a switch routing table
- * @rdev: RIO device
- * @table: Routing table ID
- * @route_destid: Destination ID to be routed
- * @route_port: Pointer to read port number into
- * @lock: lock switch device flag
- *
- * Calls the switch specific get_entry() method to read a route entry
- * in a switch. The route table can be specified using the @table
- * argument if a switch has per port routing tables or the normal
- * use is to specific all tables (or the global table) by passing
- * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
- * on failure.
- */
-static int
-rio_route_get_entry(struct rio_dev *rdev, u16 table,
-                   u16 route_destid, u8 *route_port, int lock)
-{
-       int rc;
-
-       if (lock) {
-               rc = rio_lock_device(rdev->net->hport, rdev->destid,
-                                    rdev->hopcount, 1000);
-               if (rc)
-                       return rc;
-       }
-
-       rc = rdev->rswitch->get_entry(rdev->net->hport, rdev->destid,
-                                     rdev->hopcount, table,
-                                     route_destid, route_port);
-       if (lock)
-               rio_unlock_device(rdev->net->hport, rdev->destid,
-                                 rdev->hopcount);
-
-       return rc;
-}
-
 /**
  * rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a device
  * @port: Master port to send transaction
@@ -1094,12 +943,9 @@ static void rio_update_route_tables(struct rio_net *net)
 
                                sport = RIO_GET_PORT_NUM(swrdev->swpinfo);
 
-                               if (rswitch->add_entry) {
-                                       rio_route_add_entry(swrdev,
-                                               RIO_GLOBAL_TABLE, destid,
-                                               sport, 0);
-                                       rswitch->route_table[destid] = sport;
-                               }
+                               rio_route_add_entry(swrdev, RIO_GLOBAL_TABLE,
+                                                   destid, sport, 0);
+                               rswitch->route_table[destid] = sport;
                        }
                }
        }
@@ -1115,8 +961,8 @@ static void rio_update_route_tables(struct rio_net *net)
 static void rio_init_em(struct rio_dev *rdev)
 {
        if (rio_is_switch(rdev) && (rdev->em_efptr) &&
-           (rdev->rswitch->em_init)) {
-               rdev->rswitch->em_init(rdev);
+           rdev->rswitch->ops && rdev->rswitch->ops->em_init) {
+               rdev->rswitch->ops->em_init(rdev);
        }
 }
 
@@ -1141,7 +987,7 @@ static void rio_pw_enable(struct rio_mport *port, int enable)
  * link, then start recursive peer enumeration. Returns %0 if
  * enumeration succeeds or %-EBUSY if enumeration fails.
  */
-int rio_enum_mport(struct rio_mport *mport, u32 flags)
+static int rio_enum_mport(struct rio_mport *mport, u32 flags)
 {
        struct rio_net *net = NULL;
        int rc = 0;
@@ -1256,7 +1102,7 @@ static void rio_build_route_tables(struct rio_net *net)
  * peer discovery. Returns %0 if discovery succeeds or %-EBUSY
  * on failure.
  */
-int rio_disc_mport(struct rio_mport *mport, u32 flags)
+static int rio_disc_mport(struct rio_mport *mport, u32 flags)
 {
        struct rio_net *net = NULL;
        unsigned long to_end;
@@ -1315,6 +1161,7 @@ bail:
 }
 
 static struct rio_scan rio_scan_ops = {
+       .owner = THIS_MODULE,
        .enumerate = rio_enum_mport,
        .discover = rio_disc_mport,
 };
index 66d4acd5e18fd8f230cbb732a12dce1b90f98978..9331be646dc34d4075df3b6512975efe3eec8c1a 100644 (file)
@@ -84,6 +84,15 @@ static ssize_t lnext_show(struct device *dev,
        return str - buf;
 }
 
+static ssize_t modalias_show(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       struct rio_dev *rdev = to_rio_dev(dev);
+
+       return sprintf(buf, "rapidio:v%04Xd%04Xav%04Xad%04X\n",
+                      rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did);
+}
+
 struct device_attribute rio_dev_attrs[] = {
        __ATTR_RO(did),
        __ATTR_RO(vid),
@@ -93,6 +102,7 @@ struct device_attribute rio_dev_attrs[] = {
        __ATTR_RO(asm_rev),
        __ATTR_RO(lprev),
        __ATTR_RO(destid),
+       __ATTR_RO(modalias),
        __ATTR_NULL,
 };
 
@@ -257,8 +267,6 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
                err |= device_create_file(&rdev->dev, &dev_attr_routes);
                err |= device_create_file(&rdev->dev, &dev_attr_lnext);
                err |= device_create_file(&rdev->dev, &dev_attr_hopcount);
-               if (!err && rdev->rswitch->sw_sysfs)
-                       err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE);
        }
 
        if (err)
@@ -281,8 +289,6 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
                device_remove_file(&rdev->dev, &dev_attr_routes);
                device_remove_file(&rdev->dev, &dev_attr_lnext);
                device_remove_file(&rdev->dev, &dev_attr_hopcount);
-               if (rdev->rswitch->sw_sysfs)
-                       rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE);
        }
 }
 
@@ -290,7 +296,6 @@ static ssize_t bus_scan_store(struct bus_type *bus, const char *buf,
                                size_t count)
 {
        long val;
-       struct rio_mport *port = NULL;
        int rc;
 
        if (kstrtol(buf, 0, &val) < 0)
@@ -304,21 +309,7 @@ static ssize_t bus_scan_store(struct bus_type *bus, const char *buf,
        if (val < 0 || val >= RIO_MAX_MPORTS)
                return -EINVAL;
 
-       port = rio_find_mport((int)val);
-
-       if (!port) {
-               pr_debug("RIO: %s: mport_%d not available\n",
-                        __func__, (int)val);
-               return -EINVAL;
-       }
-
-       if (!port->nscan)
-               return -EINVAL;
-
-       if (port->host_deviceid >= 0)
-               rc = port->nscan->enumerate(port, 0);
-       else
-               rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT);
+       rc = rio_mport_scan((int)val);
 exit:
        if (!rc)
                rc = count;
index cb1c08996fbb133a2a49b68635a563abf3a2742c..f4f30af2df68c682744cc125ede61da5f87eb4d1 100644 (file)
@@ -5,9 +5,8 @@
  * Copyright 2005 MontaVista Software, Inc.
  * Matt Porter <mporter@kernel.crashing.org>
  *
- * Copyright 2009 Integrated Device Technology, Inc.
+ * Copyright 2009 - 2013 Integrated Device Technology, Inc.
  * Alex Bounine <alexandre.bounine@idt.com>
- * - Added Port-Write/Error Management initialization and handling
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
 
 #include "rio.h"
 
+MODULE_DESCRIPTION("RapidIO Subsystem Core");
+MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
+MODULE_AUTHOR("Alexandre Bounine <alexandre.bounine@idt.com>");
+MODULE_LICENSE("GPL");
+
+static int hdid[RIO_MAX_MPORTS];
+static int ids_num;
+module_param_array(hdid, int, &ids_num, 0);
+MODULE_PARM_DESC(hdid,
+       "Destination ID assignment to local RapidIO controllers");
+
 static LIST_HEAD(rio_devices);
 static DEFINE_SPINLOCK(rio_global_list_lock);
 
 static LIST_HEAD(rio_mports);
+static LIST_HEAD(rio_scans);
 static DEFINE_MUTEX(rio_mport_list_lock);
 static unsigned char next_portid;
 static DEFINE_SPINLOCK(rio_mmap_lock);
@@ -579,44 +590,6 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
 }
 EXPORT_SYMBOL_GPL(rio_set_port_lockout);
 
-/**
- * rio_switch_init - Sets switch operations for a particular vendor switch
- * @rdev: RIO device
- * @do_enum: Enumeration/Discovery mode flag
- *
- * Searches the RIO switch ops table for known switch types. If the vid
- * and did match a switch table entry, then call switch initialization
- * routine to setup switch-specific routines.
- */
-void rio_switch_init(struct rio_dev *rdev, int do_enum)
-{
-       struct rio_switch_ops *cur = __start_rio_switch_ops;
-       struct rio_switch_ops *end = __end_rio_switch_ops;
-
-       while (cur < end) {
-               if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
-                       pr_debug("RIO: calling init routine for %s\n",
-                                rio_name(rdev));
-                       cur->init_hook(rdev, do_enum);
-                       break;
-               }
-               cur++;
-       }
-
-       if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
-               pr_debug("RIO: adding STD routing ops for %s\n",
-                       rio_name(rdev));
-               rdev->rswitch->add_entry = rio_std_route_add_entry;
-               rdev->rswitch->get_entry = rio_std_route_get_entry;
-               rdev->rswitch->clr_table = rio_std_route_clr_table;
-       }
-
-       if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
-               printk(KERN_ERR "RIO: missing routing ops for %s\n",
-                      rio_name(rdev));
-}
-EXPORT_SYMBOL_GPL(rio_switch_init);
-
 /**
  * rio_enable_rx_tx_port - enable input receiver and output transmitter of
  * given port
@@ -970,8 +943,8 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
        /*
         * Process the port-write notification from switch
         */
-       if (rdev->rswitch->em_handle)
-               rdev->rswitch->em_handle(rdev, portnum);
+       if (rdev->rswitch->ops && rdev->rswitch->ops->em_handle)
+               rdev->rswitch->ops->em_handle(rdev, portnum);
 
        rio_read_config_32(rdev,
                        rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
@@ -1207,8 +1180,9 @@ struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from)
  * @route_destid: destID entry in the RT
  * @route_port: destination port for specified destID
  */
-int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
-                      u16 table, u16 route_destid, u8 route_port)
+static int
+rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                       u16 table, u16 route_destid, u8 route_port)
 {
        if (table == RIO_GLOBAL_TABLE) {
                rio_mport_write_config_32(mport, destid, hopcount,
@@ -1234,8 +1208,9 @@ int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
  * @route_destid: destID entry in the RT
  * @route_port: returned destination port for specified destID
  */
-int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
-                      u16 table, u16 route_destid, u8 *route_port)
+static int
+rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                       u16 table, u16 route_destid, u8 *route_port)
 {
        u32 result;
 
@@ -1259,8 +1234,9 @@ int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
  * @hopcount: Number of switch hops to the device
  * @table: routing table ID (global or port-specific)
  */
-int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
-                      u16 table)
+static int
+rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+                       u16 table)
 {
        u32 max_destid = 0xff;
        u32 i, pef, id_inc = 1, ext_cfg = 0;
@@ -1301,6 +1277,234 @@ int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
        return 0;
 }
 
+/**
+ * rio_lock_device - Acquires host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ * @wait_ms: Max wait time in msec (0 = no timeout)
+ *
+ * Attepts to acquire host device lock for specified device
+ * Returns 0 if device lock acquired or EINVAL if timeout expires.
+ */
+int rio_lock_device(struct rio_mport *port, u16 destid,
+                   u8 hopcount, int wait_ms)
+{
+       u32 result;
+       int tcnt = 0;
+
+       /* Attempt to acquire device lock */
+       rio_mport_write_config_32(port, destid, hopcount,
+                                 RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
+       rio_mport_read_config_32(port, destid, hopcount,
+                                RIO_HOST_DID_LOCK_CSR, &result);
+
+       while (result != port->host_deviceid) {
+               if (wait_ms != 0 && tcnt == wait_ms) {
+                       pr_debug("RIO: timeout when locking device %x:%x\n",
+                               destid, hopcount);
+                       return -EINVAL;
+               }
+
+               /* Delay a bit */
+               mdelay(1);
+               tcnt++;
+               /* Try to acquire device lock again */
+               rio_mport_write_config_32(port, destid,
+                       hopcount,
+                       RIO_HOST_DID_LOCK_CSR,
+                       port->host_deviceid);
+               rio_mport_read_config_32(port, destid,
+                       hopcount,
+                       RIO_HOST_DID_LOCK_CSR, &result);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rio_lock_device);
+
+/**
+ * rio_unlock_device - Releases host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ *
+ * Returns 0 if device lock released or EINVAL if fails.
+ */
+int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
+{
+       u32 result;
+
+       /* Release device lock */
+       rio_mport_write_config_32(port, destid,
+                                 hopcount,
+                                 RIO_HOST_DID_LOCK_CSR,
+                                 port->host_deviceid);
+       rio_mport_read_config_32(port, destid, hopcount,
+               RIO_HOST_DID_LOCK_CSR, &result);
+       if ((result & 0xffff) != 0xffff) {
+               pr_debug("RIO: badness when releasing device lock %x:%x\n",
+                        destid, hopcount);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rio_unlock_device);
+
+/**
+ * rio_route_add_entry- Add a route entry to a switch routing table
+ * @rdev: RIO device
+ * @table: Routing table ID
+ * @route_destid: Destination ID to be routed
+ * @route_port: Port number to be routed
+ * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock)
+ *
+ * If available calls the switch specific add_entry() method to add a route
+ * entry into a switch routing table. Otherwise uses standard RT update method
+ * as defined by RapidIO specification. A specific routing table can be selected
+ * using the @table argument if a switch has per port routing tables or
+ * the standard (or global) table may be used by passing
+ * %RIO_GLOBAL_TABLE in @table.
+ *
+ * Returns %0 on success or %-EINVAL on failure.
+ */
+int rio_route_add_entry(struct rio_dev *rdev,
+                       u16 table, u16 route_destid, u8 route_port, int lock)
+{
+       int rc = -EINVAL;
+       struct rio_switch_ops *ops = rdev->rswitch->ops;
+
+       if (lock) {
+               rc = rio_lock_device(rdev->net->hport, rdev->destid,
+                                    rdev->hopcount, 1000);
+               if (rc)
+                       return rc;
+       }
+
+       spin_lock(&rdev->rswitch->lock);
+
+       if (ops == NULL || ops->add_entry == NULL) {
+               rc = rio_std_route_add_entry(rdev->net->hport, rdev->destid,
+                                            rdev->hopcount, table,
+                                            route_destid, route_port);
+       } else if (try_module_get(ops->owner)) {
+               rc = ops->add_entry(rdev->net->hport, rdev->destid,
+                                   rdev->hopcount, table, route_destid,
+                                   route_port);
+               module_put(ops->owner);
+       }
+
+       spin_unlock(&rdev->rswitch->lock);
+
+       if (lock)
+               rio_unlock_device(rdev->net->hport, rdev->destid,
+                                 rdev->hopcount);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(rio_route_add_entry);
+
+/**
+ * rio_route_get_entry- Read an entry from a switch routing table
+ * @rdev: RIO device
+ * @table: Routing table ID
+ * @route_destid: Destination ID to be routed
+ * @route_port: Pointer to read port number into
+ * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock)
+ *
+ * If available calls the switch specific get_entry() method to fetch a route
+ * entry from a switch routing table. Otherwise uses standard RT read method
+ * as defined by RapidIO specification. A specific routing table can be selected
+ * using the @table argument if a switch has per port routing tables or
+ * the standard (or global) table may be used by passing
+ * %RIO_GLOBAL_TABLE in @table.
+ *
+ * Returns %0 on success or %-EINVAL on failure.
+ */
+int rio_route_get_entry(struct rio_dev *rdev, u16 table,
+                       u16 route_destid, u8 *route_port, int lock)
+{
+       int rc = -EINVAL;
+       struct rio_switch_ops *ops = rdev->rswitch->ops;
+
+       if (lock) {
+               rc = rio_lock_device(rdev->net->hport, rdev->destid,
+                                    rdev->hopcount, 1000);
+               if (rc)
+                       return rc;
+       }
+
+       spin_lock(&rdev->rswitch->lock);
+
+       if (ops == NULL || ops->get_entry == NULL) {
+               rc = rio_std_route_get_entry(rdev->net->hport, rdev->destid,
+                                            rdev->hopcount, table,
+                                            route_destid, route_port);
+       } else if (try_module_get(ops->owner)) {
+               rc = ops->get_entry(rdev->net->hport, rdev->destid,
+                                   rdev->hopcount, table, route_destid,
+                                   route_port);
+               module_put(ops->owner);
+       }
+
+       spin_unlock(&rdev->rswitch->lock);
+
+       if (lock)
+               rio_unlock_device(rdev->net->hport, rdev->destid,
+                                 rdev->hopcount);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(rio_route_get_entry);
+
+/**
+ * rio_route_clr_table - Clear a switch routing table
+ * @rdev: RIO device
+ * @table: Routing table ID
+ * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock)
+ *
+ * If available calls the switch specific clr_table() method to clear a switch
+ * routing table. Otherwise uses standard RT write method as defined by RapidIO
+ * specification. A specific routing table can be selected using the @table
+ * argument if a switch has per port routing tables or the standard (or global)
+ * table may be used by passing %RIO_GLOBAL_TABLE in @table.
+ *
+ * Returns %0 on success or %-EINVAL on failure.
+ */
+int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock)
+{
+       int rc = -EINVAL;
+       struct rio_switch_ops *ops = rdev->rswitch->ops;
+
+       if (lock) {
+               rc = rio_lock_device(rdev->net->hport, rdev->destid,
+                                    rdev->hopcount, 1000);
+               if (rc)
+                       return rc;
+       }
+
+       spin_lock(&rdev->rswitch->lock);
+
+       if (ops == NULL || ops->clr_table == NULL) {
+               rc = rio_std_route_clr_table(rdev->net->hport, rdev->destid,
+                                            rdev->hopcount, table);
+       } else if (try_module_get(ops->owner)) {
+               rc = ops->clr_table(rdev->net->hport, rdev->destid,
+                                   rdev->hopcount, table);
+
+               module_put(ops->owner);
+       }
+
+       spin_unlock(&rdev->rswitch->lock);
+
+       if (lock)
+               rio_unlock_device(rdev->net->hport, rdev->destid,
+                                 rdev->hopcount);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(rio_route_clr_table);
+
 #ifdef CONFIG_RAPIDIO_DMA_ENGINE
 
 static bool rio_chan_filter(struct dma_chan *chan, void *arg)
@@ -1410,34 +1614,73 @@ found:
  * rio_register_scan - enumeration/discovery method registration interface
  * @mport_id: mport device ID for which fabric scan routine has to be set
  *            (RIO_MPORT_ANY = set for all available mports)
- * @scan_ops: enumeration/discovery control structure
+ * @scan_ops: enumeration/discovery operations structure
+ *
+ * Registers enumeration/discovery operations with RapidIO subsystem and
+ * attaches it to the specified mport device (or all available mports
+ * if RIO_MPORT_ANY is specified).
  *
- * Assigns enumeration or discovery method to the specified mport device (or all
- * available mports if RIO_MPORT_ANY is specified).
  * Returns error if the mport already has an enumerator attached to it.
- * In case of RIO_MPORT_ANY ignores ports with valid scan routines and returns
- * an error if was unable to find at least one available mport.
+ * In case of RIO_MPORT_ANY skips mports with valid scan routines (no error).
  */
 int rio_register_scan(int mport_id, struct rio_scan *scan_ops)
 {
        struct rio_mport *port;
-       int rc = -EBUSY;
+       struct rio_scan_node *scan;
+       int rc = 0;
 
-       mutex_lock(&rio_mport_list_lock);
-       list_for_each_entry(port, &rio_mports, node) {
-               if (port->id == mport_id || mport_id == RIO_MPORT_ANY) {
-                       if (port->nscan && mport_id == RIO_MPORT_ANY)
-                               continue;
-                       else if (port->nscan)
-                               break;
+       pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id);
 
-                       port->nscan = scan_ops;
-                       rc = 0;
+       if ((mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) ||
+           !scan_ops)
+               return -EINVAL;
 
-                       if (mport_id != RIO_MPORT_ANY)
-                               break;
+       mutex_lock(&rio_mport_list_lock);
+
+       /*
+        * Check if there is another enumerator already registered for
+        * the same mport ID (including RIO_MPORT_ANY). Multiple enumerators
+        * for the same mport ID are not supported.
+        */
+       list_for_each_entry(scan, &rio_scans, node) {
+               if (scan->mport_id == mport_id) {
+                       rc = -EBUSY;
+                       goto err_out;
                }
        }
+
+       /*
+        * Allocate and initialize new scan registration node.
+        */
+       scan = kzalloc(sizeof(*scan), GFP_KERNEL);
+       if (!scan) {
+               rc = -ENOMEM;
+               goto err_out;
+       }
+
+       scan->mport_id = mport_id;
+       scan->ops = scan_ops;
+
+       /*
+        * Traverse the list of registered mports to attach this new scan.
+        *
+        * The new scan with matching mport ID overrides any previously attached
+        * scan assuming that old scan (if any) is the default one (based on the
+        * enumerator registration check above).
+        * If the new scan is the global one, it will be attached only to mports
+        * that do not have their own individual operations already attached.
+        */
+       list_for_each_entry(port, &rio_mports, node) {
+               if (port->id == mport_id) {
+                       port->nscan = scan_ops;
+                       break;
+               } else if (mport_id == RIO_MPORT_ANY && !port->nscan)
+                       port->nscan = scan_ops;
+       }
+
+       list_add_tail(&scan->node, &rio_scans);
+
+err_out:
        mutex_unlock(&rio_mport_list_lock);
 
        return rc;
@@ -1447,30 +1690,81 @@ EXPORT_SYMBOL_GPL(rio_register_scan);
 /**
  * rio_unregister_scan - removes enumeration/discovery method from mport
  * @mport_id: mport device ID for which fabric scan routine has to be
- *            unregistered (RIO_MPORT_ANY = set for all available mports)
+ *            unregistered (RIO_MPORT_ANY = apply to all mports that use
+ *            the specified scan_ops)
+ * @scan_ops: enumeration/discovery operations structure
  *
  * Removes enumeration or discovery method assigned to the specified mport
- * device (or all available mports if RIO_MPORT_ANY is specified).
+ * device. If RIO_MPORT_ANY is specified, removes the specified operations from
+ * all mports that have them attached.
  */
-int rio_unregister_scan(int mport_id)
+int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops)
 {
        struct rio_mport *port;
+       struct rio_scan_node *scan;
+
+       pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id);
+
+       if (mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS)
+               return -EINVAL;
 
        mutex_lock(&rio_mport_list_lock);
-       list_for_each_entry(port, &rio_mports, node) {
-               if (port->id == mport_id || mport_id == RIO_MPORT_ANY) {
-                       if (port->nscan)
-                               port->nscan = NULL;
-                       if (mport_id != RIO_MPORT_ANY)
-                               break;
+
+       list_for_each_entry(port, &rio_mports, node)
+               if (port->id == mport_id ||
+                   (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops))
+                       port->nscan = NULL;
+
+       list_for_each_entry(scan, &rio_scans, node)
+               if (scan->mport_id == mport_id) {
+                       list_del(&scan->node);
+                       kfree(scan);
                }
-       }
+
        mutex_unlock(&rio_mport_list_lock);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(rio_unregister_scan);
 
+/**
+ * rio_mport_scan - execute enumeration/discovery on the specified mport
+ * @mport_id: number (ID) of mport device
+ */
+int rio_mport_scan(int mport_id)
+{
+       struct rio_mport *port = NULL;
+       int rc;
+
+       mutex_lock(&rio_mport_list_lock);
+       list_for_each_entry(port, &rio_mports, node) {
+               if (port->id == mport_id)
+                       goto found;
+       }
+       mutex_unlock(&rio_mport_list_lock);
+       return -ENODEV;
+found:
+       if (!port->nscan) {
+               mutex_unlock(&rio_mport_list_lock);
+               return -EINVAL;
+       }
+
+       if (!try_module_get(port->nscan->owner)) {
+               mutex_unlock(&rio_mport_list_lock);
+               return -ENODEV;
+       }
+
+       mutex_unlock(&rio_mport_list_lock);
+
+       if (port->host_deviceid >= 0)
+               rc = port->nscan->enumerate(port, 0);
+       else
+               rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT);
+
+       module_put(port->nscan->owner);
+       return rc;
+}
+
 static void rio_fixup_device(struct rio_dev *dev)
 {
 }
@@ -1499,7 +1793,10 @@ static void disc_work_handler(struct work_struct *_work)
        work = container_of(_work, struct rio_disc_work, work);
        pr_debug("RIO: discovery work for mport %d %s\n",
                 work->mport->id, work->mport->name);
-       work->mport->nscan->discover(work->mport, 0);
+       if (try_module_get(work->mport->nscan->owner)) {
+               work->mport->nscan->discover(work->mport, 0);
+               module_put(work->mport->nscan->owner);
+       }
 }
 
 int rio_init_mports(void)
@@ -1518,8 +1815,10 @@ int rio_init_mports(void)
        mutex_lock(&rio_mport_list_lock);
        list_for_each_entry(port, &rio_mports, node) {
                if (port->host_deviceid >= 0) {
-                       if (port->nscan)
+                       if (port->nscan && try_module_get(port->nscan->owner)) {
                                port->nscan->enumerate(port, 0);
+                               module_put(port->nscan->owner);
+                       }
                } else
                        n++;
        }
@@ -1533,7 +1832,7 @@ int rio_init_mports(void)
         * for each of them. If the code below fails to allocate needed
         * resources, exit without error to keep results of enumeration
         * process (if any).
-        * TODO: Implement restart of dicovery process for all or
+        * TODO: Implement restart of discovery process for all or
         * individual discovering mports.
         */
        rio_wq = alloc_workqueue("riodisc", 0, 0);
@@ -1559,9 +1858,9 @@ int rio_init_mports(void)
                        n++;
                }
        }
-       mutex_unlock(&rio_mport_list_lock);
 
        flush_workqueue(rio_wq);
+       mutex_unlock(&rio_mport_list_lock);
        pr_debug("RIO: destroy discovery workqueue\n");
        destroy_workqueue(rio_wq);
        kfree(work);
@@ -1572,26 +1871,18 @@ no_disc:
        return 0;
 }
 
-static int hdids[RIO_MAX_MPORTS + 1];
-
 static int rio_get_hdid(int index)
 {
-       if (!hdids[0] || hdids[0] <= index || index >= RIO_MAX_MPORTS)
+       if (ids_num == 0 || ids_num <= index || index >= RIO_MAX_MPORTS)
                return -1;
 
-       return hdids[index + 1];
-}
-
-static int rio_hdid_setup(char *str)
-{
-       (void)get_options(str, ARRAY_SIZE(hdids), hdids);
-       return 1;
+       return hdid[index];
 }
 
-__setup("riohdid=", rio_hdid_setup);
-
 int rio_register_mport(struct rio_mport *port)
 {
+       struct rio_scan_node *scan = NULL;
+
        if (next_portid >= RIO_MAX_MPORTS) {
                pr_err("RIO: reached specified max number of mports\n");
                return 1;
@@ -1600,11 +1891,28 @@ int rio_register_mport(struct rio_mport *port)
        port->id = next_portid++;
        port->host_deviceid = rio_get_hdid(port->id);
        port->nscan = NULL;
+
        mutex_lock(&rio_mport_list_lock);
        list_add_tail(&port->node, &rio_mports);
+
+       /*
+        * Check if there are any registered enumeration/discovery operations
+        * that have to be attached to the added mport.
+        */
+       list_for_each_entry(scan, &rio_scans, node) {
+               if (port->id == scan->mport_id ||
+                   scan->mport_id == RIO_MPORT_ANY) {
+                       port->nscan = scan->ops;
+                       if (port->id == scan->mport_id)
+                               break;
+               }
+       }
        mutex_unlock(&rio_mport_list_lock);
+
+       pr_debug("RIO: %s %s id=%d\n", __func__, port->name, port->id);
        return 0;
 }
+EXPORT_SYMBOL_GPL(rio_register_mport);
 
 EXPORT_SYMBOL_GPL(rio_local_get_device_id);
 EXPORT_SYMBOL_GPL(rio_get_device);
index c14f864dea5cbf420fd247ec6d4584c89e932703..085215cd8502f5b12ca93787a267eef1d173759a 100644 (file)
@@ -28,52 +28,28 @@ extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
 extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid,
                                    u8 hopcount);
 extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
-extern int rio_std_route_add_entry(struct rio_mport *mport, u16 destid,
-                                  u8 hopcount, u16 table, u16 route_destid,
-                                  u8 route_port);
-extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid,
-                                  u8 hopcount, u16 table, u16 route_destid,
-                                  u8 *route_port);
-extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
-                                  u8 hopcount, u16 table);
+extern int rio_lock_device(struct rio_mport *port, u16 destid,
+                       u8 hopcount, int wait_ms);
+extern int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount);
+extern int rio_route_add_entry(struct rio_dev *rdev,
+                       u16 table, u16 route_destid, u8 route_port, int lock);
+extern int rio_route_get_entry(struct rio_dev *rdev, u16 table,
+                       u16 route_destid, u8 *route_port, int lock);
+extern int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock);
 extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock);
 extern struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from);
 extern int rio_add_device(struct rio_dev *rdev);
-extern void rio_switch_init(struct rio_dev *rdev, int do_enum);
 extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid,
                                 u8 hopcount, u8 port_num);
 extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops);
-extern int rio_unregister_scan(int mport_id);
+extern int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops);
 extern void rio_attach_device(struct rio_dev *rdev);
 extern struct rio_mport *rio_find_mport(int mport_id);
+extern int rio_mport_scan(int mport_id);
 
 /* Structures internal to the RIO core code */
 extern struct device_attribute rio_dev_attrs[];
 extern struct bus_attribute rio_bus_attrs[];
 
-extern struct rio_switch_ops __start_rio_switch_ops[];
-extern struct rio_switch_ops __end_rio_switch_ops[];
-
-/* Helpers internal to the RIO core code */
-#define DECLARE_RIO_SWITCH_SECTION(section, name, vid, did, init_hook) \
-       static const struct rio_switch_ops __rio_switch_##name __used \
-       __section(section) = { vid, did, init_hook };
-
-/**
- * DECLARE_RIO_SWITCH_INIT - Registers switch initialization routine
- * @vid: RIO vendor ID
- * @did: RIO device ID
- * @init_hook: Callback that performs switch-specific initialization
- *
- * Manipulating switch route tables and error management in RIO
- * is switch specific. This registers a switch by vendor and device ID with
- * initialization callback for setting up switch operations and (if required)
- * hardware initialization. A &struct rio_switch_ops is initialized with
- * pointer to the init routine and placed into a RIO-specific kernel section.
- */
-#define DECLARE_RIO_SWITCH_INIT(vid, did, init_hook)           \
-       DECLARE_RIO_SWITCH_SECTION(.rio_switch_ops, vid##did, \
-                       vid, did, init_hook)
-
 #define RIO_GET_DID(size, x)   (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
 #define RIO_SET_DID(size, x)   (size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
index f47fee5d4563a44d8ae6e918b8422e111cb5823c..345841562f95bdf57be587e9f0c65ae86e1a6778 100644 (file)
@@ -2,34 +2,23 @@
 # RapidIO switches configuration
 #
 config RAPIDIO_TSI57X
-       bool "IDT Tsi57x SRIO switches support"
-       depends on RAPIDIO
+       tristate "IDT Tsi57x SRIO switches support"
        ---help---
          Includes support for IDT Tsi57x family of serial RapidIO switches.
 
 config RAPIDIO_CPS_XX
-       bool "IDT CPS-xx SRIO switches support"
-       depends on RAPIDIO
+       tristate "IDT CPS-xx SRIO switches support"
        ---help---
          Includes support for IDT CPS-16/12/10/8 serial RapidIO switches.
 
 config RAPIDIO_TSI568
-       bool "Tsi568 SRIO switch support"
-       depends on RAPIDIO
+       tristate "Tsi568 SRIO switch support"
        default n
        ---help---
          Includes support for IDT Tsi568 serial RapidIO switch.
 
 config RAPIDIO_CPS_GEN2
-       bool "IDT CPS Gen.2 SRIO switch support"
-       depends on RAPIDIO
+       tristate "IDT CPS Gen.2 SRIO switch support"
        default n
        ---help---
          Includes support for ITD CPS Gen.2 serial RapidIO switches.
-
-config RAPIDIO_TSI500
-       bool "Tsi500 Parallel RapidIO switch support"
-       depends on RAPIDIO
-       default n
-       ---help---
-         Includes support for IDT Tsi500 parallel RapidIO switch.
index c4d3acc3c71560f63b605b410072ace4828c81a5..051cc6b3818827e485e971859ab9096cd4ffd9f7 100644 (file)
@@ -5,5 +5,4 @@
 obj-$(CONFIG_RAPIDIO_TSI57X)   += tsi57x.o
 obj-$(CONFIG_RAPIDIO_CPS_XX)   += idtcps.o
 obj-$(CONFIG_RAPIDIO_TSI568)   += tsi568.o
-obj-$(CONFIG_RAPIDIO_TSI500)   += tsi500.o
 obj-$(CONFIG_RAPIDIO_CPS_GEN2) += idt_gen2.o
index 809b7a3336baa40e654f296feeaa8ebb5067411e..00a71ebb5cac2f3b4a7b11248d32139db67a772c 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/stat.h>
+#include <linux/module.h>
 #include <linux/rio.h>
 #include <linux/rio_drv.h>
 #include <linux/rio_ids.h>
@@ -387,12 +388,12 @@ idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf)
 
 static DEVICE_ATTR(errlog, S_IRUGO, idtg2_show_errlog, NULL);
 
-static int idtg2_sysfs(struct rio_dev *rdev, int create)
+static int idtg2_sysfs(struct rio_dev *rdev, bool create)
 {
        struct device *dev = &rdev->dev;
        int err = 0;
 
-       if (create == RIO_SW_SYSFS_CREATE) {
+       if (create) {
                /* Initialize sysfs entries */
                err = device_create_file(dev, &dev_attr_errlog);
                if (err)
@@ -403,29 +404,90 @@ static int idtg2_sysfs(struct rio_dev *rdev, int create)
        return err;
 }
 
-static int idtg2_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops idtg2_switch_ops = {
+       .owner = THIS_MODULE,
+       .add_entry = idtg2_route_add_entry,
+       .get_entry = idtg2_route_get_entry,
+       .clr_table = idtg2_route_clr_table,
+       .set_domain = idtg2_set_domain,
+       .get_domain = idtg2_get_domain,
+       .em_init = idtg2_em_init,
+       .em_handle = idtg2_em_handler,
+};
+
+static int idtg2_probe(struct rio_dev *rdev, const struct rio_device_id *id)
 {
        pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
-       rdev->rswitch->add_entry = idtg2_route_add_entry;
-       rdev->rswitch->get_entry = idtg2_route_get_entry;
-       rdev->rswitch->clr_table = idtg2_route_clr_table;
-       rdev->rswitch->set_domain = idtg2_set_domain;
-       rdev->rswitch->get_domain = idtg2_get_domain;
-       rdev->rswitch->em_init = idtg2_em_init;
-       rdev->rswitch->em_handle = idtg2_em_handler;
-       rdev->rswitch->sw_sysfs = idtg2_sysfs;
-
-       if (do_enum) {
+
+       spin_lock(&rdev->rswitch->lock);
+
+       if (rdev->rswitch->ops) {
+               spin_unlock(&rdev->rswitch->lock);
+               return -EINVAL;
+       }
+
+       rdev->rswitch->ops = &idtg2_switch_ops;
+
+       if (rdev->do_enum) {
                /* Ensure that default routing is disabled on startup */
                rio_write_config_32(rdev,
                                    RIO_STD_RTE_DEFAULT_PORT, IDT_NO_ROUTE);
        }
 
+       /* Create device-specific sysfs attributes */
+       idtg2_sysfs(rdev, true);
+
+       spin_unlock(&rdev->rswitch->lock);
        return 0;
 }
 
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTVPS1616, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTSPS1616, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1432, idtg2_switch_init);
+static void idtg2_remove(struct rio_dev *rdev)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       spin_lock(&rdev->rswitch->lock);
+       if (rdev->rswitch->ops != &idtg2_switch_ops) {
+               spin_unlock(&rdev->rswitch->lock);
+               return;
+       }
+       rdev->rswitch->ops = NULL;
+
+       /* Remove device-specific sysfs attributes */
+       idtg2_sysfs(rdev, false);
+
+       spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id idtg2_id_table[] = {
+       {RIO_DEVICE(RIO_DID_IDTCPS1848, RIO_VID_IDT)},
+       {RIO_DEVICE(RIO_DID_IDTCPS1616, RIO_VID_IDT)},
+       {RIO_DEVICE(RIO_DID_IDTVPS1616, RIO_VID_IDT)},
+       {RIO_DEVICE(RIO_DID_IDTSPS1616, RIO_VID_IDT)},
+       {RIO_DEVICE(RIO_DID_IDTCPS1432, RIO_VID_IDT)},
+       { 0, }  /* terminate list */
+};
+
+static struct rio_driver idtg2_driver = {
+       .name = "idt_gen2",
+       .id_table = idtg2_id_table,
+       .probe = idtg2_probe,
+       .remove = idtg2_remove,
+};
+
+static int __init idtg2_init(void)
+{
+       return rio_register_driver(&idtg2_driver);
+}
+
+static void __exit idtg2_exit(void)
+{
+       pr_debug("RIO: %s\n", __func__);
+       rio_unregister_driver(&idtg2_driver);
+       pr_debug("RIO: %s done\n", __func__);
+}
+
+device_initcall(idtg2_init);
+module_exit(idtg2_exit);
+
+MODULE_DESCRIPTION("IDT CPS Gen.2 Serial RapidIO switch family driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
index d06ee2d44b44794f08b23511b19339024bde2d4d..7fbb60d3179602240766871fde2ace6d3b303283 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/rio.h>
 #include <linux/rio_drv.h>
 #include <linux/rio_ids.h>
+#include <linux/module.h>
 #include "../rio.h"
 
 #define CPS_DEFAULT_ROUTE      0xde
@@ -118,18 +119,31 @@ idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
        return 0;
 }
 
-static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops idtcps_switch_ops = {
+       .owner = THIS_MODULE,
+       .add_entry = idtcps_route_add_entry,
+       .get_entry = idtcps_route_get_entry,
+       .clr_table = idtcps_route_clr_table,
+       .set_domain = idtcps_set_domain,
+       .get_domain = idtcps_get_domain,
+       .em_init = NULL,
+       .em_handle = NULL,
+};
+
+static int idtcps_probe(struct rio_dev *rdev, const struct rio_device_id *id)
 {
        pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
-       rdev->rswitch->add_entry = idtcps_route_add_entry;
-       rdev->rswitch->get_entry = idtcps_route_get_entry;
-       rdev->rswitch->clr_table = idtcps_route_clr_table;
-       rdev->rswitch->set_domain = idtcps_set_domain;
-       rdev->rswitch->get_domain = idtcps_get_domain;
-       rdev->rswitch->em_init = NULL;
-       rdev->rswitch->em_handle = NULL;
-
-       if (do_enum) {
+
+       spin_lock(&rdev->rswitch->lock);
+
+       if (rdev->rswitch->ops) {
+               spin_unlock(&rdev->rswitch->lock);
+               return -EINVAL;
+       }
+
+       rdev->rswitch->ops = &idtcps_switch_ops;
+
+       if (rdev->do_enum) {
                /* set TVAL = ~50us */
                rio_write_config_32(rdev,
                        rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
@@ -138,12 +152,52 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
                                    RIO_STD_RTE_DEFAULT_PORT, CPS_NO_ROUTE);
        }
 
+       spin_unlock(&rdev->rswitch->lock);
        return 0;
 }
 
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS6Q, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS8, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS10Q, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS12, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS16, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDT70K200, idtcps_switch_init);
+static void idtcps_remove(struct rio_dev *rdev)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       spin_lock(&rdev->rswitch->lock);
+       if (rdev->rswitch->ops != &idtcps_switch_ops) {
+               spin_unlock(&rdev->rswitch->lock);
+               return;
+       }
+       rdev->rswitch->ops = NULL;
+       spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id idtcps_id_table[] = {
+       {RIO_DEVICE(RIO_DID_IDTCPS6Q, RIO_VID_IDT)},
+       {RIO_DEVICE(RIO_DID_IDTCPS8, RIO_VID_IDT)},
+       {RIO_DEVICE(RIO_DID_IDTCPS10Q, RIO_VID_IDT)},
+       {RIO_DEVICE(RIO_DID_IDTCPS12, RIO_VID_IDT)},
+       {RIO_DEVICE(RIO_DID_IDTCPS16, RIO_VID_IDT)},
+       {RIO_DEVICE(RIO_DID_IDT70K200, RIO_VID_IDT)},
+       { 0, }  /* terminate list */
+};
+
+static struct rio_driver idtcps_driver = {
+       .name = "idtcps",
+       .id_table = idtcps_id_table,
+       .probe = idtcps_probe,
+       .remove = idtcps_remove,
+};
+
+static int __init idtcps_init(void)
+{
+       return rio_register_driver(&idtcps_driver);
+}
+
+static void __exit idtcps_exit(void)
+{
+       rio_unregister_driver(&idtcps_driver);
+}
+
+device_initcall(idtcps_init);
+module_exit(idtcps_exit);
+
+MODULE_DESCRIPTION("IDT CPS Gen.1 Serial RapidIO switch family driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/switches/tsi500.c b/drivers/rapidio/switches/tsi500.c
deleted file mode 100644 (file)
index 914eddd..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * RapidIO Tsi500 switch support
- *
- * Copyright 2009-2010 Integrated Device Technology, Inc.
- * Alexandre Bounine <alexandre.bounine@idt.com>
- *  - Modified switch operations initialization.
- *
- * Copyright 2005 MontaVista Software, Inc.
- * Matt Porter <mporter@kernel.crashing.org>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <linux/rio.h>
-#include <linux/rio_drv.h>
-#include <linux/rio_ids.h>
-#include "../rio.h"
-
-static int
-tsi500_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table, u16 route_destid, u8 route_port)
-{
-       int i;
-       u32 offset = 0x10000 + 0xa00 + ((route_destid / 2)&~0x3);
-       u32 result;
-
-       if (table == 0xff) {
-               rio_mport_read_config_32(mport, destid, hopcount, offset, &result);
-               result &= ~(0xf << (4*(route_destid & 0x7)));
-               for (i=0;i<4;i++)
-                       rio_mport_write_config_32(mport, destid, hopcount, offset + (0x20000*i), result | (route_port << (4*(route_destid & 0x7))));
-       }
-       else {
-               rio_mport_read_config_32(mport, destid, hopcount, offset + (0x20000*table), &result);
-               result &= ~(0xf << (4*(route_destid & 0x7)));
-               rio_mport_write_config_32(mport, destid, hopcount, offset + (0x20000*table), result | (route_port << (4*(route_destid & 0x7))));
-       }
-
-       return 0;
-}
-
-static int
-tsi500_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table, u16 route_destid, u8 *route_port)
-{
-       int ret = 0;
-       u32 offset = 0x10000 + 0xa00 + ((route_destid / 2)&~0x3);
-       u32 result;
-
-       if (table == 0xff)
-               rio_mport_read_config_32(mport, destid, hopcount, offset, &result);
-       else
-               rio_mport_read_config_32(mport, destid, hopcount, offset + (0x20000*table), &result);
-
-       result &= 0xf << (4*(route_destid & 0x7));
-       *route_port = result >> (4*(route_destid & 0x7));
-       if (*route_port > 3)
-               ret = -1;
-
-       return ret;
-}
-
-static int tsi500_switch_init(struct rio_dev *rdev, int do_enum)
-{
-       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
-       rdev->rswitch->add_entry = tsi500_route_add_entry;
-       rdev->rswitch->get_entry = tsi500_route_get_entry;
-       rdev->rswitch->clr_table = NULL;
-       rdev->rswitch->set_domain = NULL;
-       rdev->rswitch->get_domain = NULL;
-       rdev->rswitch->em_init = NULL;
-       rdev->rswitch->em_handle = NULL;
-
-       return 0;
-}
-
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_switch_init);
index 3994c00aa01ff7161ad19193110e1a493e91d5f2..8a43561b9d17f7d4b9dc3f67f4c2e3e521b84e14 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/rio_drv.h>
 #include <linux/rio_ids.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include "../rio.h"
 
 /* Global (broadcast) route registers */
@@ -129,18 +130,70 @@ tsi568_em_init(struct rio_dev *rdev)
        return 0;
 }
 
-static int tsi568_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops tsi568_switch_ops = {
+       .owner = THIS_MODULE,
+       .add_entry = tsi568_route_add_entry,
+       .get_entry = tsi568_route_get_entry,
+       .clr_table = tsi568_route_clr_table,
+       .set_domain = NULL,
+       .get_domain = NULL,
+       .em_init = tsi568_em_init,
+       .em_handle = NULL,
+};
+
+static int tsi568_probe(struct rio_dev *rdev, const struct rio_device_id *id)
 {
        pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
-       rdev->rswitch->add_entry = tsi568_route_add_entry;
-       rdev->rswitch->get_entry = tsi568_route_get_entry;
-       rdev->rswitch->clr_table = tsi568_route_clr_table;
-       rdev->rswitch->set_domain = NULL;
-       rdev->rswitch->get_domain = NULL;
-       rdev->rswitch->em_init = tsi568_em_init;
-       rdev->rswitch->em_handle = NULL;
 
+       spin_lock(&rdev->rswitch->lock);
+
+       if (rdev->rswitch->ops) {
+               spin_unlock(&rdev->rswitch->lock);
+               return -EINVAL;
+       }
+
+       rdev->rswitch->ops = &tsi568_switch_ops;
+       spin_unlock(&rdev->rswitch->lock);
        return 0;
 }
 
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_switch_init);
+static void tsi568_remove(struct rio_dev *rdev)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       spin_lock(&rdev->rswitch->lock);
+       if (rdev->rswitch->ops != &tsi568_switch_ops) {
+               spin_unlock(&rdev->rswitch->lock);
+               return;
+       }
+       rdev->rswitch->ops = NULL;
+       spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id tsi568_id_table[] = {
+       {RIO_DEVICE(RIO_DID_TSI568, RIO_VID_TUNDRA)},
+       { 0, }  /* terminate list */
+};
+
+static struct rio_driver tsi568_driver = {
+       .name = "tsi568",
+       .id_table = tsi568_id_table,
+       .probe = tsi568_probe,
+       .remove = tsi568_remove,
+};
+
+static int __init tsi568_init(void)
+{
+       return rio_register_driver(&tsi568_driver);
+}
+
+static void __exit tsi568_exit(void)
+{
+       rio_unregister_driver(&tsi568_driver);
+}
+
+device_initcall(tsi568_init);
+module_exit(tsi568_exit);
+
+MODULE_DESCRIPTION("IDT Tsi568 Serial RapidIO switch driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
index db8b8028988d38216290a3e6021573f527d9ee55..42c8b014fe1584a7ba9f42550690168b425c31e4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/rio_drv.h>
 #include <linux/rio_ids.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include "../rio.h"
 
 /* Global (broadcast) route registers */
@@ -292,27 +293,79 @@ exit_es:
        return 0;
 }
 
-static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops tsi57x_switch_ops = {
+       .owner = THIS_MODULE,
+       .add_entry = tsi57x_route_add_entry,
+       .get_entry = tsi57x_route_get_entry,
+       .clr_table = tsi57x_route_clr_table,
+       .set_domain = tsi57x_set_domain,
+       .get_domain = tsi57x_get_domain,
+       .em_init = tsi57x_em_init,
+       .em_handle = tsi57x_em_handler,
+};
+
+static int tsi57x_probe(struct rio_dev *rdev, const struct rio_device_id *id)
 {
        pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
-       rdev->rswitch->add_entry = tsi57x_route_add_entry;
-       rdev->rswitch->get_entry = tsi57x_route_get_entry;
-       rdev->rswitch->clr_table = tsi57x_route_clr_table;
-       rdev->rswitch->set_domain = tsi57x_set_domain;
-       rdev->rswitch->get_domain = tsi57x_get_domain;
-       rdev->rswitch->em_init = tsi57x_em_init;
-       rdev->rswitch->em_handle = tsi57x_em_handler;
-
-       if (do_enum) {
+
+       spin_lock(&rdev->rswitch->lock);
+
+       if (rdev->rswitch->ops) {
+               spin_unlock(&rdev->rswitch->lock);
+               return -EINVAL;
+       }
+       rdev->rswitch->ops = &tsi57x_switch_ops;
+
+       if (rdev->do_enum) {
                /* Ensure that default routing is disabled on startup */
                rio_write_config_32(rdev, RIO_STD_RTE_DEFAULT_PORT,
                                    RIO_INVALID_ROUTE);
        }
 
+       spin_unlock(&rdev->rswitch->lock);
        return 0;
 }
 
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_switch_init);
+static void tsi57x_remove(struct rio_dev *rdev)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       spin_lock(&rdev->rswitch->lock);
+       if (rdev->rswitch->ops != &tsi57x_switch_ops) {
+               spin_unlock(&rdev->rswitch->lock);
+               return;
+       }
+       rdev->rswitch->ops = NULL;
+       spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id tsi57x_id_table[] = {
+       {RIO_DEVICE(RIO_DID_TSI572, RIO_VID_TUNDRA)},
+       {RIO_DEVICE(RIO_DID_TSI574, RIO_VID_TUNDRA)},
+       {RIO_DEVICE(RIO_DID_TSI577, RIO_VID_TUNDRA)},
+       {RIO_DEVICE(RIO_DID_TSI578, RIO_VID_TUNDRA)},
+       { 0, }  /* terminate list */
+};
+
+static struct rio_driver tsi57x_driver = {
+       .name = "tsi57x",
+       .id_table = tsi57x_id_table,
+       .probe = tsi57x_probe,
+       .remove = tsi57x_remove,
+};
+
+static int __init tsi57x_init(void)
+{
+       return rio_register_driver(&tsi57x_driver);
+}
+
+static void __exit tsi57x_exit(void)
+{
+       rio_unregister_driver(&tsi57x_driver);
+}
+
+device_initcall(tsi57x_init);
+module_exit(tsi57x_exit);
+
+MODULE_DESCRIPTION("IDT Tsi57x Serial RapidIO switch family driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
index 493948a38fcab596eb71e920277dc2b9cad22567..8a7cb1f43046acf8c17572088d250c5396a9b070 100644 (file)
@@ -406,7 +406,6 @@ static int pm8607_regulator_remove(struct platform_device *pdev)
 {
        struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        regulator_unregister(info->regulator);
        return 0;
 }
index 8bb26446037e297ff974200bf3c81e993ff62a47..f1e6ad98eebaa2c784a748e700785af479b80e96 100644 (file)
@@ -250,6 +250,15 @@ config REGULATOR_MAX77686
          via I2C bus. The provided regulator is suitable for
          Exynos-4 chips to control VARM and VINT voltages.
 
+config REGULATOR_MAX77693
+       tristate "Maxim MAX77693 regulator"
+       depends on MFD_MAX77693
+       help
+         This driver controls a Maxim 77693 regulator via I2C bus.
+         The regulators include two LDOs, 'SAFEOUT1', 'SAFEOUT2'
+         and one current regulator 'CHARGER'. This is suitable for
+         Exynos-4x12 chips.
+
 config REGULATOR_PCAP
        tristate "Motorola PCAP2 regulator driver"
        depends on EZX_PCAP
@@ -472,6 +481,16 @@ config REGULATOR_TWL4030
          This driver supports the voltage regulators provided by
          this family of companion chips.
 
+config REGULATOR_TI_ABB
+       bool "TI Adaptive Body Bias on-chip LDO"
+       depends on ARCH_OMAP
+       help
+         Select this option to support Texas Instruments' on-chip Adaptive Body
+         Bias (ABB) LDO regulators. It is recommended that this option be
+         enabled on required TI SoC. Certain Operating Performance Points
+         on TI SoCs may be unstable without enabling this as it provides
+         device specific optimized bias to allow/optimize functionality.
+
 config REGULATOR_VEXPRESS
        tristate "Versatile Express regulators"
        depends on VEXPRESS_CONFIG
index 47a34ff88f981e6f0c96012940bbf24597a47c22..ba4a3cf3afec57eef79179abf72ae1f51d5b3073 100644 (file)
@@ -12,7 +12,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
 obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
 obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
-obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o ab8500-ext.o
+obj-$(CONFIG_REGULATOR_AB8500) += ab8500-ext.o ab8500.o
 obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
 obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
 obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
@@ -41,6 +41,7 @@ obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
 obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
 obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
+obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
@@ -63,6 +64,7 @@ obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
 obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
 obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
+obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
index b4d45472aae6badbe9d63363d6427cad98af8fe4..02ff691cdb8b291b44ecc1569339a9251aa59987 100644 (file)
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/regulator/ab8500.h>
@@ -229,6 +231,28 @@ static unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev *rdev)
        return ret;
 }
 
+static int ab8500_ext_set_voltage(struct regulator_dev *rdev, int min_uV,
+                                 int max_uV, unsigned *selector)
+{
+       struct regulation_constraints *regu_constraints = rdev->constraints;
+
+       if (!regu_constraints) {
+               dev_err(rdev_get_dev(rdev), "No regulator constraints\n");
+               return -EINVAL;
+       }
+
+       if (regu_constraints->min_uV == min_uV &&
+           regu_constraints->max_uV == max_uV)
+               return 0;
+
+       dev_err(rdev_get_dev(rdev),
+               "Requested min %duV max %duV != constrained min %duV max %duV\n",
+               min_uV, max_uV,
+               regu_constraints->min_uV, regu_constraints->max_uV);
+
+       return -EINVAL;
+}
+
 static int ab8500_ext_list_voltage(struct regulator_dev *rdev,
                                   unsigned selector)
 {
@@ -252,6 +276,7 @@ static struct regulator_ops ab8500_ext_regulator_ops = {
        .is_enabled             = ab8500_ext_regulator_is_enabled,
        .set_mode               = ab8500_ext_regulator_set_mode,
        .get_mode               = ab8500_ext_regulator_get_mode,
+       .set_voltage            = ab8500_ext_set_voltage,
        .list_voltage           = ab8500_ext_list_voltage,
 };
 
@@ -310,18 +335,37 @@ static struct ab8500_ext_regulator_info
        },
 };
 
-int ab8500_ext_regulator_init(struct platform_device *pdev)
+static struct of_regulator_match ab8500_ext_regulator_match[] = {
+       { .name = "ab8500_ext1", .driver_data = (void *) AB8500_EXT_SUPPLY1, },
+       { .name = "ab8500_ext2", .driver_data = (void *) AB8500_EXT_SUPPLY2, },
+       { .name = "ab8500_ext3", .driver_data = (void *) AB8500_EXT_SUPPLY3, },
+};
+
+static int ab8500_ext_regulator_probe(struct platform_device *pdev)
 {
        struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
        struct ab8500_platform_data *ppdata;
        struct ab8500_regulator_platform_data *pdata;
+       struct device_node *np = pdev->dev.of_node;
        struct regulator_config config = { };
        int i, err;
 
+       if (np) {
+               err = of_regulator_match(&pdev->dev, np,
+                                        ab8500_ext_regulator_match,
+                                        ARRAY_SIZE(ab8500_ext_regulator_match));
+               if (err < 0) {
+                       dev_err(&pdev->dev,
+                               "Error parsing regulator init data: %d\n", err);
+                       return err;
+               }
+       }
+
        if (!ab8500) {
                dev_err(&pdev->dev, "null mfd parent\n");
                return -EINVAL;
        }
+
        ppdata = dev_get_platdata(ab8500->dev);
        if (!ppdata) {
                dev_err(&pdev->dev, "null parent pdata\n");
@@ -362,8 +406,11 @@ int ab8500_ext_regulator_init(struct platform_device *pdev)
                        pdata->ext_regulator[i].driver_data;
 
                config.dev = &pdev->dev;
-               config.init_data = &pdata->ext_regulator[i];
                config.driver_data = info;
+               config.of_node = ab8500_ext_regulator_match[i].of_node;
+               config.init_data = (np) ?
+                       ab8500_ext_regulator_match[i].init_data :
+                       &pdata->ext_regulator[i];
 
                /* register regulator with framework */
                info->rdev = regulator_register(&info->desc, &config);
@@ -386,7 +433,7 @@ int ab8500_ext_regulator_init(struct platform_device *pdev)
        return 0;
 }
 
-void ab8500_ext_regulator_exit(struct platform_device *pdev)
+static int ab8500_ext_regulator_remove(struct platform_device *pdev)
 {
        int i;
 
@@ -399,7 +446,36 @@ void ab8500_ext_regulator_exit(struct platform_device *pdev)
 
                regulator_unregister(info->rdev);
        }
+
+       return 0;
+}
+
+static struct platform_driver ab8500_ext_regulator_driver = {
+       .probe = ab8500_ext_regulator_probe,
+       .remove = ab8500_ext_regulator_remove,
+       .driver         = {
+               .name   = "ab8500-ext-regulator",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init ab8500_ext_regulator_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&ab8500_ext_regulator_driver);
+       if (ret)
+               pr_err("Failed to register ab8500 ext regulator: %d\n", ret);
+
+       return ret;
+}
+subsys_initcall(ab8500_ext_regulator_init);
+
+static void __exit ab8500_ext_regulator_exit(void)
+{
+       platform_driver_unregister(&ab8500_ext_regulator_driver);
 }
+module_exit(ab8500_ext_regulator_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>");
index a19045ee0ec432ba45a4a023cd26371ecb647e46..603f192e84f1736b5e116baaf07a3ca1eaf0cbaf 100644 (file)
@@ -719,6 +719,7 @@ static struct ab8500_regulator_info
                        .n_voltages     = ARRAY_SIZE(ldo_vauxn_voltages),
                        .volt_table     = ldo_vauxn_voltages,
                        .enable_time    = 200,
+                       .supply_name    = "vin",
                },
                .load_lp_uA             = 5000,
                .update_bank            = 0x04,
@@ -741,6 +742,7 @@ static struct ab8500_regulator_info
                        .n_voltages     = ARRAY_SIZE(ldo_vauxn_voltages),
                        .volt_table     = ldo_vauxn_voltages,
                        .enable_time    = 200,
+                       .supply_name    = "vin",
                },
                .load_lp_uA             = 5000,
                .update_bank            = 0x04,
@@ -763,6 +765,7 @@ static struct ab8500_regulator_info
                        .n_voltages     = ARRAY_SIZE(ldo_vaux3_voltages),
                        .volt_table     = ldo_vaux3_voltages,
                        .enable_time    = 450,
+                       .supply_name    = "vin",
                },
                .load_lp_uA             = 5000,
                .update_bank            = 0x04,
@@ -3156,22 +3159,12 @@ static int ab8500_regulator_probe(struct platform_device *pdev)
                        return err;
        }
 
-       if (!is_ab8505(ab8500)) {
-               /* register external regulators (before Vaux1, 2 and 3) */
-               err = ab8500_ext_regulator_init(pdev);
-               if (err)
-                       return err;
-       }
-
        /* register all regulators */
        for (i = 0; i < abx500_regulator.info_size; i++) {
                err = ab8500_regulator_register(pdev, &pdata->regulator[i],
                                                i, NULL);
-               if (err < 0) {
-                       if (!is_ab8505(ab8500))
-                               ab8500_ext_regulator_exit(pdev);
+               if (err < 0)
                        return err;
-               }
        }
 
        return 0;
@@ -3180,7 +3173,6 @@ static int ab8500_regulator_probe(struct platform_device *pdev)
 static int ab8500_regulator_remove(struct platform_device *pdev)
 {
        int i, err;
-       struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
 
        for (i = 0; i < abx500_regulator.info_size; i++) {
                struct ab8500_regulator_info *info = NULL;
@@ -3192,10 +3184,6 @@ static int ab8500_regulator_remove(struct platform_device *pdev)
                regulator_unregister(info->regulator);
        }
 
-       /* remove external regulators (after Vaux1, 2 and 3) */
-       if (!is_ab8505(ab8500))
-               ab8500_ext_regulator_exit(pdev);
-
        /* remove regulator debug */
        err = ab8500_regulator_debug_exit(pdev);
        if (err)
index 815d6df8bd5f70fab479247c81c6afe7fa746841..288c75abc19034c06e62772ea6b6cc62242da473 100644 (file)
@@ -2137,6 +2137,21 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector)
 }
 EXPORT_SYMBOL_GPL(regulator_list_voltage);
 
+/**
+ * regulator_get_linear_step - return the voltage step size between VSEL values
+ * @regulator: regulator source
+ *
+ * Returns the voltage step size between VSEL values for linear
+ * regulators, or return 0 if the regulator isn't a linear regulator.
+ */
+unsigned int regulator_get_linear_step(struct regulator *regulator)
+{
+       struct regulator_dev *rdev = regulator->rdev;
+
+       return rdev->desc->uV_step;
+}
+EXPORT_SYMBOL_GPL(regulator_get_linear_step);
+
 /**
  * regulator_is_supported_voltage - check if a voltage range can be supported
  *
index d1e5bee2a26b210685290f7bb98d0a5138315a87..b99c49b9aff0a0577009b57fe509f18269d0e9a4 100644 (file)
@@ -130,7 +130,7 @@ static int isl6271a_probe(struct i2c_client *i2c,
                if (i == 0)
                        config.init_data = init_data;
                else
-                       config.init_data = 0;
+                       config.init_data = NULL;
                config.driver_data = pmic;
 
                pmic->rdev[i] = regulator_register(&isl_rd[i], &config);
index d8af9e773310f965865f40630b8c47ebbb612f1c..3809b43816060ca0a4e71fecc024b6c7e472b09d 100644 (file)
@@ -434,7 +434,7 @@ static int lp3971_i2c_probe(struct i2c_client *i2c,
                return -ENODEV;
        }
 
-       lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL);
+       lp3971 = devm_kzalloc(&i2c->dev, sizeof(struct lp3971), GFP_KERNEL);
        if (lp3971 == NULL)
                return -ENOMEM;
 
@@ -449,19 +449,15 @@ static int lp3971_i2c_probe(struct i2c_client *i2c,
                ret = -ENODEV;
        if (ret < 0) {
                dev_err(&i2c->dev, "failed to detect device\n");
-               goto err_detect;
+               return ret;
        }
 
        ret = setup_regulators(lp3971, pdata);
        if (ret < 0)
-               goto err_detect;
+               return ret;
 
        i2c_set_clientdata(i2c, lp3971);
        return 0;
-
-err_detect:
-       kfree(lp3971);
-       return ret;
 }
 
 static int lp3971_i2c_remove(struct i2c_client *i2c)
@@ -473,7 +469,6 @@ static int lp3971_i2c_remove(struct i2c_client *i2c)
                regulator_unregister(lp3971->rdev[i]);
 
        kfree(lp3971->rdev);
-       kfree(lp3971);
 
        return 0;
 }
index 61e4cf9edf6e55b121beb935b405e2010d7ab8dd..573024039ca0c5751fbd5faf31ca2553d0ee91c1 100644 (file)
@@ -528,7 +528,7 @@ static int lp3972_i2c_probe(struct i2c_client *i2c,
                return -ENODEV;
        }
 
-       lp3972 = kzalloc(sizeof(struct lp3972), GFP_KERNEL);
+       lp3972 = devm_kzalloc(&i2c->dev, sizeof(struct lp3972), GFP_KERNEL);
        if (!lp3972)
                return -ENOMEM;
 
@@ -546,19 +546,15 @@ static int lp3972_i2c_probe(struct i2c_client *i2c,
        }
        if (ret < 0) {
                dev_err(&i2c->dev, "failed to detect device. ret = %d\n", ret);
-               goto err_detect;
+               return ret;
        }
 
        ret = setup_regulators(lp3972, pdata);
        if (ret < 0)
-               goto err_detect;
+               return ret;
 
        i2c_set_clientdata(i2c, lp3972);
        return 0;
-
-err_detect:
-       kfree(lp3972);
-       return ret;
 }
 
 static int lp3972_i2c_remove(struct i2c_client *i2c)
@@ -569,7 +565,6 @@ static int lp3972_i2c_remove(struct i2c_client *i2c)
        for (i = 0; i < lp3972->num_regulators; i++)
                regulator_unregister(lp3972->rdev[i]);
        kfree(lp3972->rdev);
-       kfree(lp3972);
 
        return 0;
 }
index f5fc4a142cdf3b5fd9d7ecd293a865883b1b374b..b16336bcd4d46daa099c313fc8cb98b6488ea230 100644 (file)
@@ -18,6 +18,9 @@
 #include <linux/regulator/lp872x.h>
 #include <linux/regulator/driver.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/of_regulator.h>
 
 /* Registers : LP8720/8725 shared */
 #define LP872X_GENERAL_CFG             0x00
@@ -723,8 +726,8 @@ static int lp872x_init_dvs(struct lp872x *lp)
 
        gpio = dvs->gpio;
        if (!gpio_is_valid(gpio)) {
-               dev_err(lp->dev, "invalid gpio: %d\n", gpio);
-               return -EINVAL;
+               dev_warn(lp->dev, "invalid gpio: %d\n", gpio);
+               goto set_default_dvs_mode;
        }
 
        pinstate = dvs->init_state;
@@ -829,6 +832,103 @@ static const struct regmap_config lp872x_regmap_config = {
        .max_register = MAX_REGISTERS,
 };
 
+#ifdef CONFIG_OF
+
+#define LP872X_VALID_OPMODE    (REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL)
+
+static struct of_regulator_match lp8720_matches[] = {
+       { .name = "ldo1", .driver_data = (void *)LP8720_ID_LDO1, },
+       { .name = "ldo2", .driver_data = (void *)LP8720_ID_LDO2, },
+       { .name = "ldo3", .driver_data = (void *)LP8720_ID_LDO3, },
+       { .name = "ldo4", .driver_data = (void *)LP8720_ID_LDO4, },
+       { .name = "ldo5", .driver_data = (void *)LP8720_ID_LDO5, },
+       { .name = "buck", .driver_data = (void *)LP8720_ID_BUCK, },
+};
+
+static struct of_regulator_match lp8725_matches[] = {
+       { .name = "ldo1", .driver_data = (void *)LP8725_ID_LDO1, },
+       { .name = "ldo2", .driver_data = (void *)LP8725_ID_LDO2, },
+       { .name = "ldo3", .driver_data = (void *)LP8725_ID_LDO3, },
+       { .name = "ldo4", .driver_data = (void *)LP8725_ID_LDO4, },
+       { .name = "ldo5", .driver_data = (void *)LP8725_ID_LDO5, },
+       { .name = "lilo1", .driver_data = (void *)LP8725_ID_LILO1, },
+       { .name = "lilo2", .driver_data = (void *)LP8725_ID_LILO2, },
+       { .name = "buck1", .driver_data = (void *)LP8725_ID_BUCK1, },
+       { .name = "buck2", .driver_data = (void *)LP8725_ID_BUCK2, },
+};
+
+static struct lp872x_platform_data
+*lp872x_populate_pdata_from_dt(struct device *dev, enum lp872x_id which)
+{
+       struct device_node *np = dev->of_node;
+       struct lp872x_platform_data *pdata;
+       struct of_regulator_match *match;
+       struct regulator_init_data *d;
+       int num_matches;
+       int count;
+       int i;
+       u8 dvs_state;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               goto out;
+
+       of_property_read_u8(np, "ti,general-config", &pdata->general_config);
+       if (of_find_property(np, "ti,update-config", NULL))
+               pdata->update_config = true;
+
+       pdata->dvs = devm_kzalloc(dev, sizeof(struct lp872x_dvs), GFP_KERNEL);
+       if (!pdata->dvs)
+               goto out;
+
+       pdata->dvs->gpio = of_get_named_gpio(np, "ti,dvs-gpio", 0);
+       of_property_read_u8(np, "ti,dvs-vsel", (u8 *)&pdata->dvs->vsel);
+       of_property_read_u8(np, "ti,dvs-state", &dvs_state);
+       pdata->dvs->init_state = dvs_state ? DVS_HIGH : DVS_LOW;
+
+       if (of_get_child_count(np) == 0)
+               goto out;
+
+       switch (which) {
+       case LP8720:
+               match = lp8720_matches;
+               num_matches = ARRAY_SIZE(lp8720_matches);
+               break;
+       case LP8725:
+               match = lp8725_matches;
+               num_matches = ARRAY_SIZE(lp8725_matches);
+               break;
+       default:
+               goto out;
+       }
+
+       count = of_regulator_match(dev, np, match, num_matches);
+       if (count <= 0)
+               goto out;
+
+       for (i = 0; i < num_matches; i++) {
+               pdata->regulator_data[i].id = (int)match[i].driver_data;
+               pdata->regulator_data[i].init_data = match[i].init_data;
+
+               /* Operation mode configuration for buck/buck1/buck2 */
+               if (strncmp(match[i].name, "buck", 4))
+                       continue;
+
+               d = pdata->regulator_data[i].init_data;
+               d->constraints.valid_modes_mask |= LP872X_VALID_OPMODE;
+               d->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE;
+       }
+out:
+       return pdata;
+}
+#else
+static struct lp872x_platform_data
+*lp872x_populate_pdata_from_dt(struct device *dev, enum lp872x_id which)
+{
+       return NULL;
+}
+#endif
+
 static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 {
        struct lp872x *lp;
@@ -838,6 +938,10 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
                [LP8725] = LP8725_NUM_REGULATORS,
        };
 
+       if (cl->dev.of_node)
+               cl->dev.platform_data = lp872x_populate_pdata_from_dt(&cl->dev,
+                                             (enum lp872x_id)id->driver_data);
+
        lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL);
        if (!lp)
                goto err_mem;
@@ -882,6 +986,13 @@ static int lp872x_remove(struct i2c_client *cl)
        return 0;
 }
 
+static const struct of_device_id lp872x_dt_ids[] = {
+       { .compatible = "ti,lp8720", },
+       { .compatible = "ti,lp8725", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, lp872x_dt_ids);
+
 static const struct i2c_device_id lp872x_ids[] = {
        {"lp8720", LP8720},
        {"lp8725", LP8725},
@@ -893,6 +1004,7 @@ static struct i2c_driver lp872x_driver = {
        .driver = {
                .name = "lp872x",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(lp872x_dt_ids),
        },
        .probe = lp872x_probe,
        .remove = lp872x_remove,
index f0f6ea05065bcb4dd1dacdb84f6b362c237c21e8..d9e38b4c2adcd45b39bceba1b7b7b80dff09234d 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
 #include <linux/regmap.h>
-#include <linux/delay.h>
 #include <linux/uaccess.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
index eb1e1e88ae512b819307a37f4cf92a6e2a610daa..0b015f2a7fd9e3dd33c0928421f55441b1459467 100644 (file)
@@ -533,7 +533,6 @@ static int lp8788_buck_remove(struct platform_device *pdev)
 {
        struct lp8788_buck *buck = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        regulator_unregister(buck->regulator);
 
        return 0;
index 0ce2c4c194b358fa0a7347674ffe2cc5cfd41b61..0527d87c6dd5adea8c7614ecc61f44fc8599f5f6 100644 (file)
@@ -561,7 +561,6 @@ static int lp8788_dldo_remove(struct platform_device *pdev)
 {
        struct lp8788_ldo *ldo = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        regulator_unregister(ldo->regulator);
 
        return 0;
@@ -622,7 +621,6 @@ static int lp8788_aldo_remove(struct platform_device *pdev)
 {
        struct lp8788_ldo *ldo = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        regulator_unregister(ldo->regulator);
 
        return 0;
index 20935b1a6ed4fd85a4061f0d80fe94dfc529b9f6..f563057e56904c868a5344a43e80e41e97ced60d 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <linux/kernel.h>
 #include <linux/bug.h>
-#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c
new file mode 100644 (file)
index 0000000..ce4b96c
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * max77693.c - Regulator driver for the Maxim 77693
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Jonghwa Lee <jonghwa3.lee@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max77686.c
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/max77693.h>
+#include <linux/mfd/max77693-private.h>
+#include <linux/regulator/of_regulator.h>
+
+#define CHGIN_ILIM_STEP_20mA                   20000
+
+struct max77693_pmic_dev {
+       struct device *dev;
+       struct max77693_dev *iodev;
+       int num_regulators;
+       struct regulator_dev **rdev;
+};
+
+/* CHARGER regulator ops */
+/* CHARGER regulator uses two bits for enabling */
+static int max77693_chg_is_enabled(struct regulator_dev *rdev)
+{
+       int ret;
+       u8 val;
+
+       ret = max77693_read_reg(rdev->regmap, rdev->desc->enable_reg, &val);
+       if (ret)
+               return ret;
+
+       return (val & rdev->desc->enable_mask) == rdev->desc->enable_mask;
+}
+
+/*
+ * CHARGER regulator - Min : 20mA, Max : 2580mA, step : 20mA
+ * 0x00, 0x01, 0x2, 0x03       = 60 mA
+ * 0x04 ~ 0x7E                 = (60 + (X - 3) * 20) mA
+ */
+static int max77693_chg_get_current_limit(struct regulator_dev *rdev)
+{
+       unsigned int chg_min_uA = rdev->constraints->min_uA;
+       unsigned int chg_max_uA = rdev->constraints->max_uA;
+       u8 reg, sel;
+       unsigned int val;
+       int ret;
+
+       ret = max77693_read_reg(rdev->regmap,
+                               MAX77693_CHG_REG_CHG_CNFG_09, &reg);
+       if (ret < 0)
+               return ret;
+
+       sel = reg & CHG_CNFG_09_CHGIN_ILIM_MASK;
+
+       /* the first four codes for charger current are all 60mA */
+       if (sel <= 3)
+               sel = 0;
+       else
+               sel -= 3;
+
+       val = chg_min_uA + CHGIN_ILIM_STEP_20mA * sel;
+       if (val > chg_max_uA)
+               return -EINVAL;
+
+       return val;
+}
+
+static int max77693_chg_set_current_limit(struct regulator_dev *rdev,
+                                               int min_uA, int max_uA)
+{
+       unsigned int chg_min_uA = rdev->constraints->min_uA;
+       int sel = 0;
+
+       while (chg_min_uA + CHGIN_ILIM_STEP_20mA * sel < min_uA)
+               sel++;
+
+       if (chg_min_uA + CHGIN_ILIM_STEP_20mA * sel > max_uA)
+               return -EINVAL;
+
+       /* the first four codes for charger current are all 60mA */
+       sel += 3;
+
+       return max77693_write_reg(rdev->regmap,
+                               MAX77693_CHG_REG_CHG_CNFG_09, sel);
+}
+/* end of CHARGER regulator ops */
+
+static const unsigned int max77693_safeout_table[] = {
+       4850000,
+       4900000,
+       4950000,
+       3300000,
+};
+
+static struct regulator_ops max77693_safeout_ops = {
+       .list_voltage           = regulator_list_voltage_table,
+       .is_enabled             = regulator_is_enabled_regmap,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+};
+
+static struct regulator_ops max77693_charger_ops = {
+       .is_enabled             = max77693_chg_is_enabled,
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .get_current_limit      = max77693_chg_get_current_limit,
+       .set_current_limit      = max77693_chg_set_current_limit,
+};
+
+#define regulator_desc_esafeout(_num)  {                       \
+       .name           = "ESAFEOUT"#_num,                      \
+       .id             = MAX77693_ESAFEOUT##_num,              \
+       .n_voltages     = 4,                                    \
+       .ops            = &max77693_safeout_ops,                \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .volt_table     = max77693_safeout_table,               \
+       .vsel_reg       = MAX77693_CHG_REG_SAFEOUT_CTRL,        \
+       .vsel_mask      = SAFEOUT_CTRL_SAFEOUT##_num##_MASK,    \
+       .enable_reg     = MAX77693_CHG_REG_SAFEOUT_CTRL,        \
+       .enable_mask    = SAFEOUT_CTRL_ENSAFEOUT##_num##_MASK , \
+}
+
+static struct regulator_desc regulators[] = {
+       regulator_desc_esafeout(1),
+       regulator_desc_esafeout(2),
+       {
+               .name = "CHARGER",
+               .id = MAX77693_CHARGER,
+               .ops = &max77693_charger_ops,
+               .type = REGULATOR_CURRENT,
+               .owner = THIS_MODULE,
+               .enable_reg = MAX77693_CHG_REG_CHG_CNFG_00,
+               .enable_mask = CHG_CNFG_00_CHG_MASK |
+                               CHG_CNFG_00_BUCK_MASK,
+       },
+};
+
+#ifdef CONFIG_OF
+static int max77693_pmic_dt_parse_rdata(struct device *dev,
+                                       struct max77693_regulator_data **rdata)
+{
+       struct device_node *np;
+       struct of_regulator_match *rmatch;
+       struct max77693_regulator_data *tmp;
+       int i, matched = 0;
+
+       np = of_find_node_by_name(dev->parent->of_node, "regulators");
+       if (!np)
+               return -EINVAL;
+
+       rmatch = devm_kzalloc(dev,
+                sizeof(*rmatch) * ARRAY_SIZE(regulators), GFP_KERNEL);
+       if (!rmatch)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(regulators); i++)
+               rmatch[i].name = regulators[i].name;
+
+       matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(regulators));
+       if (matched <= 0)
+               return matched;
+       *rdata = devm_kzalloc(dev, sizeof(**rdata) * matched, GFP_KERNEL);
+       if (!(*rdata))
+               return -ENOMEM;
+
+       tmp = *rdata;
+
+       for (i = 0; i < matched; i++) {
+               tmp->initdata = rmatch[i].init_data;
+               tmp->of_node = rmatch[i].of_node;
+               tmp->id = regulators[i].id;
+               tmp++;
+       }
+
+       return matched;
+}
+#else
+static int max77693_pmic_dt_parse_rdata(struct device *dev,
+                                       struct max77693_regulator_data **rdata)
+{
+       return 0;
+}
+#endif /* CONFIG_OF */
+
+static int max77693_pmic_init_rdata(struct device *dev,
+                                   struct max77693_regulator_data **rdata)
+{
+       struct max77693_platform_data *pdata;
+       int num_regulators = 0;
+
+       pdata = dev_get_platdata(dev->parent);
+       if (pdata) {
+               *rdata = pdata->regulators;
+               num_regulators = pdata->num_regulators;
+       }
+
+       if (!(*rdata) && dev->parent->of_node)
+               num_regulators = max77693_pmic_dt_parse_rdata(dev, rdata);
+
+       return num_regulators;
+}
+
+static int max77693_pmic_probe(struct platform_device *pdev)
+{
+       struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max77693_pmic_dev *max77693_pmic;
+       struct max77693_regulator_data *rdata = NULL;
+       int num_rdata, i, ret;
+       struct regulator_config config;
+
+       num_rdata = max77693_pmic_init_rdata(&pdev->dev, &rdata);
+       if (!rdata || num_rdata <= 0) {
+               dev_err(&pdev->dev, "No init data supplied.\n");
+               return -ENODEV;
+       }
+
+       max77693_pmic = devm_kzalloc(&pdev->dev,
+                               sizeof(struct max77693_pmic_dev),
+                               GFP_KERNEL);
+       if (!max77693_pmic)
+               return -ENOMEM;
+
+       max77693_pmic->rdev = devm_kzalloc(&pdev->dev,
+                               sizeof(struct regulator_dev *) * num_rdata,
+                               GFP_KERNEL);
+       if (!max77693_pmic->rdev)
+               return -ENOMEM;
+
+       max77693_pmic->dev = &pdev->dev;
+       max77693_pmic->iodev = iodev;
+       max77693_pmic->num_regulators = num_rdata;
+
+       config.dev = &pdev->dev;
+       config.regmap = iodev->regmap;
+       config.driver_data = max77693_pmic;
+       platform_set_drvdata(pdev, max77693_pmic);
+
+       for (i = 0; i < max77693_pmic->num_regulators; i++) {
+               int id = rdata[i].id;
+
+               config.init_data = rdata[i].initdata;
+               config.of_node = rdata[i].of_node;
+
+               max77693_pmic->rdev[i] = regulator_register(&regulators[id],
+                                                           &config);
+               if (IS_ERR(max77693_pmic->rdev[i])) {
+                       ret = PTR_ERR(max77693_pmic->rdev[i]);
+                       dev_err(max77693_pmic->dev,
+                               "Failed to initialize regulator-%d\n", id);
+                       max77693_pmic->rdev[i] = NULL;
+                       goto err;
+               }
+       }
+
+       return 0;
+ err:
+       while (--i >= 0)
+               regulator_unregister(max77693_pmic->rdev[i]);
+
+       return ret;
+}
+
+static int max77693_pmic_remove(struct platform_device *pdev)
+{
+       struct max77693_pmic_dev *max77693_pmic = platform_get_drvdata(pdev);
+       struct regulator_dev **rdev = max77693_pmic->rdev;
+       int i;
+
+       for (i = 0; i < max77693_pmic->num_regulators; i++)
+               if (rdev[i])
+                       regulator_unregister(rdev[i]);
+
+       return 0;
+}
+
+static const struct platform_device_id max77693_pmic_id[] = {
+       {"max77693-pmic", 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(platform, max77693_pmic_id);
+
+static struct platform_driver max77693_pmic_driver = {
+       .driver = {
+                  .name = "max77693-pmic",
+                  .owner = THIS_MODULE,
+                  },
+       .probe = max77693_pmic_probe,
+       .remove = max77693_pmic_remove,
+       .id_table = max77693_pmic_id,
+};
+
+module_platform_driver(max77693_pmic_driver);
+
+MODULE_DESCRIPTION("MAXIM MAX77693 regulator driver");
+MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
+MODULE_LICENSE("GPL");
index 3597da8f0dca6341720be5b40b4459682cc74f50..e6d54a546d36d40c68aeb0b623c8d83fee79ef0f 100644 (file)
@@ -327,7 +327,6 @@ static int max8925_regulator_remove(struct platform_device *pdev)
 {
        struct regulator_dev *rdev = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        regulator_unregister(rdev);
 
        return 0;
index adb1414e5e37f3f72a95c744f30d04a890980005..0c5195a842e2ee68b5568f8e1c9cd85081a9df17 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/max8973-regulator.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
@@ -100,6 +102,7 @@ struct max8973_chip {
        int curr_vout_reg;
        int curr_gpio_val;
        bool valid_dvs_gpio;
+       struct regulator_ops ops;
 };
 
 /*
@@ -240,7 +243,7 @@ static unsigned int max8973_dcdc_get_mode(struct regulator_dev *rdev)
                REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
 }
 
-static struct regulator_ops max8973_dcdc_ops = {
+static const struct regulator_ops max8973_dcdc_ops = {
        .get_voltage_sel        = max8973_dcdc_get_voltage_sel,
        .set_voltage_sel        = max8973_dcdc_set_voltage_sel,
        .list_voltage           = regulator_list_voltage_linear,
@@ -369,7 +372,8 @@ static int max8973_probe(struct i2c_client *client,
        int ret;
 
        pdata = client->dev.platform_data;
-       if (!pdata) {
+
+       if (!pdata && !client->dev.of_node) {
                dev_err(&client->dev, "No Platform data");
                return -EIO;
        }
@@ -388,30 +392,36 @@ static int max8973_probe(struct i2c_client *client,
        }
 
        i2c_set_clientdata(client, max);
+       max->ops = max8973_dcdc_ops;
        max->dev = &client->dev;
        max->desc.name = id->name;
        max->desc.id = 0;
-       max->desc.ops = &max8973_dcdc_ops;
+       max->desc.ops = &max->ops;
        max->desc.type = REGULATOR_VOLTAGE;
        max->desc.owner = THIS_MODULE;
        max->desc.min_uV = MAX8973_MIN_VOLATGE;
        max->desc.uV_step = MAX8973_VOLATGE_STEP;
        max->desc.n_voltages = MAX8973_BUCK_N_VOLTAGE;
 
-       if (!pdata->enable_ext_control) {
+       if (!pdata || !pdata->enable_ext_control) {
                max->desc.enable_reg = MAX8973_VOUT;
                max->desc.enable_mask = MAX8973_VOUT_ENABLE;
-               max8973_dcdc_ops.enable = regulator_enable_regmap;
-               max8973_dcdc_ops.disable = regulator_disable_regmap;
-               max8973_dcdc_ops.is_enabled = regulator_is_enabled_regmap;
+               max->ops.enable = regulator_enable_regmap;
+               max->ops.disable = regulator_disable_regmap;
+               max->ops.is_enabled = regulator_is_enabled_regmap;
+       }
+
+       if (pdata) {
+               max->dvs_gpio = pdata->dvs_gpio;
+               max->enable_external_control = pdata->enable_ext_control;
+               max->curr_gpio_val = pdata->dvs_def_state;
+               max->curr_vout_reg = MAX8973_VOUT + pdata->dvs_def_state;
+       } else {
+               max->dvs_gpio = -EINVAL;
+               max->curr_vout_reg = MAX8973_VOUT;
        }
 
-       max->enable_external_control = pdata->enable_ext_control;
-       max->dvs_gpio = pdata->dvs_gpio;
-       max->curr_gpio_val = pdata->dvs_def_state;
-       max->curr_vout_reg = MAX8973_VOUT + pdata->dvs_def_state;
        max->lru_index[0] = max->curr_vout_reg;
-       max->valid_dvs_gpio = false;
 
        if (gpio_is_valid(max->dvs_gpio)) {
                int gpio_flags;
@@ -437,16 +447,21 @@ static int max8973_probe(struct i2c_client *client,
                        max->lru_index[i] = i;
                max->lru_index[0] = max->curr_vout_reg;
                max->lru_index[max->curr_vout_reg] = 0;
+       } else {
+               max->valid_dvs_gpio = false;
        }
 
-       ret = max8973_init_dcdc(max, pdata);
-       if (ret < 0) {
-               dev_err(max->dev, "Max8973 Init failed, err = %d\n", ret);
-               return ret;
+       if (pdata) {
+               ret = max8973_init_dcdc(max, pdata);
+               if (ret < 0) {
+                       dev_err(max->dev, "Max8973 Init failed, err = %d\n", ret);
+                       return ret;
+               }
        }
 
        config.dev = &client->dev;
-       config.init_data = pdata->reg_init_data;
+       config.init_data = pdata ? pdata->reg_init_data :
+               of_get_regulator_init_data(&client->dev, client->dev.of_node);
        config.driver_data = max;
        config.of_node = client->dev.of_node;
        config.regmap = max->regmap;
index fdf7f0a090903cadcb6f3e0348dfe0bdf4e0c4be..5ff99d2703db0db55e947be9cf88a6fca46c53cc 100644 (file)
@@ -466,8 +466,6 @@ static int mc13783_regulator_remove(struct platform_device *pdev)
        struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
        int i;
 
-       platform_set_drvdata(pdev, NULL);
-
        for (i = 0; i < priv->num_regulators; i++)
                regulator_unregister(priv->regulators[i]);
 
index b716283a8760b214ef189b4fb771726d2585f548..1037e07937cfba7080de781a0db63b42cb6db679 100644 (file)
@@ -636,8 +636,6 @@ static int mc13892_regulator_remove(struct platform_device *pdev)
        struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
        int i;
 
-       platform_set_drvdata(pdev, NULL);
-
        for (i = 0; i < priv->num_regulators; i++)
                regulator_unregister(priv->regulators[i]);
 
index 66ca769287ab3427aa9ac8695ad5a67ca5dc77c3..f3c8f8f9dc39d48e8b586cb808cfdc568ae67d27 100644 (file)
@@ -61,6 +61,9 @@ static void of_get_regulation_constraints(struct device_node *np,
        else /* status change should be possible if not always on. */
                constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
 
+       if (of_property_read_bool(np, "regulator-allow-bypass"))
+               constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
+
        ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL);
        if (ramp_delay)
                constraints->ramp_delay = be32_to_cpu(*ramp_delay);
index 4899342f1fc12cba02790a094c4be82f5ec30b15..1a73a297fe730533cc6be23469eee0014f6dbe80 100644 (file)
@@ -260,7 +260,6 @@ static int pcap_regulator_remove(struct platform_device *pdev)
        struct regulator_dev *rdev = platform_get_drvdata(pdev);
 
        regulator_unregister(rdev);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 534075e13d6dba59e5f21b4db91fb3b0d9acdb25..54df9f7cb504b7da2f4b6c6b26c8389bcdd3f117 100644 (file)
@@ -106,7 +106,6 @@ static int pcf50633_regulator_remove(struct platform_device *pdev)
 {
        struct regulator_dev *rdev = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        regulator_unregister(rdev);
 
        return 0;
index cd9ea2ea1826bc5e6b40de856b4884637eae3103..c9f16e17920fc2005e9a165fd28a343073c83c14 100644 (file)
@@ -12,7 +12,6 @@
  */
 
 #include <linux/bug.h>
-#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c
new file mode 100644 (file)
index 0000000..3753ed0
--- /dev/null
@@ -0,0 +1,910 @@
+/*
+ * Texas Instruments SoC Adaptive Body Bias(ABB) Regulator
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Mike Turquette <mturquette@ti.com>
+ *
+ * Copyright (C) 2012-2013 Texas Instruments, Inc.
+ * Andrii Tseglytskyi <andrii.tseglytskyi@ti.com>
+ * Nishanth Menon <nm@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 "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+/*
+ * ABB LDO operating states:
+ * NOMINAL_OPP:        bypasses the ABB LDO
+ * FAST_OPP:   sets ABB LDO to Forward Body-Bias
+ * SLOW_OPP:   sets ABB LDO to Reverse Body-Bias
+ */
+#define TI_ABB_NOMINAL_OPP     0
+#define TI_ABB_FAST_OPP                1
+#define TI_ABB_SLOW_OPP                3
+
+/**
+ * struct ti_abb_info - ABB information per voltage setting
+ * @opp_sel:   one of TI_ABB macro
+ * @vset:      (optional) vset value that LDOVBB needs to be overriden with.
+ *
+ * Array of per voltage entries organized in the same order as regulator_desc's
+ * volt_table list. (selector is used to index from this array)
+ */
+struct ti_abb_info {
+       u32 opp_sel;
+       u32 vset;
+};
+
+/**
+ * struct ti_abb_reg - Register description for ABB block
+ * @setup_reg:                 setup register offset from base
+ * @control_reg:               control register offset from base
+ * @sr2_wtcnt_value_mask:      setup register- sr2_wtcnt_value mask
+ * @fbb_sel_mask:              setup register- FBB sel mask
+ * @rbb_sel_mask:              setup register- RBB sel mask
+ * @sr2_en_mask:               setup register- enable mask
+ * @opp_change_mask:           control register - mask to trigger LDOVBB change
+ * @opp_sel_mask:              control register - mask for mode to operate
+ */
+struct ti_abb_reg {
+       u32 setup_reg;
+       u32 control_reg;
+
+       /* Setup register fields */
+       u32 sr2_wtcnt_value_mask;
+       u32 fbb_sel_mask;
+       u32 rbb_sel_mask;
+       u32 sr2_en_mask;
+
+       /* Control register fields */
+       u32 opp_change_mask;
+       u32 opp_sel_mask;
+};
+
+/**
+ * struct ti_abb - ABB instance data
+ * @rdesc:                     regulator descriptor
+ * @clk:                       clock(usually sysclk) supplying ABB block
+ * @base:                      base address of ABB block
+ * @int_base:                  interrupt register base address
+ * @efuse_base:                        (optional) efuse base address for ABB modes
+ * @ldo_base:                  (optional) LDOVBB vset override base address
+ * @regs:                      pointer to struct ti_abb_reg for ABB block
+ * @txdone_mask:               mask on int_base for tranxdone interrupt
+ * @ldovbb_override_mask:      mask to ldo_base for overriding default LDO VBB
+ *                             vset with value from efuse
+ * @ldovbb_vset_mask:          mask to ldo_base for providing the VSET override
+ * @info:                      array to per voltage ABB configuration
+ * @current_info_idx:          current index to info
+ * @settling_time:             SoC specific settling time for LDO VBB
+ */
+struct ti_abb {
+       struct regulator_desc rdesc;
+       struct clk *clk;
+       void __iomem *base;
+       void __iomem *int_base;
+       void __iomem *efuse_base;
+       void __iomem *ldo_base;
+
+       const struct ti_abb_reg *regs;
+       u32 txdone_mask;
+       u32 ldovbb_override_mask;
+       u32 ldovbb_vset_mask;
+
+       struct ti_abb_info *info;
+       int current_info_idx;
+
+       u32 settling_time;
+};
+
+/**
+ * ti_abb_rmw() - handy wrapper to set specific register bits
+ * @mask:      mask for register field
+ * @value:     value shifted to mask location and written
+ * @offset:    offset of register
+ * @base:      base address
+ *
+ * Return: final register value (may be unused)
+ */
+static inline u32 ti_abb_rmw(u32 mask, u32 value, u32 offset,
+                            void __iomem *base)
+{
+       u32 val;
+
+       val = readl(base + offset);
+       val &= ~mask;
+       val |= (value << __ffs(mask)) & mask;
+       writel(val, base + offset);
+
+       return val;
+}
+
+/**
+ * ti_abb_check_txdone() - handy wrapper to check ABB tranxdone status
+ * @abb:       pointer to the abb instance
+ *
+ * Return: true or false
+ */
+static inline bool ti_abb_check_txdone(const struct ti_abb *abb)
+{
+       return !!(readl(abb->int_base) & abb->txdone_mask);
+}
+
+/**
+ * ti_abb_clear_txdone() - handy wrapper to clear ABB tranxdone status
+ * @abb:       pointer to the abb instance
+ */
+static inline void ti_abb_clear_txdone(const struct ti_abb *abb)
+{
+       writel(abb->txdone_mask, abb->int_base);
+};
+
+/**
+ * ti_abb_wait_tranx() - waits for ABB tranxdone event
+ * @dev:       device
+ * @abb:       pointer to the abb instance
+ *
+ * Return: 0 on success or -ETIMEDOUT if the event is not cleared on time.
+ */
+static int ti_abb_wait_txdone(struct device *dev, struct ti_abb *abb)
+{
+       int timeout = 0;
+       bool status;
+
+       while (timeout++ <= abb->settling_time) {
+               status = ti_abb_check_txdone(abb);
+               if (status)
+                       break;
+
+               udelay(1);
+       }
+
+       if (timeout > abb->settling_time) {
+               dev_warn_ratelimited(dev,
+                                    "%s:TRANXDONE timeout(%duS) int=0x%08x\n",
+                                    __func__, timeout, readl(abb->int_base));
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+/**
+ * ti_abb_clear_all_txdone() - clears ABB tranxdone event
+ * @dev:       device
+ * @abb:       pointer to the abb instance
+ *
+ * Return: 0 on success or -ETIMEDOUT if the event is not cleared on time.
+ */
+static int ti_abb_clear_all_txdone(struct device *dev, const struct ti_abb *abb)
+{
+       int timeout = 0;
+       bool status;
+
+       while (timeout++ <= abb->settling_time) {
+               ti_abb_clear_txdone(abb);
+
+               status = ti_abb_check_txdone(abb);
+               if (!status)
+                       break;
+
+               udelay(1);
+       }
+
+       if (timeout > abb->settling_time) {
+               dev_warn_ratelimited(dev,
+                                    "%s:TRANXDONE timeout(%duS) int=0x%08x\n",
+                                    __func__, timeout, readl(abb->int_base));
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+/**
+ * ti_abb_program_ldovbb() - program LDOVBB register for override value
+ * @dev:       device
+ * @abb:       pointer to the abb instance
+ * @info:      ABB info to program
+ */
+static void ti_abb_program_ldovbb(struct device *dev, const struct ti_abb *abb,
+                                 struct ti_abb_info *info)
+{
+       u32 val;
+
+       val = readl(abb->ldo_base);
+       /* clear up previous values */
+       val &= ~(abb->ldovbb_override_mask | abb->ldovbb_vset_mask);
+
+       switch (info->opp_sel) {
+       case TI_ABB_SLOW_OPP:
+       case TI_ABB_FAST_OPP:
+               val |= abb->ldovbb_override_mask;
+               val |= info->vset << __ffs(abb->ldovbb_vset_mask);
+               break;
+       }
+
+       writel(val, abb->ldo_base);
+}
+
+/**
+ * ti_abb_set_opp() - Setup ABB and LDO VBB for required bias
+ * @rdev:      regulator device
+ * @abb:       pointer to the abb instance
+ * @info:      ABB info to program
+ *
+ * Return: 0 on success or appropriate error value when fails
+ */
+static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,
+                         struct ti_abb_info *info)
+{
+       const struct ti_abb_reg *regs = abb->regs;
+       struct device *dev = &rdev->dev;
+       int ret;
+
+       ret = ti_abb_clear_all_txdone(dev, abb);
+       if (ret)
+               goto out;
+
+       ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, regs->setup_reg,
+                  abb->base);
+
+       switch (info->opp_sel) {
+       case TI_ABB_SLOW_OPP:
+               ti_abb_rmw(regs->rbb_sel_mask, 1, regs->setup_reg, abb->base);
+               break;
+       case TI_ABB_FAST_OPP:
+               ti_abb_rmw(regs->fbb_sel_mask, 1, regs->setup_reg, abb->base);
+               break;
+       }
+
+       /* program next state of ABB ldo */
+       ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg,
+                  abb->base);
+
+       /* program LDO VBB vset override if needed */
+       if (abb->ldo_base)
+               ti_abb_program_ldovbb(dev, abb, info);
+
+       /* Initiate ABB ldo change */
+       ti_abb_rmw(regs->opp_change_mask, 1, regs->control_reg, abb->base);
+
+       /* Wait for ABB LDO to complete transition to new Bias setting */
+       ret = ti_abb_wait_txdone(dev, abb);
+       if (ret)
+               goto out;
+
+       ret = ti_abb_clear_all_txdone(dev, abb);
+       if (ret)
+               goto out;
+
+out:
+       return ret;
+}
+
+/**
+ * ti_abb_set_voltage_sel() - regulator accessor function to set ABB LDO
+ * @rdev:      regulator device
+ * @sel:       selector to index into required ABB LDO settings (maps to
+ *             regulator descriptor's volt_table)
+ *
+ * Return: 0 on success or appropriate error value when fails
+ */
+static int ti_abb_set_voltage_sel(struct regulator_dev *rdev, unsigned sel)
+{
+       const struct regulator_desc *desc = rdev->desc;
+       struct ti_abb *abb = rdev_get_drvdata(rdev);
+       struct device *dev = &rdev->dev;
+       struct ti_abb_info *info, *oinfo;
+       int ret = 0;
+
+       if (!abb) {
+               dev_err_ratelimited(dev, "%s: No regulator drvdata\n",
+                                   __func__);
+               return -ENODEV;
+       }
+
+       if (!desc->n_voltages || !abb->info) {
+               dev_err_ratelimited(dev,
+                                   "%s: No valid voltage table entries?\n",
+                                   __func__);
+               return -EINVAL;
+       }
+
+       if (sel >= desc->n_voltages) {
+               dev_err(dev, "%s: sel idx(%d) >= n_voltages(%d)\n", __func__,
+                       sel, desc->n_voltages);
+               return -EINVAL;
+       }
+
+       /* If we are in the same index as we were, nothing to do here! */
+       if (sel == abb->current_info_idx) {
+               dev_dbg(dev, "%s: Already at sel=%d\n", __func__, sel);
+               return ret;
+       }
+
+       /* If data is exactly the same, then just update index, no change */
+       info = &abb->info[sel];
+       oinfo = &abb->info[abb->current_info_idx];
+       if (!memcmp(info, oinfo, sizeof(*info))) {
+               dev_dbg(dev, "%s: Same data new idx=%d, old idx=%d\n", __func__,
+                       sel, abb->current_info_idx);
+               goto out;
+       }
+
+       ret = ti_abb_set_opp(rdev, abb, info);
+
+out:
+       if (!ret)
+               abb->current_info_idx = sel;
+       else
+               dev_err_ratelimited(dev,
+                                   "%s: Volt[%d] idx[%d] mode[%d] Fail(%d)\n",
+                                   __func__, desc->volt_table[sel], sel,
+                                   info->opp_sel, ret);
+       return ret;
+}
+
+/**
+ * ti_abb_get_voltage_sel() - Regulator accessor to get current ABB LDO setting
+ * @rdev:      regulator device
+ *
+ * Return: 0 on success or appropriate error value when fails
+ */
+static int ti_abb_get_voltage_sel(struct regulator_dev *rdev)
+{
+       const struct regulator_desc *desc = rdev->desc;
+       struct ti_abb *abb = rdev_get_drvdata(rdev);
+       struct device *dev = &rdev->dev;
+
+       if (!abb) {
+               dev_err_ratelimited(dev, "%s: No regulator drvdata\n",
+                                   __func__);
+               return -ENODEV;
+       }
+
+       if (!desc->n_voltages || !abb->info) {
+               dev_err_ratelimited(dev,
+                                   "%s: No valid voltage table entries?\n",
+                                   __func__);
+               return -EINVAL;
+       }
+
+       if (abb->current_info_idx >= (int)desc->n_voltages) {
+               dev_err(dev, "%s: Corrupted data? idx(%d) >= n_voltages(%d)\n",
+                       __func__, abb->current_info_idx, desc->n_voltages);
+               return -EINVAL;
+       }
+
+       return abb->current_info_idx;
+}
+
+/**
+ * ti_abb_init_timings() - setup ABB clock timing for the current platform
+ * @dev:       device
+ * @abb:       pointer to the abb instance
+ *
+ * Return: 0 if timing is updated, else returns error result.
+ */
+static int ti_abb_init_timings(struct device *dev, struct ti_abb *abb)
+{
+       u32 clock_cycles;
+       u32 clk_rate, sr2_wt_cnt_val, cycle_rate;
+       const struct ti_abb_reg *regs = abb->regs;
+       int ret;
+       char *pname = "ti,settling-time";
+
+       /* read device tree properties */
+       ret = of_property_read_u32(dev->of_node, pname, &abb->settling_time);
+       if (ret) {
+               dev_err(dev, "Unable to get property '%s'(%d)\n", pname, ret);
+               return ret;
+       }
+
+       /* ABB LDO cannot be settle in 0 time */
+       if (!abb->settling_time) {
+               dev_err(dev, "Invalid property:'%s' set as 0!\n", pname);
+               return -EINVAL;
+       }
+
+       pname = "ti,clock-cycles";
+       ret = of_property_read_u32(dev->of_node, pname, &clock_cycles);
+       if (ret) {
+               dev_err(dev, "Unable to get property '%s'(%d)\n", pname, ret);
+               return ret;
+       }
+       /* ABB LDO cannot be settle in 0 clock cycles */
+       if (!clock_cycles) {
+               dev_err(dev, "Invalid property:'%s' set as 0!\n", pname);
+               return -EINVAL;
+       }
+
+       abb->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(abb->clk)) {
+               ret = PTR_ERR(abb->clk);
+               dev_err(dev, "%s: Unable to get clk(%d)\n", __func__, ret);
+               return ret;
+       }
+
+       /*
+        * SR2_WTCNT_VALUE is the settling time for the ABB ldo after a
+        * transition and must be programmed with the correct time at boot.
+        * The value programmed into the register is the number of SYS_CLK
+        * clock cycles that match a given wall time profiled for the ldo.
+        * This value depends on:
+        * settling time of ldo in micro-seconds (varies per OMAP family)
+        * # of clock cycles per SYS_CLK period (varies per OMAP family)
+        * the SYS_CLK frequency in MHz (varies per board)
+        * The formula is:
+        *
+        *                      ldo settling time (in micro-seconds)
+        * SR2_WTCNT_VALUE = ------------------------------------------
+        *                   (# system clock cycles) * (sys_clk period)
+        *
+        * Put another way:
+        *
+        * SR2_WTCNT_VALUE = settling time / (# SYS_CLK cycles / SYS_CLK rate))
+        *
+        * To avoid dividing by zero multiply both "# clock cycles" and
+        * "settling time" by 10 such that the final result is the one we want.
+        */
+
+       /* Convert SYS_CLK rate to MHz & prevent divide by zero */
+       clk_rate = DIV_ROUND_CLOSEST(clk_get_rate(abb->clk), 1000000);
+
+       /* Calculate cycle rate */
+       cycle_rate = DIV_ROUND_CLOSEST(clock_cycles * 10, clk_rate);
+
+       /* Calulate SR2_WTCNT_VALUE */
+       sr2_wt_cnt_val = DIV_ROUND_CLOSEST(abb->settling_time * 10, cycle_rate);
+
+       dev_dbg(dev, "%s: Clk_rate=%ld, sr2_cnt=0x%08x\n", __func__,
+               clk_get_rate(abb->clk), sr2_wt_cnt_val);
+
+       ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, regs->setup_reg,
+                  abb->base);
+
+       return 0;
+}
+
+/**
+ * ti_abb_init_table() - Initialize ABB table from device tree
+ * @dev:       device
+ * @abb:       pointer to the abb instance
+ * @rinit_data:        regulator initdata
+ *
+ * Return: 0 on success or appropriate error value when fails
+ */
+static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,
+                            struct regulator_init_data *rinit_data)
+{
+       struct ti_abb_info *info;
+       const struct property *prop;
+       const __be32 *abb_info;
+       const u32 num_values = 6;
+       char *pname = "ti,abb_info";
+       u32 num_entries, i;
+       unsigned int *volt_table;
+       int min_uV = INT_MAX, max_uV = 0;
+       struct regulation_constraints *c = &rinit_data->constraints;
+
+       prop = of_find_property(dev->of_node, pname, NULL);
+       if (!prop) {
+               dev_err(dev, "No '%s' property?\n", pname);
+               return -ENODEV;
+       }
+
+       if (!prop->value) {
+               dev_err(dev, "Empty '%s' property?\n", pname);
+               return -ENODATA;
+       }
+
+       /*
+        * Each abb_info is a set of n-tuple, where n is num_values, consisting
+        * of voltage and a set of detection logic for ABB information for that
+        * voltage to apply.
+        */
+       num_entries = prop->length / sizeof(u32);
+       if (!num_entries || (num_entries % num_values)) {
+               dev_err(dev, "All '%s' list entries need %d vals\n", pname,
+                       num_values);
+               return -EINVAL;
+       }
+       num_entries /= num_values;
+
+       info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL);
+       if (!info) {
+               dev_err(dev, "Can't allocate info table for '%s' property\n",
+                       pname);
+               return -ENOMEM;
+       }
+       abb->info = info;
+
+       volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries,
+                                 GFP_KERNEL);
+       if (!volt_table) {
+               dev_err(dev, "Can't allocate voltage table for '%s' property\n",
+                       pname);
+               return -ENOMEM;
+       }
+
+       abb->rdesc.n_voltages = num_entries;
+       abb->rdesc.volt_table = volt_table;
+       /* We do not know where the OPP voltage is at the moment */
+       abb->current_info_idx = -EINVAL;
+
+       abb_info = prop->value;
+       for (i = 0; i < num_entries; i++, info++, volt_table++) {
+               u32 efuse_offset, rbb_mask, fbb_mask, vset_mask;
+               u32 efuse_val;
+
+               /* NOTE: num_values should equal to entries picked up here */
+               *volt_table = be32_to_cpup(abb_info++);
+               info->opp_sel = be32_to_cpup(abb_info++);
+               efuse_offset = be32_to_cpup(abb_info++);
+               rbb_mask = be32_to_cpup(abb_info++);
+               fbb_mask = be32_to_cpup(abb_info++);
+               vset_mask = be32_to_cpup(abb_info++);
+
+               dev_dbg(dev,
+                       "[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n",
+                       i, *volt_table, info->opp_sel, efuse_offset, rbb_mask,
+                       fbb_mask, vset_mask);
+
+               /* Find min/max for voltage set */
+               if (min_uV > *volt_table)
+                       min_uV = *volt_table;
+               if (max_uV < *volt_table)
+                       max_uV = *volt_table;
+
+               if (!abb->efuse_base) {
+                       /* Ignore invalid data, but warn to help cleanup */
+                       if (efuse_offset || rbb_mask || fbb_mask || vset_mask)
+                               dev_err(dev, "prop '%s': v=%d,bad efuse/mask\n",
+                                       pname, *volt_table);
+                       goto check_abb;
+               }
+
+               efuse_val = readl(abb->efuse_base + efuse_offset);
+
+               /* Use ABB recommendation from Efuse */
+               if (efuse_val & rbb_mask)
+                       info->opp_sel = TI_ABB_SLOW_OPP;
+               else if (efuse_val & fbb_mask)
+                       info->opp_sel = TI_ABB_FAST_OPP;
+               else if (rbb_mask || fbb_mask)
+                       info->opp_sel = TI_ABB_NOMINAL_OPP;
+
+               dev_dbg(dev,
+                       "[%d]v=%d efusev=0x%x final ABB=%d\n",
+                       i, *volt_table, efuse_val, info->opp_sel);
+
+               /* Use recommended Vset bits from Efuse */
+               if (!abb->ldo_base) {
+                       if (vset_mask)
+                               dev_err(dev, "prop'%s':v=%d vst=%x LDO base?\n",
+                                       pname, *volt_table, vset_mask);
+                       continue;
+               }
+               info->vset = efuse_val & vset_mask >> __ffs(vset_mask);
+               dev_dbg(dev, "[%d]v=%d vset=%x\n", i, *volt_table, info->vset);
+check_abb:
+               switch (info->opp_sel) {
+               case TI_ABB_NOMINAL_OPP:
+               case TI_ABB_FAST_OPP:
+               case TI_ABB_SLOW_OPP:
+                       /* Valid values */
+                       break;
+               default:
+                       dev_err(dev, "%s:[%d]v=%d, ABB=%d is invalid! Abort!\n",
+                               __func__, i, *volt_table, info->opp_sel);
+                       return -EINVAL;
+               }
+       }
+
+       /* Setup the min/max voltage constraints from the supported list */
+       c->min_uV = min_uV;
+       c->max_uV = max_uV;
+
+       return 0;
+}
+
+static struct regulator_ops ti_abb_reg_ops = {
+       .list_voltage = regulator_list_voltage_table,
+
+       .set_voltage_sel = ti_abb_set_voltage_sel,
+       .get_voltage_sel = ti_abb_get_voltage_sel,
+};
+
+/* Default ABB block offsets, IF this changes in future, create new one */
+static const struct ti_abb_reg abb_regs_v1 = {
+       /* WARNING: registers are wrongly documented in TRM */
+       .setup_reg              = 0x04,
+       .control_reg            = 0x00,
+
+       .sr2_wtcnt_value_mask   = (0xff << 8),
+       .fbb_sel_mask           = (0x01 << 2),
+       .rbb_sel_mask           = (0x01 << 1),
+       .sr2_en_mask            = (0x01 << 0),
+
+       .opp_change_mask        = (0x01 << 2),
+       .opp_sel_mask           = (0x03 << 0),
+};
+
+static const struct ti_abb_reg abb_regs_v2 = {
+       .setup_reg              = 0x00,
+       .control_reg            = 0x04,
+
+       .sr2_wtcnt_value_mask   = (0xff << 8),
+       .fbb_sel_mask           = (0x01 << 2),
+       .rbb_sel_mask           = (0x01 << 1),
+       .sr2_en_mask            = (0x01 << 0),
+
+       .opp_change_mask        = (0x01 << 2),
+       .opp_sel_mask           = (0x03 << 0),
+};
+
+static const struct of_device_id ti_abb_of_match[] = {
+       {.compatible = "ti,abb-v1", .data = &abb_regs_v1},
+       {.compatible = "ti,abb-v2", .data = &abb_regs_v2},
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, ti_abb_of_match);
+
+/**
+ * ti_abb_probe() - Initialize an ABB ldo instance
+ * @pdev: ABB platform device
+ *
+ * Initializes an individual ABB LDO for required Body-Bias. ABB is used to
+ * addional bias supply to SoC modules for power savings or mandatory stability
+ * configuration at certain Operating Performance Points(OPPs).
+ *
+ * Return: 0 on success or appropriate error value when fails
+ */
+static int ti_abb_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       const struct of_device_id *match;
+       struct resource *res;
+       struct ti_abb *abb;
+       struct regulator_init_data *initdata = NULL;
+       struct regulator_dev *rdev = NULL;
+       struct regulator_desc *desc;
+       struct regulation_constraints *c;
+       struct regulator_config config = { };
+       char *pname;
+       int ret = 0;
+
+       match = of_match_device(ti_abb_of_match, dev);
+       if (!match) {
+               /* We do not expect this to happen */
+               ret = -ENODEV;
+               dev_err(dev, "%s: Unable to match device\n", __func__);
+               goto err;
+       }
+       if (!match->data) {
+               ret = -EINVAL;
+               dev_err(dev, "%s: Bad data in match\n", __func__);
+               goto err;
+       }
+
+       abb = devm_kzalloc(dev, sizeof(struct ti_abb), GFP_KERNEL);
+       if (!abb) {
+               dev_err(dev, "%s: Unable to allocate ABB struct\n", __func__);
+               ret = -ENOMEM;
+               goto err;
+       }
+       abb->regs = match->data;
+
+       /* Map ABB resources */
+       pname = "base-address";
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+       if (!res) {
+               dev_err(dev, "Missing '%s' IO resource\n", pname);
+               ret = -ENODEV;
+               goto err;
+       }
+       abb->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(abb->base)) {
+               ret = PTR_ERR(abb->base);
+               goto err;
+       }
+
+       pname = "int-address";
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+       if (!res) {
+               dev_err(dev, "Missing '%s' IO resource\n", pname);
+               ret = -ENODEV;
+               goto err;
+       }
+       /*
+        * We may have shared interrupt register offsets which are
+        * write-1-to-clear between domains ensuring exclusivity.
+        */
+       abb->int_base = devm_ioremap_nocache(dev, res->start,
+                                            resource_size(res));
+       if (!abb->int_base) {
+               dev_err(dev, "Unable to map '%s'\n", pname);
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* Map Optional resources */
+       pname = "efuse-address";
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+       if (!res) {
+               dev_dbg(dev, "Missing '%s' IO resource\n", pname);
+               ret = -ENODEV;
+               goto skip_opt;
+       }
+
+       /*
+        * We may have shared efuse register offsets which are read-only
+        * between domains
+        */
+       abb->efuse_base = devm_ioremap_nocache(dev, res->start,
+                                              resource_size(res));
+       if (!abb->efuse_base) {
+               dev_err(dev, "Unable to map '%s'\n", pname);
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       pname = "ldo-address";
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
+       if (!res) {
+               dev_dbg(dev, "Missing '%s' IO resource\n", pname);
+               ret = -ENODEV;
+               goto skip_opt;
+       }
+       abb->ldo_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(abb->ldo_base)) {
+               ret = PTR_ERR(abb->ldo_base);
+               goto err;
+       }
+
+       /* IF ldo_base is set, the following are mandatory */
+       pname = "ti,ldovbb-override-mask";
+       ret =
+           of_property_read_u32(pdev->dev.of_node, pname,
+                                &abb->ldovbb_override_mask);
+       if (ret) {
+               dev_err(dev, "Missing '%s' (%d)\n", pname, ret);
+               goto err;
+       }
+       if (!abb->ldovbb_override_mask) {
+               dev_err(dev, "Invalid property:'%s' set as 0!\n", pname);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       pname = "ti,ldovbb-vset-mask";
+       ret =
+           of_property_read_u32(pdev->dev.of_node, pname,
+                                &abb->ldovbb_vset_mask);
+       if (ret) {
+               dev_err(dev, "Missing '%s' (%d)\n", pname, ret);
+               goto err;
+       }
+       if (!abb->ldovbb_vset_mask) {
+               dev_err(dev, "Invalid property:'%s' set as 0!\n", pname);
+               ret = -EINVAL;
+               goto err;
+       }
+
+skip_opt:
+       pname = "ti,tranxdone-status-mask";
+       ret =
+           of_property_read_u32(pdev->dev.of_node, pname,
+                                &abb->txdone_mask);
+       if (ret) {
+               dev_err(dev, "Missing '%s' (%d)\n", pname, ret);
+               goto err;
+       }
+       if (!abb->txdone_mask) {
+               dev_err(dev, "Invalid property:'%s' set as 0!\n", pname);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       initdata = of_get_regulator_init_data(dev, pdev->dev.of_node);
+       if (!initdata) {
+               ret = -ENOMEM;
+               dev_err(dev, "%s: Unable to alloc regulator init data\n",
+                       __func__);
+               goto err;
+       }
+
+       /* init ABB opp_sel table */
+       ret = ti_abb_init_table(dev, abb, initdata);
+       if (ret)
+               goto err;
+
+       /* init ABB timing */
+       ret = ti_abb_init_timings(dev, abb);
+       if (ret)
+               goto err;
+
+       desc = &abb->rdesc;
+       desc->name = dev_name(dev);
+       desc->owner = THIS_MODULE;
+       desc->type = REGULATOR_VOLTAGE;
+       desc->ops = &ti_abb_reg_ops;
+
+       c = &initdata->constraints;
+       if (desc->n_voltages > 1)
+               c->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
+       c->always_on = true;
+
+       config.dev = dev;
+       config.init_data = initdata;
+       config.driver_data = abb;
+       config.of_node = pdev->dev.of_node;
+
+       rdev = regulator_register(desc, &config);
+       if (IS_ERR(rdev)) {
+               ret = PTR_ERR(rdev);
+               dev_err(dev, "%s: failed to register regulator(%d)\n",
+                       __func__, ret);
+               goto err;
+       }
+       platform_set_drvdata(pdev, rdev);
+
+       /* Enable the ldo if not already done by bootloader */
+       ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->regs->setup_reg, abb->base);
+
+       return 0;
+
+err:
+       dev_err(dev, "%s: Failed to initialize(%d)\n", __func__, ret);
+       return ret;
+}
+
+/**
+ * ti_abb_remove() - cleanups
+ * @pdev: ABB platform device
+ *
+ * Return: 0
+ */
+static int ti_abb_remove(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+       regulator_unregister(rdev);
+       return 0;
+}
+
+MODULE_ALIAS("platform:ti_abb");
+
+static struct platform_driver ti_abb_driver = {
+       .probe = ti_abb_probe,
+       .remove = ti_abb_remove,
+       .driver = {
+                  .name = "ti_abb",
+                  .owner = THIS_MODULE,
+                  .of_match_table = of_match_ptr(ti_abb_of_match),
+                  },
+};
+module_platform_driver(ti_abb_driver);
+
+MODULE_DESCRIPTION("Texas Instruments ABB LDO regulator driver");
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_LICENSE("GPL v2");
index 612919c3081cafd1a46d010787a97dd3e7d49e62..a490d5b749b2c75efffe33c4249fdf06a83c4e33 100644 (file)
@@ -351,7 +351,6 @@ static int tps62360_probe(struct i2c_client *client,
        int chip_id;
 
        pdata = client->dev.platform_data;
-       chip_id = id->driver_data;
 
        if (client->dev.of_node) {
                const struct of_device_id *match;
@@ -364,6 +363,11 @@ static int tps62360_probe(struct i2c_client *client,
                chip_id = (int)match->data;
                if (!pdata)
                        pdata = of_get_tps62360_platform_data(&client->dev);
+       } else if (id) {
+               chip_id = id->driver_data;
+       } else {
+               dev_err(&client->dev, "No device tree match or id table match found\n");
+               return -ENODEV;
        }
 
        if (!pdata) {
@@ -402,7 +406,7 @@ static int tps62360_probe(struct i2c_client *client,
                return -ENODEV;
        }
 
-       tps->desc.name = id->name;
+       tps->desc.name = client->name;
        tps->desc.id = 0;
        tps->desc.ops = &tps62360_dcdc_ops;
        tps->desc.type = REGULATOR_VOLTAGE;
index df395187c06301114c144305b19cdd29dedb5a22..2df4616621f5e33b9c071b19070ce466bd550fb5 100644 (file)
@@ -405,8 +405,6 @@ static int tps65217_regulator_remove(struct platform_device *pdev)
        for (i = 0; i < TPS65217_NUM_REGULATOR; i++)
                regulator_unregister(tps->rdev[i]);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 01c66e9712a4aa236ba36ed409abbbce51cd66f2..a9d4284ea007cc83658db17724e976d34dc9aafb 100644 (file)
@@ -330,8 +330,6 @@ static int regulator_virtual_remove(struct platform_device *pdev)
        if (drvdata->enabled)
                regulator_disable(drvdata->regulator);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 0af6898bcd79b4e2739ffaa4282f8b1aea6fee70..46938cf162ad7821403dc97b70b2db3298c86e85 100644 (file)
@@ -567,8 +567,6 @@ static int wm831x_buckv_remove(struct platform_device *pdev)
        struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
        struct wm831x *wm831x = dcdc->wm831x;
 
-       platform_set_drvdata(pdev, NULL);
-
        free_irq(wm831x_irq(wm831x, platform_get_irq_byname(pdev, "HC")),
                            dcdc);
        free_irq(wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")),
@@ -714,8 +712,6 @@ static int wm831x_buckp_remove(struct platform_device *pdev)
 {
        struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        free_irq(wm831x_irq(dcdc->wm831x, platform_get_irq_byname(pdev, "UV")),
                            dcdc);
        regulator_unregister(dcdc->regulator);
@@ -849,8 +845,6 @@ static int wm831x_boostp_remove(struct platform_device *pdev)
 {
        struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        free_irq(wm831x_irq(dcdc->wm831x, platform_get_irq_byname(pdev, "UV")),
                 dcdc);
        regulator_unregister(dcdc->regulator);
@@ -940,7 +934,6 @@ static int wm831x_epe_remove(struct platform_device *pdev)
 {
        struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        regulator_unregister(dcdc->regulator);
 
        return 0;
index 68586ee3e1cb18197f64ea68d7cbee9e963408fc..16ebdf94d0a044b6db0111c4d4f9a5c2f8feb5fe 100644 (file)
@@ -225,8 +225,6 @@ static int wm831x_isink_remove(struct platform_device *pdev)
 {
        struct wm831x_isink *isink = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        free_irq(wm831x_irq(isink->wm831x, platform_get_irq(pdev, 0)), isink);
 
        regulator_unregister(isink->regulator);
index 1ec379a9a95c88807c9987b23568e892b14bdc1a..9ff883f80878447dc2902de4cae7de8e206b47fd 100644 (file)
@@ -338,8 +338,6 @@ static int wm831x_gp_ldo_remove(struct platform_device *pdev)
 {
        struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        free_irq(wm831x_irq(ldo->wm831x,
                            platform_get_irq_byname(pdev, "UV")), ldo);
        regulator_unregister(ldo->regulator);
index c6a32ea80b9d2aa063408f6ac38d11622253f477..a09f03ee550621503dfbf95d457cc83de1a1cbbd 100644 (file)
@@ -250,7 +250,6 @@ static int wm8400_regulator_remove(struct platform_device *pdev)
 {
        struct regulator_dev *rdev = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        regulator_unregister(rdev);
 
        return 0;
index a612c356a697cd89e9cb107a2840f20e32acb8e8..8f2a8a7a3f997f5475d305b87f508a47a6daf267 100644 (file)
@@ -185,8 +185,6 @@ static int wm8994_ldo_remove(struct platform_device *pdev)
 {
        struct wm8994_ldo *ldo = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        regulator_unregister(ldo->regulator);
 
        return 0;
index b9838130a7b0da42a3bc0f35724c9b53b553096f..9e3498bf302b3ba659f4b89d9a5de7a088af1c15 100644 (file)
@@ -313,6 +313,15 @@ config RTC_DRV_PALMAS
          This driver can also be built as a module. If so, the module
          will be called rtc-palma.
 
+config RTC_DRV_PCF2127
+       tristate "NXP PCF2127"
+       help
+         If you say yes here you get support for the NXP PCF2127/29 RTC
+         chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-pcf2127.
+
 config RTC_DRV_PCF8523
        tristate "NXP PCF8523"
        help
@@ -1233,6 +1242,13 @@ config RTC_DRV_SNVS
           This driver can also be built as a module, if so, the module
           will be called "rtc-snvs".
 
+config RTC_DRV_SIRFSOC
+       tristate "SiRFSOC RTC"
+       depends on ARCH_SIRF
+       help
+         Say "yes" here to support the real time clock on SiRF SOC chips.
+         This driver can also be built as a module called rtc-sirfsoc.
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
index c33f86f1a69b313f84f7c0e5ceb492474a59f892..d3b4488f48f2405541d401f750c5894b559b4781 100644 (file)
@@ -83,6 +83,7 @@ obj-$(CONFIG_RTC_DRV_NUC900)  += rtc-nuc900.o
 obj-$(CONFIG_RTC_DRV_OMAP)     += rtc-omap.o
 obj-$(CONFIG_RTC_DRV_PALMAS)   += rtc-palmas.o
 obj-$(CONFIG_RTC_DRV_PCAP)     += rtc-pcap.o
+obj-$(CONFIG_RTC_DRV_PCF2127)  += rtc-pcf2127.o
 obj-$(CONFIG_RTC_DRV_PCF8523)  += rtc-pcf8523.o
 obj-$(CONFIG_RTC_DRV_PCF8563)  += rtc-pcf8563.o
 obj-$(CONFIG_RTC_DRV_PCF8583)  += rtc-pcf8583.o
@@ -128,3 +129,4 @@ obj-$(CONFIG_RTC_DRV_VT8500)        += rtc-vt8500.o
 obj-$(CONFIG_RTC_DRV_WM831X)   += rtc-wm831x.o
 obj-$(CONFIG_RTC_DRV_WM8350)   += rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
+obj-$(CONFIG_RTC_DRV_SIRFSOC)  += rtc-sirfsoc.o
index 66385402d20ebf52672a2fa2eab03cbe4b59eedc..02426812bebc5c5cc74cba4db4395e2c67d78f25 100644 (file)
@@ -38,7 +38,7 @@ static void rtc_device_release(struct device *dev)
 int rtc_hctosys_ret = -ENODEV;
 #endif
 
-#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
 /*
  * On suspend(), measure the delta between one RTC and the
  * system's wall clock; restore it on resume().
@@ -47,7 +47,7 @@ int rtc_hctosys_ret = -ENODEV;
 static struct timespec old_rtc, old_system, old_delta;
 
 
-static int rtc_suspend(struct device *dev, pm_message_t mesg)
+static int rtc_suspend(struct device *dev)
 {
        struct rtc_device       *rtc = to_rtc_device(dev);
        struct rtc_time         tm;
@@ -135,9 +135,10 @@ static int rtc_resume(struct device *dev)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume);
+#define RTC_CLASS_DEV_PM_OPS   (&rtc_class_dev_pm_ops)
 #else
-#define rtc_suspend    NULL
-#define rtc_resume     NULL
+#define RTC_CLASS_DEV_PM_OPS   NULL
 #endif
 
 
@@ -336,8 +337,7 @@ static int __init rtc_init(void)
                pr_err("couldn't create class\n");
                return PTR_ERR(rtc_class);
        }
-       rtc_class->suspend = rtc_suspend;
-       rtc_class->resume = rtc_resume;
+       rtc_class->pm = RTC_CLASS_DEV_PM_OPS;
        rtc_dev_init();
        rtc_sysfs_init(rtc_class);
        return 0;
index 42bd57da239de73a05c79c2f11ac129092aa9a19..72c5cdbe0791afd2fed9a4779e5769c82c6b6ba3 100644 (file)
@@ -109,9 +109,9 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
                                err = rtc->ops->set_time(rtc->dev.parent,
                                                &new);
                }
-       }
-       else
+       } else {
                err = -EINVAL;
+       }
 
        mutex_unlock(&rtc->ops_lock);
        /* A timer might have just expired */
@@ -367,14 +367,14 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
        err = mutex_lock_interruptible(&rtc->ops_lock);
        if (err)
                return err;
-       if (rtc->aie_timer.enabled) {
+       if (rtc->aie_timer.enabled)
                rtc_timer_remove(rtc, &rtc->aie_timer);
-       }
+
        rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
        rtc->aie_timer.period = ktime_set(0, 0);
-       if (alarm->enabled) {
+       if (alarm->enabled)
                err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
-       }
+
        mutex_unlock(&rtc->ops_lock);
        return err;
 }
@@ -698,9 +698,9 @@ retry:
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
        if (rtc->irq_task != NULL && task == NULL)
                err = -EBUSY;
-       if (rtc->irq_task != task)
+       else if (rtc->irq_task != task)
                err = -EACCES;
-       if (!err) {
+       else {
                if (rtc_update_hrtimer(rtc, enabled) < 0) {
                        spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
                        cpu_relax();
@@ -734,9 +734,9 @@ retry:
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
        if (rtc->irq_task != NULL && task == NULL)
                err = -EBUSY;
-       if (rtc->irq_task != task)
+       else if (rtc->irq_task != task)
                err = -EACCES;
-       if (!err) {
+       else {
                rtc->irq_freq = freq;
                if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) {
                        spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
@@ -891,7 +891,7 @@ again:
  *
  * Kernel interface to initializing an rtc_timer.
  */
-void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data)
+void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data)
 {
        timerqueue_init(&timer->node);
        timer->enabled = 0;
@@ -907,7 +907,7 @@ void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data)
  *
  * Kernel interface to set an rtc_timer
  */
-int rtc_timer_start(struct rtc_device *rtc, struct rtc_timertimer,
+int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
                        ktime_t expires, ktime_t period)
 {
        int ret = 0;
@@ -930,7 +930,7 @@ int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
  *
  * Kernel interface to cancel an rtc_timer
  */
-int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timertimer)
+int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer)
 {
        int ret = 0;
        mutex_lock(&rtc->ops_lock);
index f3742f364eb8a91e498da2fe9d27e3b29453f3d4..354c937a58665a753ad3ee9b697741264476ec65 100644 (file)
@@ -345,7 +345,6 @@ out:
 static int pm80x_rtc_remove(struct platform_device *pdev)
 {
        struct pm80x_rtc_info *info = platform_get_drvdata(pdev);
-       platform_set_drvdata(pdev, NULL);
        pm80x_free_irq(info->chip, info->irq, info);
        return 0;
 }
index 0f2b91bfee37fb6bfca9d2e2eddac9f25792882e..4e30c85728e5078b7b635c5bc7be4c2eaa4b3476 100644 (file)
@@ -418,7 +418,6 @@ static int pm860x_rtc_remove(struct platform_device *pdev)
        pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
 #endif /* VRTC_CALIBRATION */
 
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 47a4f2c4d30e8b766d2fca6ca50592005c886cb5..ff435343ba9fd33f9289dd576db2768904e085be 100644 (file)
@@ -240,18 +240,11 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit ab3100_rtc_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-       return 0;
-}
-
 static struct platform_driver ab3100_rtc_driver = {
        .driver = {
                .name = "ab3100-rtc",
                .owner = THIS_MODULE,
        },
-       .remove  = __exit_p(ab3100_rtc_remove),
 };
 
 module_platform_driver_probe(ab3100_rtc_driver, ab3100_rtc_probe);
index 63cfa314a39f2b2be6e5307b219be24aed926d3b..727e2f5d14d9a0976c8e57b4cf4dc6499971575a 100644 (file)
 #define AB8500_RTC_FORCE_BKUP_REG      0x0D
 #define AB8500_RTC_CALIB_REG           0x0E
 #define AB8500_RTC_SWITCH_STAT_REG     0x0F
+#define AB8540_RTC_ALRM_SEC            0x22
+#define AB8540_RTC_ALRM_MIN_LOW_REG    0x23
+#define AB8540_RTC_ALRM_MIN_MID_REG    0x24
+#define AB8540_RTC_ALRM_MIN_HI_REG     0x25
 
 /* RtcReadRequest bits */
 #define RTC_READ_REQUEST               0x01
@@ -58,6 +62,11 @@ static const u8 ab8500_rtc_alarm_regs[] = {
        AB8500_RTC_ALRM_MIN_LOW_REG
 };
 
+static const u8 ab8540_rtc_alarm_regs[] = {
+       AB8540_RTC_ALRM_MIN_HI_REG, AB8540_RTC_ALRM_MIN_MID_REG,
+       AB8540_RTC_ALRM_MIN_LOW_REG, AB8540_RTC_ALRM_SEC
+};
+
 /* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */
 static unsigned long get_elapsed_seconds(int year)
 {
@@ -267,6 +276,42 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        return ab8500_rtc_irq_enable(dev, alarm->enabled);
 }
 
+static int ab8540_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       int retval, i;
+       unsigned char buf[ARRAY_SIZE(ab8540_rtc_alarm_regs)];
+       unsigned long mins, secs = 0;
+
+       if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
+               dev_dbg(dev, "year should be equal to or greater than %d\n",
+                               AB8500_RTC_EPOCH);
+               return -EINVAL;
+       }
+
+       /* Get the number of seconds since 1970 */
+       rtc_tm_to_time(&alarm->time, &secs);
+
+       /*
+        * Convert it to the number of seconds since 01-01-2000 00:00:00
+        */
+       secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
+       mins = secs / 60;
+
+       buf[3] = secs % 60;
+       buf[2] = mins & 0xFF;
+       buf[1] = (mins >> 8) & 0xFF;
+       buf[0] = (mins >> 16) & 0xFF;
+
+       /* Set the alarm time */
+       for (i = 0; i < ARRAY_SIZE(ab8540_rtc_alarm_regs); i++) {
+               retval = abx500_set_register_interruptible(dev, AB8500_RTC,
+                       ab8540_rtc_alarm_regs[i], buf[i]);
+               if (retval < 0)
+                       return retval;
+       }
+
+       return ab8500_rtc_irq_enable(dev, alarm->enabled);
+}
 
 static int ab8500_rtc_set_calibration(struct device *dev, int calibration)
 {
@@ -389,8 +434,22 @@ static const struct rtc_class_ops ab8500_rtc_ops = {
        .alarm_irq_enable       = ab8500_rtc_irq_enable,
 };
 
+static const struct rtc_class_ops ab8540_rtc_ops = {
+       .read_time              = ab8500_rtc_read_time,
+       .set_time               = ab8500_rtc_set_time,
+       .read_alarm             = ab8500_rtc_read_alarm,
+       .set_alarm              = ab8540_rtc_set_alarm,
+       .alarm_irq_enable       = ab8500_rtc_irq_enable,
+};
+
+static struct platform_device_id ab85xx_rtc_ids[] = {
+       { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, },
+       { "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, },
+};
+
 static int ab8500_rtc_probe(struct platform_device *pdev)
 {
+       const struct platform_device_id *platid = platform_get_device_id(pdev);
        int err;
        struct rtc_device *rtc;
        u8 rtc_ctrl;
@@ -423,7 +482,8 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
        device_init_wakeup(&pdev->dev, true);
 
        rtc = devm_rtc_device_register(&pdev->dev, "ab8500-rtc",
-                                       &ab8500_rtc_ops, THIS_MODULE);
+                               (struct rtc_class_ops *)platid->driver_data,
+                               THIS_MODULE);
        if (IS_ERR(rtc)) {
                dev_err(&pdev->dev, "Registration failed\n");
                err = PTR_ERR(rtc);
@@ -451,8 +511,6 @@ static int ab8500_rtc_remove(struct platform_device *pdev)
 {
        ab8500_sysfs_rtc_unregister(&pdev->dev);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
@@ -463,6 +521,7 @@ static struct platform_driver ab8500_rtc_driver = {
        },
        .probe  = ab8500_rtc_probe,
        .remove = ab8500_rtc_remove,
+       .id_table = ab85xx_rtc_ids,
 };
 
 module_platform_driver(ab8500_rtc_driver);
index f47fbb5eee8bddd5d29d360c8142fcfc4547e67e..3161ab5263ed93329fce90d5e537ced05ff3d5b2 100644 (file)
@@ -141,7 +141,7 @@ static int at32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 
        spin_lock_irq(&rtc->lock);
 
-       if(enabled) {
+       if (enabled) {
                if (rtc_readl(rtc, VAL) > rtc->alarm_time) {
                        ret = -EINVAL;
                        goto out;
@@ -212,23 +212,20 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs) {
                dev_dbg(&pdev->dev, "no mmio resource defined\n");
-               ret = -ENXIO;
-               goto out;
+               return -ENXIO;
        }
 
        irq = platform_get_irq(pdev, 0);
        if (irq <= 0) {
                dev_dbg(&pdev->dev, "could not get irq\n");
-               ret = -ENXIO;
-               goto out;
+               return -ENXIO;
        }
 
        rtc->irq = irq;
        rtc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
        if (!rtc->regs) {
-               ret = -ENOMEM;
                dev_dbg(&pdev->dev, "could not map I/O memory\n");
-               goto out;
+               return -ENOMEM;
        }
        spin_lock_init(&rtc->lock);
 
@@ -249,7 +246,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
                                "rtc", rtc);
        if (ret) {
                dev_dbg(&pdev->dev, "could not request irq %d\n", irq);
-               goto out;
+               return ret;
        }
 
        platform_set_drvdata(pdev, rtc);
@@ -258,8 +255,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
                                &at32_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc->rtc)) {
                dev_dbg(&pdev->dev, "could not register rtc device\n");
-               ret = PTR_ERR(rtc->rtc);
-               goto out;
+               return PTR_ERR(rtc->rtc);
        }
 
        device_init_wakeup(&pdev->dev, 1);
@@ -268,18 +264,12 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
                        (unsigned long)rtc->regs, rtc->irq);
 
        return 0;
-
-out:
-       platform_set_drvdata(pdev, NULL);
-       return ret;
 }
 
 static int __exit at32_rtc_remove(struct platform_device *pdev)
 {
        device_init_wakeup(&pdev->dev, 0);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index f296f3f7db9bb72574396182f3a8dfd115e16786..741892632ae09ef4c561e6ee0801d6ea0cec435f 100644 (file)
@@ -31,8 +31,7 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include "rtc-at91rm9200.h"
 
@@ -439,7 +438,6 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
 
        rtc_device_unregister(rtc);
        iounmap(at91_rtc_regs);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index b60a34cb145a2684836bfa17e80f24a0945e3291..309b8b342d9c885ef544e53fc28688d988cd3573 100644 (file)
@@ -324,16 +324,14 @@ static int at91_rtc_probe(struct platform_device *pdev)
        rtc->rtt = devm_ioremap(&pdev->dev, r->start, resource_size(r));
        if (!rtc->rtt) {
                dev_err(&pdev->dev, "failed to map registers, aborting.\n");
-               ret = -ENOMEM;
-               goto fail;
+               return -ENOMEM;
        }
 
        rtc->gpbr = devm_ioremap(&pdev->dev, r_gpbr->start,
                                resource_size(r_gpbr));
        if (!rtc->gpbr) {
                dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n");
-               ret = -ENOMEM;
-               goto fail;
+               return -ENOMEM;
        }
 
        mr = rtt_readl(rtc, MR);
@@ -350,17 +348,15 @@ static int at91_rtc_probe(struct platform_device *pdev)
 
        rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name,
                                        &at91_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc->rtcdev)) {
-               ret = PTR_ERR(rtc->rtcdev);
-               goto fail;
-       }
+       if (IS_ERR(rtc->rtcdev))
+               return PTR_ERR(rtc->rtcdev);
 
        /* register irq handler after we know what name we'll use */
        ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt,
                                IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc);
        if (ret) {
                dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq);
-               goto fail;
+               return ret;
        }
 
        /* NOTE:  sam9260 rev A silicon has a ROM bug which resets the
@@ -374,10 +370,6 @@ static int at91_rtc_probe(struct platform_device *pdev)
                                dev_name(&rtc->rtcdev->dev));
 
        return 0;
-
-fail:
-       platform_set_drvdata(pdev, NULL);
-       return ret;
 }
 
 /*
@@ -391,7 +383,6 @@ static int at91_rtc_remove(struct platform_device *pdev)
        /* disable all interrupts */
        rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
 
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 7995abc391fcdec48b78fd569e1faccef97d8674..ed526a192ce0ec900016f92b75f4656285b34266 100644 (file)
@@ -116,19 +116,11 @@ out_err:
        return ret;
 }
 
-static int au1xtoy_rtc_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
 static struct platform_driver au1xrtc_driver = {
        .driver         = {
                .name   = "rtc-au1xxx",
                .owner  = THIS_MODULE,
        },
-       .remove         = au1xtoy_rtc_remove,
 };
 
 module_platform_driver_probe(au1xrtc_driver, au1xtoy_rtc_probe);
index ad44ec5dc29a70a5f9a7048a54488bdf6c94150f..0c53f452849d582d97b13f49058a8fc7e7750932 100644 (file)
@@ -391,7 +391,6 @@ static int bfin_rtc_remove(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
 
        bfin_rtc_reset(dev, 0);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index fea78bc713ca243ec6737ca99afb482cca6a7451..c74bf0dc52cc83baa3a66de3f030f27c7a089335 100644 (file)
@@ -163,11 +163,6 @@ static int bq32k_probe(struct i2c_client *client,
        return 0;
 }
 
-static int bq32k_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static const struct i2c_device_id bq32k_id[] = {
        { "bq32000", 0 },
        { }
@@ -180,7 +175,6 @@ static struct i2c_driver bq32k_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = bq32k_probe,
-       .remove         = bq32k_remove,
        .id_table       = bq32k_id,
 };
 
index af2886784a7b102b348154b13e730ecf08ab2ae9..fc0ff87aa5dfe23d39689c64b40c0cff1d84b32c 100644 (file)
@@ -186,13 +186,6 @@ out:
 
 }
 
-static int bq4802_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
 /* work with hotplug and coldplug */
 MODULE_ALIAS("platform:rtc-bq4802");
 
@@ -202,7 +195,6 @@ static struct platform_driver bq4802_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = bq4802_probe,
-       .remove         = bq4802_remove,
 };
 
 module_platform_driver(bq4802_driver);
index f1cb706445c739d7eee047a06482e63f0444de83..be06d7150de5d4b81f6c84e9c5cc874e26360e70 100644 (file)
@@ -326,7 +326,7 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
 static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
        struct cmos_rtc *cmos = dev_get_drvdata(dev);
-       unsigned char   mon, mday, hrs, min, sec, rtc_control;
+       unsigned char mon, mday, hrs, min, sec, rtc_control;
 
        if (!is_valid_irq(cmos->irq))
                return -EIO;
@@ -556,17 +556,24 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
        rtc_control = CMOS_READ(RTC_CONTROL);
        if (is_hpet_enabled())
                irqstat = (unsigned long)irq & 0xF0;
-       irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+
+       /* If we were suspended, RTC_CONTROL may not be accurate since the
+        * bios may have cleared it.
+        */
+       if (!cmos_rtc.suspend_ctrl)
+               irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+       else
+               irqstat &= (cmos_rtc.suspend_ctrl & RTC_IRQMASK) | RTC_IRQF;
 
        /* All Linux RTC alarms should be treated as if they were oneshot.
         * Similar code may be needed in system wakeup paths, in case the
         * alarm woke the system.
         */
        if (irqstat & RTC_AIE) {
+               cmos_rtc.suspend_ctrl &= ~RTC_AIE;
                rtc_control &= ~RTC_AIE;
                CMOS_WRITE(rtc_control, RTC_CONTROL);
                hpet_mask_rtc_irq_bit(RTC_AIE);
-
                CMOS_READ(RTC_INTR_FLAGS);
        }
        spin_unlock(&rtc_lock);
@@ -691,7 +698,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
        /* FIXME:
         * <asm-generic/rtc.h> doesn't know 12-hour mode either.
         */
-       if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
+       if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
                dev_warn(dev, "only 24-hr supported\n");
                retval = -ENXIO;
                goto cleanup1;
@@ -839,21 +846,23 @@ static inline int cmos_poweroff(struct device *dev)
 static int cmos_resume(struct device *dev)
 {
        struct cmos_rtc *cmos = dev_get_drvdata(dev);
-       unsigned char   tmp = cmos->suspend_ctrl;
+       unsigned char tmp;
+
+       if (cmos->enabled_wake) {
+               if (cmos->wake_off)
+                       cmos->wake_off(dev);
+               else
+                       disable_irq_wake(cmos->irq);
+               cmos->enabled_wake = 0;
+       }
 
+       spin_lock_irq(&rtc_lock);
+       tmp = cmos->suspend_ctrl;
+       cmos->suspend_ctrl = 0;
        /* re-enable any irqs previously active */
        if (tmp & RTC_IRQMASK) {
                unsigned char   mask;
 
-               if (cmos->enabled_wake) {
-                       if (cmos->wake_off)
-                               cmos->wake_off(dev);
-                       else
-                               disable_irq_wake(cmos->irq);
-                       cmos->enabled_wake = 0;
-               }
-
-               spin_lock_irq(&rtc_lock);
                if (device_may_wakeup(dev))
                        hpet_rtc_timer_init();
 
@@ -873,8 +882,8 @@ static int cmos_resume(struct device *dev)
                        tmp &= ~RTC_AIE;
                        hpet_mask_rtc_irq_bit(RTC_AIE);
                } while (mask & RTC_AIE);
-               spin_unlock_irq(&rtc_lock);
        }
+       spin_unlock_irq(&rtc_lock);
 
        dev_dbg(dev, "resume, ctrl %02x\n", tmp);
 
@@ -991,7 +1000,7 @@ static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
 {
        cmos_wake_setup(&pnp->dev);
 
-       if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0))
+       if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0))
                /* Some machines contain a PNP entry for the RTC, but
                 * don't define the IRQ. It should always be safe to
                 * hardcode it in these cases
index ad6863a76af9bd5201796d73591cf17bb127cd76..73f157519dff08acdf9aa96e4e3d2135ed1721b9 100644 (file)
@@ -152,12 +152,10 @@ static struct rtc_class_ops coh901331_ops = {
 
 static int __exit coh901331_remove(struct platform_device *pdev)
 {
-       struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
+       struct coh901331_port *rtap = platform_get_drvdata(pdev);
 
-       if (rtap) {
+       if (rtap)
                clk_unprepare(rtap->clk);
-               platform_set_drvdata(pdev, NULL);
-       }
 
        return 0;
 }
@@ -220,7 +218,6 @@ static int __init coh901331_probe(struct platform_device *pdev)
        return 0;
 
  out_no_rtc:
-       platform_set_drvdata(pdev, NULL);
        clk_unprepare(rtap->clk);
        return ret;
 }
@@ -267,7 +264,7 @@ static SIMPLE_DEV_PM_OPS(coh901331_pm_ops, coh901331_suspend, coh901331_resume);
 
 static void coh901331_shutdown(struct platform_device *pdev)
 {
-       struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
+       struct coh901331_port *rtap = platform_get_drvdata(pdev);
 
        clk_enable(rtap->clk);
        writel(0, rtap->virtbase + COH901331_IRQ_MASK);
index 7286b279cf2d312d07a9a061fb4901cc39bc949e..9c8c19441cc65211a0c3dbd63a5147ea6e7ff8b0 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
+#include <linux/err.h>
 
 #include <linux/mfd/da9052/da9052.h>
 #include <linux/mfd/da9052/reg.h>
@@ -249,22 +250,11 @@ static int da9052_rtc_probe(struct platform_device *pdev)
 
        rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                                       &da9052_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc->rtc))
-               return PTR_ERR(rtc->rtc);
-
-       return 0;
-}
-
-static int da9052_rtc_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
+       return PTR_RET(rtc->rtc);
 }
 
 static struct platform_driver da9052_rtc_driver = {
        .probe  = da9052_rtc_probe,
-       .remove = da9052_rtc_remove,
        .driver = {
                .name   = "da9052-rtc",
                .owner  = THIS_MODULE,
index 73858ca9709a1eb6f6af06882f099fe2f9d1d930..e00642b61076e06f01971a5988cbbbcc53aebcba 100644 (file)
@@ -315,13 +315,6 @@ err_rtc:
 
 }
 
-static int da9055_rtc_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM
 /* Turn off the alarm if it should not be a wake source. */
 static int da9055_rtc_suspend(struct device *dev)
@@ -394,7 +387,6 @@ static const struct dev_pm_ops da9055_rtc_pm_ops = {
 
 static struct platform_driver da9055_rtc_driver = {
        .probe  = da9055_rtc_probe,
-       .remove = da9055_rtc_remove,
        .driver = {
                .name   = "da9055-rtc",
                .owner  = THIS_MODULE,
index a55048c3e26f010121121b97056d0ea9b72921cd..24677ef8c39ad37b9d920862242f0b245337de18 100644 (file)
 static DEFINE_SPINLOCK(davinci_rtc_lock);
 
 struct davinci_rtc {
-       struct rtc_device               *rtc;
+       struct rtc_device               *rtc;
        void __iomem                    *base;
        resource_size_t                 pbase;
        size_t                          base_size;
@@ -526,10 +526,9 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
        davinci_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                                    &davinci_rtc_ops, THIS_MODULE);
        if (IS_ERR(davinci_rtc->rtc)) {
-               ret = PTR_ERR(davinci_rtc->rtc);
                dev_err(dev, "unable to register RTC device, err %d\n",
                                ret);
-               goto fail1;
+               return PTR_ERR(davinci_rtc->rtc);
        }
 
        rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG);
@@ -543,7 +542,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
                          0, "davinci_rtc", davinci_rtc);
        if (ret < 0) {
                dev_err(dev, "unable to register davinci RTC interrupt\n");
-               goto fail1;
+               return ret;
        }
 
        /* Enable interrupts */
@@ -556,10 +555,6 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
        device_init_wakeup(&pdev->dev, 0);
 
        return 0;
-
-fail1:
-       platform_set_drvdata(pdev, NULL);
-       return ret;
 }
 
 static int __exit davinci_rtc_remove(struct platform_device *pdev)
@@ -570,8 +565,6 @@ static int __exit davinci_rtc_remove(struct platform_device *pdev)
 
        rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 1e1ca63d58a9dd67c6a19e3dc99a0394da1646c3..1aca08394c479dc2fffa69d7230e143e51413a51 100644 (file)
@@ -139,19 +139,12 @@ static int dm355evm_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int dm355evm_rtc_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-       return 0;
-}
-
 /*
  * I2C is used to talk to the MSP430, but this platform device is
  * exposed by an MFD driver that manages I2C communications.
  */
 static struct platform_driver rtc_dm355evm_driver = {
        .probe          = dm355evm_rtc_probe,
-       .remove         = dm355evm_rtc_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "rtc-dm355evm",
index c7702b7269f747d000e65bb75817c721ef20d22a..9c04fd2bc209b033ee209b3f2ab3e5f689ccbfdf 100644 (file)
@@ -167,34 +167,17 @@ static int __init ds1216_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit ds1216_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static struct platform_driver ds1216_rtc_platform_driver = {
        .driver         = {
                .name   = "rtc-ds1216",
                .owner  = THIS_MODULE,
        },
-       .remove         = __exit_p(ds1216_rtc_remove),
 };
 
-static int __init ds1216_rtc_init(void)
-{
-       return platform_driver_probe(&ds1216_rtc_platform_driver, ds1216_rtc_probe);
-}
-
-static void __exit ds1216_rtc_exit(void)
-{
-       platform_driver_unregister(&ds1216_rtc_platform_driver);
-}
+module_platform_driver_probe(ds1216_rtc_platform_driver, ds1216_rtc_probe);
 
 MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
 MODULE_DESCRIPTION("DS1216 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_ALIAS("platform:rtc-ds1216");
-
-module_init(ds1216_rtc_init);
-module_exit(ds1216_rtc_exit);
index 398c96a98fc4eca0e1b5bfce42c780353bd8f329..50e109b78252492d49f6dc0098bb5d9f00b158a1 100644 (file)
@@ -353,18 +353,12 @@ static int ds1286_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int ds1286_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static struct platform_driver ds1286_platform_driver = {
        .driver         = {
                .name   = "rtc-ds1286",
                .owner  = THIS_MODULE,
        },
        .probe          = ds1286_probe,
-       .remove         = ds1286_remove,
 };
 
 module_platform_driver(ds1286_platform_driver);
index d139543462863dc1f598b5486ac4760bd72c0b6d..07e8d79b4a09015e56c58aa363a3ab1b0d3d9626 100644 (file)
 #define        RTC_CMD_READ    0x81            /* Read command */
 #define        RTC_CMD_WRITE   0x80            /* Write command */
 
+#define        RTC_CMD_WRITE_ENABLE    0x00            /* Write enable */
+#define        RTC_CMD_WRITE_DISABLE   0x80            /* Write disable */
+
 #define RTC_ADDR_RAM0  0x20            /* Address of RAM0 */
 #define RTC_ADDR_TCR   0x08            /* Address of trickle charge register */
+#define        RTC_ADDR_CTRL   0x07            /* Address of control register */
 #define        RTC_ADDR_YEAR   0x06            /* Address of year register */
 #define        RTC_ADDR_DAY    0x05            /* Address of day of week register */
 #define        RTC_ADDR_MON    0x04            /* Address of month register */
@@ -161,6 +165,7 @@ static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
 static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
+       ds1302_writebyte(RTC_ADDR_CTRL, RTC_CMD_WRITE_ENABLE);
        /* Stop RTC */
        ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
 
@@ -175,6 +180,8 @@ static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
        /* Start RTC */
        ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
 
+       ds1302_writebyte(RTC_ADDR_CTRL, RTC_CMD_WRITE_DISABLE);
+
        return 0;
 }
 
@@ -234,19 +241,11 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit ds1302_rtc_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
 static struct platform_driver ds1302_platform_driver = {
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
        },
-       .remove         = __exit_p(ds1302_rtc_remove),
 };
 
 module_platform_driver_probe(ds1302_platform_driver, ds1302_rtc_probe);
index bb5f13f636304a0228829fe9d99abeb1b013b2a9..dd6170acde95063b8253c837508cf429e5d6753a 100644 (file)
@@ -158,7 +158,7 @@ static int ds1305_alarm_irq_enable(struct device *dev, unsigned int enabled)
                        goto done;
                buf[1] &= ~DS1305_AEI0;
        }
-       err = spi_write_then_read(ds1305->spi, buf, sizeof buf, NULL, 0);
+       err = spi_write_then_read(ds1305->spi, buf, sizeof(buf), NULL, 0);
        if (err >= 0)
                ds1305->ctrl[0] = buf[1];
 done:
@@ -181,8 +181,8 @@ static int ds1305_get_time(struct device *dev, struct rtc_time *time)
        /* Use write-then-read to get all the date/time registers
         * since dma from stack is nonportable
         */
-       status = spi_write_then_read(ds1305->spi, &addr, sizeof addr,
-                       buf, sizeof buf);
+       status = spi_write_then_read(ds1305->spi, &addr, sizeof(addr),
+                       buf, sizeof(buf));
        if (status < 0)
                return status;
 
@@ -237,7 +237,7 @@ static int ds1305_set_time(struct device *dev, struct rtc_time *time)
                buf[4], buf[5], buf[6], buf[7]);
 
        /* use write-then-read since dma from stack is nonportable */
-       return spi_write_then_read(ds1305->spi, buf, sizeof buf,
+       return spi_write_then_read(ds1305->spi, buf, sizeof(buf),
                        NULL, 0);
 }
 
@@ -286,8 +286,8 @@ static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm)
         * of EFI status is at best fragile anyway (given IRQ handlers).
         */
        addr = DS1305_CONTROL;
-       status = spi_write_then_read(spi, &addr, sizeof addr,
-                       ds1305->ctrl, sizeof ds1305->ctrl);
+       status = spi_write_then_read(spi, &addr, sizeof(addr),
+                       ds1305->ctrl, sizeof(ds1305->ctrl));
        if (status < 0)
                return status;
 
@@ -296,8 +296,8 @@ static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
        /* get and check ALM0 registers */
        addr = DS1305_ALM0(DS1305_SEC);
-       status = spi_write_then_read(spi, &addr, sizeof addr,
-                       buf, sizeof buf);
+       status = spi_write_then_read(spi, &addr, sizeof(addr),
+                       buf, sizeof(buf));
        if (status < 0)
                return status;
 
@@ -381,7 +381,7 @@ static int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
                "alm0 write", buf[1 + DS1305_SEC], buf[1 + DS1305_MIN],
                buf[1 + DS1305_HOUR], buf[1 + DS1305_WDAY]);
 
-       status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0);
+       status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
        if (status < 0)
                return status;
 
@@ -474,7 +474,7 @@ static void ds1305_work(struct work_struct *work)
        buf[1] = ds1305->ctrl[0];
        buf[2] = 0;
 
-       status = spi_write_then_read(spi, buf, sizeof buf,
+       status = spi_write_then_read(spi, buf, sizeof(buf),
                        NULL, 0);
        if (status < 0)
                dev_dbg(&spi->dev, "clear irq --> %d\n", status);
@@ -627,8 +627,8 @@ static int ds1305_probe(struct spi_device *spi)
 
        /* read and cache control registers */
        addr = DS1305_CONTROL;
-       status = spi_write_then_read(spi, &addr, sizeof addr,
-                       ds1305->ctrl, sizeof ds1305->ctrl);
+       status = spi_write_then_read(spi, &addr, sizeof(addr),
+                       ds1305->ctrl, sizeof(ds1305->ctrl));
        if (status < 0) {
                dev_dbg(&spi->dev, "can't %s, %d\n",
                                "read", status);
@@ -659,7 +659,7 @@ static int ds1305_probe(struct spi_device *spi)
 
                buf[0] = DS1305_WRITE | DS1305_CONTROL;
                buf[1] = ds1305->ctrl[0];
-               status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0);
+               status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
 
                dev_dbg(&spi->dev, "clear WP --> %d\n", status);
                if (status < 0)
@@ -713,7 +713,7 @@ static int ds1305_probe(struct spi_device *spi)
                buf[1] = ds1305->ctrl[0];
                buf[2] = ds1305->ctrl[1];
                buf[3] = ds1305->ctrl[2];
-               status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0);
+               status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
                if (status < 0) {
                        dev_dbg(&spi->dev, "can't %s, %d\n",
                                        "write", status);
@@ -725,8 +725,8 @@ static int ds1305_probe(struct spi_device *spi)
 
        /* see if non-Linux software set up AM/PM mode */
        addr = DS1305_HOUR;
-       status = spi_write_then_read(spi, &addr, sizeof addr,
-                               &value, sizeof value);
+       status = spi_write_then_read(spi, &addr, sizeof(addr),
+                               &value, sizeof(value));
        if (status < 0) {
                dev_dbg(&spi->dev, "read HOUR --> %d\n", status);
                return status;
index b53992ab30908e9987735a32cb8b891b95db8e70..ca18fd1433b3db9e61ade3acb62dacc7dcee779f 100644 (file)
@@ -683,7 +683,7 @@ static int ds1307_probe(struct i2c_client *client,
            && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
                return -EIO;
 
-       ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL);
+       ds1307 = devm_kzalloc(&client->dev, sizeof(struct ds1307), GFP_KERNEL);
        if (!ds1307)
                return -ENOMEM;
 
@@ -715,7 +715,7 @@ static int ds1307_probe(struct i2c_client *client,
                if (tmp != 2) {
                        dev_dbg(&client->dev, "read error %d\n", tmp);
                        err = -EIO;
-                       goto exit_free;
+                       goto exit;
                }
 
                /* oscillator off?  turn it on, so clock can tick. */
@@ -754,7 +754,7 @@ static int ds1307_probe(struct i2c_client *client,
                if (tmp != 2) {
                        dev_dbg(&client->dev, "read error %d\n", tmp);
                        err = -EIO;
-                       goto exit_free;
+                       goto exit;
                }
 
                /* oscillator off?  turn it on, so clock can tick. */
@@ -798,7 +798,7 @@ static int ds1307_probe(struct i2c_client *client,
                        if (tmp != 2) {
                                dev_dbg(&client->dev, "read error %d\n", tmp);
                                err = -EIO;
-                               goto exit_free;
+                               goto exit;
                        }
 
                        /* correct hour */
@@ -826,7 +826,7 @@ read_rtc:
        if (tmp != 8) {
                dev_dbg(&client->dev, "read error %d\n", tmp);
                err = -EIO;
-               goto exit_free;
+               goto exit;
        }
 
        /*
@@ -868,7 +868,7 @@ read_rtc:
                if (tmp < 0) {
                        dev_dbg(&client->dev, "read error %d\n", tmp);
                        err = -EIO;
-                       goto exit_free;
+                       goto exit;
                }
 
                /* oscillator fault?  clear flag, and warn */
@@ -927,13 +927,13 @@ read_rtc:
                                bin2bcd(tmp));
        }
 
-       ds1307->rtc = rtc_device_register(client->name, &client->dev,
+       ds1307->rtc = devm_rtc_device_register(&client->dev, client->name,
                                &ds13xx_rtc_ops, THIS_MODULE);
        if (IS_ERR(ds1307->rtc)) {
                err = PTR_ERR(ds1307->rtc);
                dev_err(&client->dev,
                        "unable to register the class device\n");
-               goto exit_free;
+               goto exit;
        }
 
        if (want_irq) {
@@ -942,7 +942,7 @@ read_rtc:
                if (err) {
                        dev_err(&client->dev,
                                "unable to request IRQ!\n");
-                       goto exit_irq;
+                       goto exit;
                }
 
                device_set_wakeup_capable(&client->dev, 1);
@@ -951,11 +951,12 @@ read_rtc:
        }
 
        if (chip->nvram_size) {
-               ds1307->nvram = kzalloc(sizeof(struct bin_attribute),
-                                                       GFP_KERNEL);
+               ds1307->nvram = devm_kzalloc(&client->dev,
+                                       sizeof(struct bin_attribute),
+                                       GFP_KERNEL);
                if (!ds1307->nvram) {
                        err = -ENOMEM;
-                       goto exit_nvram;
+                       goto exit;
                }
                ds1307->nvram->attr.name = "nvram";
                ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
@@ -965,21 +966,15 @@ read_rtc:
                ds1307->nvram->size = chip->nvram_size;
                ds1307->nvram_offset = chip->nvram_offset;
                err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
-               if (err) {
-                       kfree(ds1307->nvram);
-                       goto exit_nvram;
-               }
+               if (err)
+                       goto exit;
                set_bit(HAS_NVRAM, &ds1307->flags);
                dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size);
        }
 
        return 0;
 
-exit_nvram:
-exit_irq:
-       rtc_device_unregister(ds1307->rtc);
-exit_free:
-       kfree(ds1307);
+exit:
        return err;
 }
 
@@ -992,13 +987,9 @@ static int ds1307_remove(struct i2c_client *client)
                cancel_work_sync(&ds1307->work);
        }
 
-       if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) {
+       if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
                sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
-               kfree(ds1307->nvram);
-       }
 
-       rtc_device_unregister(ds1307->rtc);
-       kfree(ds1307);
        return 0;
 }
 
index 94366e12f40fc0ccef7bce40f7dc9381fa72da98..9e6e14fb53d740bd4a8085fe617506245131443a 100644 (file)
@@ -65,7 +65,7 @@ struct ds1374 {
 static struct i2c_driver ds1374_driver;
 
 static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
-                           int reg, int nbytes)
+                          int reg, int nbytes)
 {
        u8 buf[4];
        int ret;
@@ -90,7 +90,7 @@ static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
 }
 
 static int ds1374_write_rtc(struct i2c_client *client, u32 time,
-                            int reg, int nbytes)
+                           int reg, int nbytes)
 {
        u8 buf[4];
        int i;
@@ -119,8 +119,7 @@ static int ds1374_check_rtc_status(struct i2c_client *client)
 
        if (stat & DS1374_REG_SR_OSF)
                dev_warn(&client->dev,
-                        "oscillator discontinuity flagged, "
-                        "time unreliable\n");
+                        "oscillator discontinuity flagged, time unreliable\n");
 
        stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF);
 
@@ -363,7 +362,7 @@ static int ds1374_probe(struct i2c_client *client,
 
        if (client->irq > 0) {
                ret = devm_request_irq(&client->dev, client->irq, ds1374_irq, 0,
-                                 "ds1374", client);
+                                       "ds1374", client);
                if (ret) {
                        dev_err(&client->dev, "unable to request IRQ\n");
                        return ret;
@@ -373,7 +372,7 @@ static int ds1374_probe(struct i2c_client *client,
        }
 
        ds1374->rtc = devm_rtc_device_register(&client->dev, client->name,
-                                         &ds1374_rtc_ops, THIS_MODULE);
+                                               &ds1374_rtc_ops, THIS_MODULE);
        if (IS_ERR(ds1374->rtc)) {
                dev_err(&client->dev, "unable to register the class device\n");
                return PTR_ERR(ds1374->rtc);
index 289af419dff46940040702368e58090c2871f757..be9d8c0a7e3a9297f093522087a04c1d82d2d335 100644 (file)
@@ -154,18 +154,12 @@ static int ds1390_probe(struct spi_device *spi)
        return res;
 }
 
-static int ds1390_remove(struct spi_device *spi)
-{
-       return 0;
-}
-
 static struct spi_driver ds1390_driver = {
        .driver = {
                .name   = "rtc-ds1390",
                .owner  = THIS_MODULE,
        },
        .probe  = ds1390_probe,
-       .remove = ds1390_remove,
 };
 
 module_spi_driver(ds1390_driver);
index 6ce8a997cf5196720a31d8a47add57eb62bd0b8b..308a8fefe76f7730b68b0405a46cc1fe50c1ac96 100644 (file)
@@ -104,31 +104,31 @@ static DEFINE_SPINLOCK(ds1511_lock);
 static __iomem char *ds1511_base;
 static u32 reg_spacing = 1;
 
- static noinline void
+static noinline void
 rtc_write(uint8_t val, uint32_t reg)
 {
        writeb(val, ds1511_base + (reg * reg_spacing));
 }
 
- static inline void
+static inline void
 rtc_write_alarm(uint8_t val, enum ds1511reg reg)
 {
        rtc_write((val | 0x80), reg);
 }
 
- static noinline uint8_t
+static noinline uint8_t
 rtc_read(enum ds1511reg reg)
 {
        return readb(ds1511_base + (reg * reg_spacing));
 }
 
- static inline void
+static inline void
 rtc_disable_update(void)
 {
        rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD);
 }
 
- static void
+static void
 rtc_enable_update(void)
 {
        rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD);
@@ -145,7 +145,7 @@ rtc_enable_update(void)
  * just enough code to set the watchdog timer so that it
  * will reboot the system
  */
- void
+void
 ds1511_wdog_set(unsigned long deciseconds)
 {
        /*
@@ -163,7 +163,7 @@ ds1511_wdog_set(unsigned long deciseconds)
        rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD);
 }
 
- void
+void
 ds1511_wdog_disable(void)
 {
        /*
@@ -191,13 +191,12 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
        /*
         * won't have to change this for a while
         */
-       if (rtc_tm->tm_year < 1900) {
+       if (rtc_tm->tm_year < 1900)
                rtc_tm->tm_year += 1900;
-       }
 
-       if (rtc_tm->tm_year < 1970) {
+       if (rtc_tm->tm_year < 1970)
                return -EINVAL;
-       }
+
        yrs = rtc_tm->tm_year % 100;
        cen = rtc_tm->tm_year / 100;
        mon = rtc_tm->tm_mon + 1;   /* tm_mon starts at zero */
@@ -207,17 +206,14 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
        min = rtc_tm->tm_min;
        sec = rtc_tm->tm_sec;
 
-       if ((mon > 12) || (day == 0)) {
+       if ((mon > 12) || (day == 0))
                return -EINVAL;
-       }
 
-       if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year)) {
+       if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year))
                return -EINVAL;
-       }
 
-       if ((hrs >= 24) || (min >= 60) || (sec >= 60)) {
+       if ((hrs >= 24) || (min >= 60) || (sec >= 60))
                return -EINVAL;
-       }
 
        /*
         * each register is a different number of valid bits
@@ -299,7 +295,7 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
  * date/hours/mins/secs matches.  the ds1511 has many more
  * permutations, but the kernel doesn't.
  */
- static void
+static void
 ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
 {
        unsigned long flags;
@@ -322,7 +318,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
        spin_unlock_irqrestore(&pdata->lock, flags);
 }
 
- static int
+static int
 ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -335,14 +331,14 @@ ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        pdata->alrm_hour = alrm->time.tm_hour;
        pdata->alrm_min = alrm->time.tm_min;
        pdata->alrm_sec = alrm->time.tm_sec;
-       if (alrm->enabled) {
+       if (alrm->enabled)
                pdata->irqen |= RTC_AF;
-       }
+
        ds1511_rtc_update_alarm(pdata);
        return 0;
 }
 
- static int
+static int
 ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -359,7 +355,7 @@ ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        return 0;
 }
 
- static irqreturn_t
+static irqreturn_t
 ds1511_interrupt(int irq, void *dev_id)
 {
        struct platform_device *pdev = dev_id;
@@ -406,7 +402,7 @@ static const struct rtc_class_ops ds1511_rtc_ops = {
        .alarm_irq_enable       = ds1511_rtc_alarm_irq_enable,
 };
 
- static ssize_t
+static ssize_t
 ds1511_nvram_read(struct file *filp, struct kobject *kobj,
                  struct bin_attribute *ba,
                  char *buf, loff_t pos, size_t size)
@@ -417,26 +413,26 @@ ds1511_nvram_read(struct file *filp, struct kobject *kobj,
         * if count is more than one, turn on "burst" mode
         * turn it off when you're done
         */
-       if (size > 1) {
+       if (size > 1)
                rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
-       }
-       if (pos > DS1511_RAM_MAX) {
+
+       if (pos > DS1511_RAM_MAX)
                pos = DS1511_RAM_MAX;
-       }
-       if (size + pos > DS1511_RAM_MAX + 1) {
+
+       if (size + pos > DS1511_RAM_MAX + 1)
                size = DS1511_RAM_MAX - pos + 1;
-       }
+
        rtc_write(pos, DS1511_RAMADDR_LSB);
-       for (count = 0; size > 0; count++, size--) {
+       for (count = 0; size > 0; count++, size--)
                *buf++ = rtc_read(DS1511_RAMDATA);
-       }
-       if (count > 1) {
+
+       if (count > 1)
                rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
-       }
+
        return count;
 }
 
- static ssize_t
+static ssize_t
 ds1511_nvram_write(struct file *filp, struct kobject *kobj,
                   struct bin_attribute *bin_attr,
                   char *buf, loff_t pos, size_t size)
@@ -447,22 +443,22 @@ ds1511_nvram_write(struct file *filp, struct kobject *kobj,
         * if count is more than one, turn on "burst" mode
         * turn it off when you're done
         */
-       if (size > 1) {
+       if (size > 1)
                rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
-       }
-       if (pos > DS1511_RAM_MAX) {
+
+       if (pos > DS1511_RAM_MAX)
                pos = DS1511_RAM_MAX;
-       }
-       if (size + pos > DS1511_RAM_MAX + 1) {
+
+       if (size + pos > DS1511_RAM_MAX + 1)
                size = DS1511_RAM_MAX - pos + 1;
-       }
+
        rtc_write(pos, DS1511_RAMADDR_LSB);
-       for (count = 0; size > 0; count++, size--) {
+       for (count = 0; size > 0; count++, size--)
                rtc_write(*buf++, DS1511_RAMDATA);
-       }
-       if (count > 1) {
+
+       if (count > 1)
                rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
-       }
+
        return count;
 }
 
@@ -484,9 +480,9 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
        int ret = 0;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
+       if (!res)
                return -ENODEV;
-       }
+
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
@@ -518,9 +514,8 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
        /*
         * check for a dying bat-tree
         */
-       if (rtc_read(RTC_CMD1) & DS1511_BLF1) {
+       if (rtc_read(RTC_CMD1) & DS1511_BLF1)
                dev_warn(&pdev->dev, "voltage-low detected.\n");
-       }
 
        spin_lock_init(&pdata->lock);
        platform_set_drvdata(pdev, pdata);
index 3fc2a4738027d34754f0f162d98dccbc6c7cb2d5..18e2d847147288c6890812640376c64d87543212 100644 (file)
@@ -153,11 +153,6 @@ static const struct rtc_class_ops ds1672_rtc_ops = {
        .set_mmss = ds1672_rtc_set_mmss,
 };
 
-static int ds1672_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static int ds1672_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -210,7 +205,6 @@ static struct i2c_driver ds1672_driver = {
                   .name = "rtc-ds1672",
                   },
        .probe = &ds1672_probe,
-       .remove = &ds1672_remove,
        .id_table = ds1672_id,
 };
 
index ba98c0e9580dc79d84e2eb0a913821556345afc7..4c9ba53684643e2b1b1babc71b1cb968862af68a 100644 (file)
@@ -73,7 +73,7 @@ static int ds3234_read_time(struct device *dev, struct rtc_time *dt)
        dt->tm_wday     = bcd2bin(buf[3]) - 1; /* 0 = Sun */
        dt->tm_mday     = bcd2bin(buf[4]);
        dt->tm_mon      = bcd2bin(buf[5] & 0x1f) - 1; /* 0 = Jan */
-       dt->tm_year     = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */
+       dt->tm_year     = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */
 
        return rtc_valid_tm(dt);
 }
@@ -156,18 +156,12 @@ static int ds3234_probe(struct spi_device *spi)
        return 0;
 }
 
-static int ds3234_remove(struct spi_device *spi)
-{
-       return 0;
-}
-
 static struct spi_driver ds3234_driver = {
        .driver = {
                .name    = "ds3234",
                .owner  = THIS_MODULE,
        },
        .probe   = ds3234_probe,
-       .remove = ds3234_remove,
 };
 
 module_spi_driver(ds3234_driver);
index b3c8c0b1709dec601e83c2d9a78ee0b20d042c30..797aa0252ba9adcd62fb765f46c8e8dfffc2c691 100644 (file)
@@ -201,17 +201,11 @@ static int __init efi_rtc_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __exit efi_rtc_remove(struct platform_device *dev)
-{
-       return 0;
-}
-
 static struct platform_driver efi_rtc_driver = {
        .driver = {
                .name = "rtc-efi",
                .owner = THIS_MODULE,
        },
-       .remove = __exit_p(efi_rtc_remove),
 };
 
 module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe);
index 3f9eb57d0486892e979ce65d0ce51c2021466782..fccf3669924540d13c3f8a2e9193a671fff8b396 100644 (file)
@@ -131,11 +131,6 @@ static int em3027_probe(struct i2c_client *client,
        return 0;
 }
 
-static int em3027_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static struct i2c_device_id em3027_id[] = {
        { "em3027", 0 },
        { }
@@ -146,7 +141,6 @@ static struct i2c_driver em3027_driver = {
                   .name = "rtc-em3027",
        },
        .probe = &em3027_probe,
-       .remove = &em3027_remove,
        .id_table = em3027_id,
 };
 
index 5807b77c444a86df3790046ff158f2cb994af244..549b3c3792d203dcb485517916a6b6c55228573d 100644 (file)
@@ -167,7 +167,6 @@ static int ep93xx_rtc_probe(struct platform_device *pdev)
        return 0;
 
 exit:
-       platform_set_drvdata(pdev, NULL);
        pdev->dev.platform_data = NULL;
        return err;
 }
@@ -175,7 +174,6 @@ exit:
 static int ep93xx_rtc_remove(struct platform_device *pdev)
 {
        sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
-       platform_set_drvdata(pdev, NULL);
        pdev->dev.platform_data = NULL;
 
        return 0;
index 2835fb6c1965a7d1acbaba149f1a387aed9904ce..83c3b3029fa774321332961b7abad8796088686b 100644 (file)
@@ -47,7 +47,7 @@
 
 struct fm3130 {
        u8                      reg_addr_time;
-       u8                      reg_addr_alarm;
+       u8                      reg_addr_alarm;
        u8                      regs[15];
        struct i2c_msg          msg[4];
        struct i2c_client       *client;
@@ -520,18 +520,12 @@ exit_free:
        return err;
 }
 
-static int fm3130_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static struct i2c_driver fm3130_driver = {
        .driver = {
                .name   = "rtc-fm3130",
                .owner  = THIS_MODULE,
        },
        .probe          = fm3130_probe,
-       .remove         = fm3130_remove,
        .id_table       = fm3130_id,
 };
 
index 06279ce6bff26aeaa27764621af7fc8930bc244c..9b6725ebbfb2bfbd31b44208b73e165ab0351172 100644 (file)
@@ -48,17 +48,11 @@ static int __init generic_rtc_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __exit generic_rtc_remove(struct platform_device *dev)
-{
-       return 0;
-}
-
 static struct platform_driver generic_rtc_driver = {
        .driver = {
                .name = "rtc-generic",
                .owner = THIS_MODULE,
        },
-       .remove = __exit_p(generic_rtc_remove),
 };
 
 module_platform_driver_probe(generic_rtc_driver, generic_rtc_probe);
index 63024505dddc4e4f5e1f39f37a6a468d76fde01c..7273b0139e5cdbdb72002ee8ab8a28ec85688f6e 100644 (file)
@@ -76,6 +76,20 @@ static int hid_time_proc_event(struct hid_sensor_hub_device *hsdev,
        return 0;
 }
 
+static u32 hid_time_value(size_t raw_len, char *raw_data)
+{
+       switch (raw_len) {
+       case 1:
+               return *(u8 *)raw_data;
+       case 2:
+               return *(u16 *)raw_data;
+       case 4:
+               return *(u32 *)raw_data;
+       default:
+               return (u32)(~0U); /* 0xff... or -1 to denote an error */
+       }
+}
+
 static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev,
                                unsigned usage_id, size_t raw_len,
                                char *raw_data, void *priv)
@@ -85,26 +99,35 @@ static int hid_time_capture_sample(struct hid_sensor_hub_device *hsdev,
 
        switch (usage_id) {
        case HID_USAGE_SENSOR_TIME_YEAR:
-               time_buf->tm_year = *(u8 *)raw_data;
-               if (time_buf->tm_year < 70)
-                       /* assume we are in 1970...2069 */
-                       time_buf->tm_year += 100;
+               /*
+                * The draft for HID-sensors (HUTRR39) currently doesn't define
+                * the range for the year attribute. Therefor we support
+                * 8 bit (0-99) and 16 or 32 bits (full) as size for the year.
+                */
+               if (raw_len == 1) {
+                       time_buf->tm_year = *(u8 *)raw_data;
+                       if (time_buf->tm_year < 70)
+                               /* assume we are in 1970...2069 */
+                               time_buf->tm_year += 100;
+               } else
+                       time_buf->tm_year =
+                               (int)hid_time_value(raw_len, raw_data)-1900;
                break;
        case HID_USAGE_SENSOR_TIME_MONTH:
-               /* sensor sending the month as 1-12, we need 0-11 */
-               time_buf->tm_mon = *(u8 *)raw_data-1;
+               /* sensors are sending the month as 1-12, we need 0-11 */
+               time_buf->tm_mon = (int)hid_time_value(raw_len, raw_data)-1;
                break;
        case HID_USAGE_SENSOR_TIME_DAY:
-               time_buf->tm_mday = *(u8 *)raw_data;
+               time_buf->tm_mday = (int)hid_time_value(raw_len, raw_data);
                break;
        case HID_USAGE_SENSOR_TIME_HOUR:
-               time_buf->tm_hour = *(u8 *)raw_data;
+               time_buf->tm_hour = (int)hid_time_value(raw_len, raw_data);
                break;
        case HID_USAGE_SENSOR_TIME_MINUTE:
-               time_buf->tm_min = *(u8 *)raw_data;
+               time_buf->tm_min = (int)hid_time_value(raw_len, raw_data);
                break;
        case HID_USAGE_SENSOR_TIME_SECOND:
-               time_buf->tm_sec = *(u8 *)raw_data;
+               time_buf->tm_sec = (int)hid_time_value(raw_len, raw_data);
                break;
        default:
                return -EINVAL;
@@ -150,9 +173,10 @@ static int hid_time_parse_report(struct platform_device *pdev,
                                "not all needed attributes inside the same report!\n");
                        return -EINVAL;
                }
-               if (time_state->info[i].size != 1) {
+               if (time_state->info[i].size == 3 ||
+                               time_state->info[i].size > 4) {
                        dev_err(&pdev->dev,
-                               "attribute '%s' not 8 bits wide!\n",
+                               "attribute '%s' not 8, 16 or 32 bits wide!\n",
                                hid_time_attrib_name(
                                        time_state->info[i].attrib_id));
                        return -EINVAL;
index a1bbbb8de02945295c3c9f2ceaa93c1c1821260c..5dbdc4405718f55705151b7f62ad8d76db154341 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/rtc.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/err.h>
 
 #define DRV_VERSION "0.1"
 
@@ -267,15 +268,7 @@ static int isl12022_probe(struct i2c_client *client,
        isl12022->rtc = devm_rtc_device_register(&client->dev,
                                        isl12022_driver.driver.name,
                                        &isl12022_rtc_ops, THIS_MODULE);
-       if (IS_ERR(isl12022->rtc))
-               return PTR_ERR(isl12022->rtc);
-
-       return 0;
-}
-
-static int isl12022_remove(struct i2c_client *client)
-{
-       return 0;
+       return PTR_RET(isl12022->rtc);
 }
 
 static const struct i2c_device_id isl12022_id[] = {
@@ -289,7 +282,6 @@ static struct i2c_driver isl12022_driver = {
                .name   = "rtc-isl12022",
        },
        .probe          = isl12022_probe,
-       .remove         = isl12022_remove,
        .id_table       = isl12022_id,
 };
 
index 1e48686ca6d22c9b54de8394cd9dced5c80b9c20..1b126d2513de9978df1b2a5e4018b8f86733ffe6 100644 (file)
@@ -14,6 +14,7 @@
  *
  */
 
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -216,37 +217,34 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
        struct jz4740_rtc *rtc;
        uint32_t scratchpad;
 
-       rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+       rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
        rtc->irq = platform_get_irq(pdev, 0);
        if (rtc->irq < 0) {
-               ret = -ENOENT;
                dev_err(&pdev->dev, "Failed to get platform irq\n");
-               goto err_free;
+               return -ENOENT;
        }
 
        rtc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!rtc->mem) {
-               ret = -ENOENT;
                dev_err(&pdev->dev, "Failed to get platform mmio memory\n");
-               goto err_free;
+               return -ENOENT;
        }
 
-       rtc->mem = request_mem_region(rtc->mem->start, resource_size(rtc->mem),
-                                       pdev->name);
+       rtc->mem = devm_request_mem_region(&pdev->dev, rtc->mem->start,
+                                       resource_size(rtc->mem), pdev->name);
        if (!rtc->mem) {
-               ret = -EBUSY;
                dev_err(&pdev->dev, "Failed to request mmio memory region\n");
-               goto err_free;
+               return -EBUSY;
        }
 
-       rtc->base = ioremap_nocache(rtc->mem->start, resource_size(rtc->mem));
+       rtc->base = devm_ioremap_nocache(&pdev->dev, rtc->mem->start,
+                                       resource_size(rtc->mem));
        if (!rtc->base) {
-               ret = -EBUSY;
                dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
-               goto err_release_mem_region;
+               return -EBUSY;
        }
 
        spin_lock_init(&rtc->lock);
@@ -255,19 +253,19 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
 
        device_init_wakeup(&pdev->dev, 1);
 
-       rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &jz4740_rtc_ops,
-                                       THIS_MODULE);
+       rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+                                       &jz4740_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc->rtc)) {
                ret = PTR_ERR(rtc->rtc);
                dev_err(&pdev->dev, "Failed to register rtc device: %d\n", ret);
-               goto err_iounmap;
+               return ret;
        }
 
-       ret = request_irq(rtc->irq, jz4740_rtc_irq, 0,
+       ret = devm_request_irq(&pdev->dev, rtc->irq, jz4740_rtc_irq, 0,
                                pdev->name, rtc);
        if (ret) {
                dev_err(&pdev->dev, "Failed to request rtc irq: %d\n", ret);
-               goto err_unregister_rtc;
+               return ret;
        }
 
        scratchpad = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SCRATCHPAD);
@@ -276,46 +274,13 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
                ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, 0);
                if (ret) {
                        dev_err(&pdev->dev, "Could not write write to RTC registers\n");
-                       goto err_free_irq;
+                       return ret;
                }
        }
 
-       return 0;
-
-err_free_irq:
-       free_irq(rtc->irq, rtc);
-err_unregister_rtc:
-       rtc_device_unregister(rtc->rtc);
-err_iounmap:
-       platform_set_drvdata(pdev, NULL);
-       iounmap(rtc->base);
-err_release_mem_region:
-       release_mem_region(rtc->mem->start, resource_size(rtc->mem));
-err_free:
-       kfree(rtc);
-
-       return ret;
-}
-
-static int jz4740_rtc_remove(struct platform_device *pdev)
-{
-       struct jz4740_rtc *rtc = platform_get_drvdata(pdev);
-
-       free_irq(rtc->irq, rtc);
-
-       rtc_device_unregister(rtc->rtc);
-
-       iounmap(rtc->base);
-       release_mem_region(rtc->mem->start, resource_size(rtc->mem));
-
-       kfree(rtc);
-
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
-
 #ifdef CONFIG_PM
 static int jz4740_rtc_suspend(struct device *dev)
 {
@@ -347,7 +312,6 @@ static const struct dev_pm_ops jz4740_pm_ops = {
 
 static struct platform_driver jz4740_rtc_driver = {
        .probe   = jz4740_rtc_probe,
-       .remove  = jz4740_rtc_remove,
        .driver  = {
                .name  = "jz4740-rtc",
                .owner = THIS_MODULE,
index 9853ac15b296bb0a41ff1a25f0b678a1516975b3..4ff6c73253b3230abc365b496d47f32fae6e2f1e 100644 (file)
@@ -312,16 +312,8 @@ static int lp8788_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int lp8788_rtc_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
 static struct platform_driver lp8788_rtc_driver = {
        .probe = lp8788_rtc_probe,
-       .remove = lp8788_rtc_remove,
        .driver = {
                .name = LP8788_DEV_RTC,
                .owner = THIS_MODULE,
index 787550d756e9b1bb06afc276de06df8d4f067055..8276ae94a2a933fd62dbde325954c7bb7fc65de6 100644 (file)
@@ -277,7 +277,6 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
                                        &lpc32xx_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc->rtc)) {
                dev_err(&pdev->dev, "Can't get RTC\n");
-               platform_set_drvdata(pdev, NULL);
                return PTR_ERR(rtc->rtc);
        }
 
@@ -306,8 +305,6 @@ static int lpc32xx_rtc_remove(struct platform_device *pdev)
        if (rtc->irq >= 0)
                device_init_wakeup(&pdev->dev, 0);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index db82f91f456254f77f88f2cd50c862f169ea7aa3..682ecb094839ce9529e02cbd4c5aebdb92cc38f4 100644 (file)
@@ -185,19 +185,11 @@ err:
        return ret;
 }
 
-static int ls1x_rtc_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
 static struct platform_driver  ls1x_rtc_driver = {
        .driver         = {
                .name   = "ls1x-rtc",
                .owner  = THIS_MODULE,
        },
-       .remove         = ls1x_rtc_remove,
        .probe          = ls1x_rtc_probe,
 };
 
index 89674b5e6efda050b1f1ef718682221e7ca10d79..a5248aa1abf143c852597ff12e4ecda0bcd9cd7e 100644 (file)
@@ -168,7 +168,7 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
        buf[M41T80_REG_MIN] =
                bin2bcd(tm->tm_min) | (buf[M41T80_REG_MIN] & ~0x7f);
        buf[M41T80_REG_HOUR] =
-               bin2bcd(tm->tm_hour) | (buf[M41T80_REG_HOUR] & ~0x3f) ;
+               bin2bcd(tm->tm_hour) | (buf[M41T80_REG_HOUR] & ~0x3f);
        buf[M41T80_REG_WDAY] =
                (tm->tm_wday & 0x07) | (buf[M41T80_REG_WDAY] & ~0x07);
        buf[M41T80_REG_DAY] =
index 9707d36e8b15e427d14f51819a5105607c847b81..4698c7e344e4be907590565a89880218367dbd4b 100644 (file)
@@ -194,19 +194,12 @@ static int m41t93_probe(struct spi_device *spi)
        return 0;
 }
 
-
-static int m41t93_remove(struct spi_device *spi)
-{
-       return 0;
-}
-
 static struct spi_driver m41t93_driver = {
        .driver = {
                .name   = "rtc-m41t93",
                .owner  = THIS_MODULE,
        },
        .probe  = m41t93_probe,
-       .remove = m41t93_remove,
 };
 
 module_spi_driver(m41t93_driver);
index 7454ef0a4cfa0b764e6a8fe2c1b3e6f693b189b1..8d800b1bf87b7cc61ec6c56a5a282bb56e1beeeb 100644 (file)
@@ -134,18 +134,12 @@ static int m41t94_probe(struct spi_device *spi)
        return 0;
 }
 
-static int m41t94_remove(struct spi_device *spi)
-{
-       return 0;
-}
-
 static struct spi_driver m41t94_driver = {
        .driver = {
                .name   = "rtc-m41t94",
                .owner  = THIS_MODULE,
        },
        .probe  = m41t94_probe,
-       .remove = m41t94_remove,
 };
 
 module_spi_driver(m41t94_driver);
index 37444246e5e49e2989cbe743c2b284e9e8d9a4a0..23c3779a5f2b4b7b26bba02b222cc724fe9670c3 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/bcd.h>
 #include <linux/io.h>
+#include <linux/err.h>
 
 #define DRV_VERSION            "1.0"
 
@@ -174,15 +175,7 @@ static int m48t35_probe(struct platform_device *pdev)
 
        priv->rtc = devm_rtc_device_register(&pdev->dev, "m48t35",
                                  &m48t35_ops, THIS_MODULE);
-       if (IS_ERR(priv->rtc))
-               return PTR_ERR(priv->rtc);
-
-       return 0;
-}
-
-static int m48t35_remove(struct platform_device *pdev)
-{
-       return 0;
+       return PTR_RET(priv->rtc);
 }
 
 static struct platform_driver m48t35_platform_driver = {
@@ -191,7 +184,6 @@ static struct platform_driver m48t35_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = m48t35_probe,
-       .remove         = m48t35_remove,
 };
 
 module_platform_driver(m48t35_platform_driver);
index 130f29af3869c974160c896d41ce890a6a64e217..fcb03291f1454c07b85d005d605cf12617e368b5 100644 (file)
@@ -409,7 +409,8 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
        } else if (res->flags & IORESOURCE_MEM) {
                /* we are memory-mapped */
                if (!pdata) {
-                       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+                       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata),
+                                               GFP_KERNEL);
                        if (!pdata)
                                return -ENOMEM;
                        /* Ensure we only kmalloc platform data once */
@@ -425,7 +426,7 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
                        pdata->read_byte = m48t59_mem_readb;
        }
 
-       m48t59 = kzalloc(sizeof(*m48t59), GFP_KERNEL);
+       m48t59 = devm_kzalloc(&pdev->dev, sizeof(*m48t59), GFP_KERNEL);
        if (!m48t59)
                return -ENOMEM;
 
@@ -433,9 +434,10 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
 
        if (!m48t59->ioaddr) {
                /* ioaddr not mapped externally */
-               m48t59->ioaddr = ioremap(res->start, resource_size(res));
+               m48t59->ioaddr = devm_ioremap(&pdev->dev, res->start,
+                                               resource_size(res));
                if (!m48t59->ioaddr)
-                       goto out;
+                       return ret;
        }
 
        /* Try to get irq number. We also can work in
@@ -446,10 +448,11 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
                m48t59->irq = NO_IRQ;
 
        if (m48t59->irq != NO_IRQ) {
-               ret = request_irq(m48t59->irq, m48t59_rtc_interrupt,
-                       IRQF_SHARED, "rtc-m48t59", &pdev->dev);
+               ret = devm_request_irq(&pdev->dev, m48t59->irq,
+                               m48t59_rtc_interrupt, IRQF_SHARED,
+                               "rtc-m48t59", &pdev->dev);
                if (ret)
-                       goto out;
+                       return ret;
        }
        switch (pdata->type) {
        case M48T59RTC_TYPE_M48T59:
@@ -469,52 +472,29 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
                break;
        default:
                dev_err(&pdev->dev, "Unknown RTC type\n");
-               ret = -ENODEV;
-               goto out;
+               return -ENODEV;
        }
 
        spin_lock_init(&m48t59->lock);
        platform_set_drvdata(pdev, m48t59);
 
-       m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE);
-       if (IS_ERR(m48t59->rtc)) {
-               ret = PTR_ERR(m48t59->rtc);
-               goto out;
-       }
+       m48t59->rtc = devm_rtc_device_register(&pdev->dev, name, ops,
+                                               THIS_MODULE);
+       if (IS_ERR(m48t59->rtc))
+               return PTR_ERR(m48t59->rtc);
 
        m48t59_nvram_attr.size = pdata->offset;
 
        ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
-       if (ret) {
-               rtc_device_unregister(m48t59->rtc);
-               goto out;
-       }
+       if (ret)
+               return ret;
 
        return 0;
-
-out:
-       if (m48t59->irq != NO_IRQ)
-               free_irq(m48t59->irq, &pdev->dev);
-       if (m48t59->ioaddr)
-               iounmap(m48t59->ioaddr);
-               kfree(m48t59);
-       return ret;
 }
 
 static int m48t59_rtc_remove(struct platform_device *pdev)
 {
-       struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
-       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
-
        sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
-       if (!IS_ERR(m48t59->rtc))
-               rtc_device_unregister(m48t59->rtc);
-       if (m48t59->ioaddr && !pdata->ioaddr)
-               iounmap(m48t59->ioaddr);
-       if (m48t59->irq != NO_IRQ)
-               free_irq(m48t59->irq, &pdev->dev);
-       platform_set_drvdata(pdev, NULL);
-       kfree(m48t59);
        return 0;
 }
 
index 33a91c4845335e37af3d3c8d093926851930d21c..2d30314fa07f9dff1162c329318b2463ac1bea3b 100644 (file)
@@ -166,20 +166,12 @@ static int m48t86_rtc_probe(struct platform_device *dev)
        return 0;
 }
 
-static int m48t86_rtc_remove(struct platform_device *dev)
-{
-       platform_set_drvdata(dev, NULL);
-
-       return 0;
-}
-
 static struct platform_driver m48t86_rtc_platform_driver = {
        .driver         = {
                .name   = "rtc-m48t86",
                .owner  = THIS_MODULE,
        },
        .probe          = m48t86_rtc_probe,
-       .remove         = m48t86_rtc_remove,
 };
 
 module_platform_driver(m48t86_rtc_platform_driver);
index 8669d6d09a00da71c6db8d598d7409449c0aa00d..55969b1b771a344a69125e2d517f8a6cdfc8f335 100644 (file)
@@ -212,11 +212,6 @@ static int max6900_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return max6900_i2c_set_time(to_i2c_client(dev), tm);
 }
 
-static int max6900_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static const struct rtc_class_ops max6900_rtc_ops = {
        .read_time = max6900_rtc_read_time,
        .set_time = max6900_rtc_set_time,
@@ -252,7 +247,6 @@ static struct i2c_driver max6900_driver = {
                   .name = "rtc-max6900",
                   },
        .probe = max6900_probe,
-       .remove = max6900_remove,
        .id_table = max6900_id,
 };
 
index e3aea00c3145746fd32abe405f091142856d6633..ac3f4191864f026103c7b9b26cafee8716d9ed2a 100644 (file)
@@ -143,23 +143,17 @@ static int max6902_probe(struct spi_device *spi)
        return 0;
 }
 
-static int max6902_remove(struct spi_device *spi)
-{
-       return 0;
-}
-
 static struct spi_driver max6902_driver = {
        .driver = {
                .name   = "rtc-max6902",
                .owner  = THIS_MODULE,
        },
        .probe  = max6902_probe,
-       .remove = max6902_remove,
 };
 
 module_spi_driver(max6902_driver);
 
-MODULE_DESCRIPTION ("max6902 spi RTC driver");
-MODULE_AUTHOR ("Raphael Assenat");
-MODULE_LICENSE ("GPL");
+MODULE_DESCRIPTION("max6902 spi RTC driver");
+MODULE_AUTHOR("Raphael Assenat");
+MODULE_LICENSE("GPL");
 MODULE_ALIAS("spi:rtc-max6902");
index 771812d62e6bd3a961742db477e660771ee593f1..9915cb96014bc96df91952bb67a7786cedc1f4d1 100644 (file)
@@ -119,7 +119,7 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
        data[RTC_WEEKDAY] = 1 << tm->tm_wday;
        data[RTC_DATE] = tm->tm_mday;
        data[RTC_MONTH] = tm->tm_mon + 1;
-       data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ;
+       data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0;
 
        if (tm->tm_year < 100) {
                pr_warn("%s: MAX77686 RTC cannot handle the year %d."
@@ -567,11 +567,6 @@ err_rtc:
        return ret;
 }
 
-static int max77686_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static void max77686_rtc_shutdown(struct platform_device *pdev)
 {
 #ifdef MAX77686_RTC_WTSR_SMPL
@@ -610,7 +605,6 @@ static struct platform_driver max77686_rtc_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = max77686_rtc_probe,
-       .remove         = max77686_rtc_remove,
        .shutdown       = max77686_rtc_shutdown,
        .id_table       = rtc_id,
 };
index 86afb797125dc4de28c643afaab1785375d47ca6..8e45b3c4aa2fdb10629c90a4b23b9af6eb6bc06f 100644 (file)
@@ -213,18 +213,12 @@ static int max8907_rtc_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int max8907_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static struct platform_driver max8907_rtc_driver = {
        .driver = {
                .name = "max8907-rtc",
                .owner = THIS_MODULE,
        },
        .probe = max8907_rtc_probe,
-       .remove = max8907_rtc_remove,
 };
 module_platform_driver(max8907_rtc_driver);
 
index 7c90f4e45e27b07eb836f06009e9a605266f4988..951d1a78e1907599d62256c46774d4c33829ff19 100644 (file)
@@ -268,7 +268,7 @@ static int max8925_rtc_probe(struct platform_device *pdev)
        if (ret < 0) {
                dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
                        info->irq, ret);
-               goto err;
+               return ret;
        }
 
        dev_set_drvdata(&pdev->dev, info);
@@ -282,17 +282,9 @@ static int max8925_rtc_probe(struct platform_device *pdev)
        ret = PTR_ERR(info->rtc_dev);
        if (IS_ERR(info->rtc_dev)) {
                dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
-               goto err;
+               return ret;
        }
 
-       return 0;
-err:
-       platform_set_drvdata(pdev, NULL);
-       return ret;
-}
-
-static int max8925_rtc_remove(struct platform_device *pdev)
-{
        return 0;
 }
 
@@ -326,7 +318,6 @@ static struct platform_driver max8925_rtc_driver = {
                .pm     = &max8925_rtc_pm_ops,
        },
        .probe          = max8925_rtc_probe,
-       .remove         = max8925_rtc_remove,
 };
 
 module_platform_driver(max8925_rtc_driver);
index dacf48db792593305961fbf10cb830de183d1926..0777c01b58e09b6d51e31f4e5929ae6ede021ffe 100644 (file)
@@ -104,7 +104,7 @@ static int max8997_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
        data[RTC_WEEKDAY] = 1 << tm->tm_wday;
        data[RTC_DATE] = tm->tm_mday;
        data[RTC_MONTH] = tm->tm_mon + 1;
-       data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ;
+       data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0;
 
        if (tm->tm_year < 100) {
                pr_warn("%s: MAX8997 RTC cannot handle the year %d."
@@ -507,11 +507,6 @@ err_out:
        return ret;
 }
 
-static int max8997_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static void max8997_rtc_shutdown(struct platform_device *pdev)
 {
        struct max8997_rtc_info *info = platform_get_drvdata(pdev);
@@ -531,7 +526,6 @@ static struct platform_driver max8997_rtc_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = max8997_rtc_probe,
-       .remove         = max8997_rtc_remove,
        .shutdown       = max8997_rtc_shutdown,
        .id_table       = rtc_id,
 };
index d5af7baa48b56c893e449b418d158f7b25448628..5388336a2c4cc89e9a872d77c27a00a8d82ec5df 100644 (file)
@@ -274,7 +274,7 @@ static int max8998_rtc_probe(struct platform_device *pdev)
        if (IS_ERR(info->rtc_dev)) {
                ret = PTR_ERR(info->rtc_dev);
                dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
-               goto out_rtc;
+               return ret;
        }
 
        ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
@@ -292,15 +292,6 @@ static int max8998_rtc_probe(struct platform_device *pdev)
        }
 
        return 0;
-
-out_rtc:
-       platform_set_drvdata(pdev, NULL);
-       return ret;
-}
-
-static int max8998_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
 }
 
 static const struct platform_device_id max8998_rtc_id[] = {
@@ -315,7 +306,6 @@ static struct platform_driver max8998_rtc_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = max8998_rtc_probe,
-       .remove         = max8998_rtc_remove,
        .id_table       = max8998_rtc_id,
 };
 
index 7a8ed27a5f2e1482c95aafab39e2ca7c1544f8eb..77ea9896b5bab48ab7c8873cabddde95eb0cb901 100644 (file)
@@ -370,8 +370,6 @@ err_reset_irq_status:
 err_reset_irq_request:
 
                mc13xxx_unlock(mc13xxx);
-
-               platform_set_drvdata(pdev, NULL);
        }
 
        return ret;
@@ -389,8 +387,6 @@ static int __exit mc13xxx_rtc_remove(struct platform_device *pdev)
 
        mc13xxx_unlock(priv->mc13xxx);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index bdcc60830aece4757cff90a22e14f9c46487c313..9c8f6090379991b0ea4ec0643a7f97d763c2ed0a 100644 (file)
@@ -68,7 +68,7 @@ struct mpc5121_rtc_regs {
        u32 target_time;        /* RTC + 0x20 */
        /*
         * actual_time:
-        *      readonly time since VBAT_RTC was last connected
+        *      readonly time since VBAT_RTC was last connected
         */
        u32 actual_time;        /* RTC + 0x24 */
        u32 keep_alive;         /* RTC + 0x28 */
@@ -312,20 +312,19 @@ static int mpc5121_rtc_probe(struct platform_device *op)
        struct mpc5121_rtc_data *rtc;
        int err = 0;
 
-       rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+       rtc = devm_kzalloc(&op->dev, sizeof(*rtc), GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
        rtc->regs = of_iomap(op->dev.of_node, 0);
        if (!rtc->regs) {
                dev_err(&op->dev, "%s: couldn't map io space\n", __func__);
-               err = -ENOSYS;
-               goto out_free;
+               return -ENOSYS;
        }
 
        device_init_wakeup(&op->dev, 1);
 
-       dev_set_drvdata(&op->dev, rtc);
+       platform_set_drvdata(op, rtc);
 
        rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1);
        err = request_irq(rtc->irq, mpc5121_rtc_handler, 0,
@@ -354,10 +353,10 @@ static int mpc5121_rtc_probe(struct platform_device *op)
                        out_be32(&rtc->regs->keep_alive, ka);
                }
 
-               rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
+               rtc->rtc = devm_rtc_device_register(&op->dev, "mpc5121-rtc",
                                                &mpc5121_rtc_ops, THIS_MODULE);
        } else {
-               rtc->rtc = rtc_device_register("mpc5200-rtc", &op->dev,
+               rtc->rtc = devm_rtc_device_register(&op->dev, "mpc5200-rtc",
                                                &mpc5200_rtc_ops, THIS_MODULE);
        }
 
@@ -377,29 +376,24 @@ out_dispose2:
 out_dispose:
        irq_dispose_mapping(rtc->irq);
        iounmap(rtc->regs);
-out_free:
-       kfree(rtc);
 
        return err;
 }
 
 static int mpc5121_rtc_remove(struct platform_device *op)
 {
-       struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev);
+       struct mpc5121_rtc_data *rtc = platform_get_drvdata(op);
        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
 
        /* disable interrupt, so there are no nasty surprises */
        out_8(&regs->alm_enable, 0);
        out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
 
-       rtc_device_unregister(rtc->rtc);
        iounmap(rtc->regs);
        free_irq(rtc->irq, &op->dev);
        free_irq(rtc->irq_periodic, &op->dev);
        irq_dispose_mapping(rtc->irq);
        irq_dispose_mapping(rtc->irq_periodic);
-       dev_set_drvdata(&op->dev, NULL);
-       kfree(rtc);
 
        return 0;
 }
index 771f86a05d14209233e11c9d1106b336a484b7ce..426cb5189daa7ee395bd842476ce4430be5426d4 100644 (file)
@@ -111,8 +111,8 @@ static void msm6242_lock(struct msm6242_priv *priv)
        }
 
        if (!cnt)
-               pr_warning("msm6242: timed out waiting for RTC (0x%x)\n",
-                          msm6242_read(priv, MSM6242_CD));
+               pr_warn("msm6242: timed out waiting for RTC (0x%x)\n",
+                       msm6242_read(priv, MSM6242_CD));
 }
 
 static void msm6242_unlock(struct msm6242_priv *priv)
@@ -199,7 +199,6 @@ static int __init msm6242_rtc_probe(struct platform_device *pdev)
        struct resource *res;
        struct msm6242_priv *priv;
        struct rtc_device *rtc;
-       int error;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
@@ -216,22 +215,11 @@ static int __init msm6242_rtc_probe(struct platform_device *pdev)
 
        rtc = devm_rtc_device_register(&pdev->dev, "rtc-msm6242",
                                &msm6242_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc)) {
-               error = PTR_ERR(rtc);
-               goto out_unmap;
-       }
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
 
        priv->rtc = rtc;
        return 0;
-
-out_unmap:
-       platform_set_drvdata(pdev, NULL);
-       return error;
-}
-
-static int __exit msm6242_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
 }
 
 static struct platform_driver msm6242_rtc_driver = {
@@ -239,7 +227,6 @@ static struct platform_driver msm6242_rtc_driver = {
                .name   = "rtc-msm6242",
                .owner  = THIS_MODULE,
        },
-       .remove = __exit_p(msm6242_rtc_remove),
 };
 
 module_platform_driver_probe(msm6242_rtc_driver, msm6242_rtc_probe);
index 9a3895bc4f4da1dc86d6b5fad6668f6df85bb04d..ab87bacb8f880b69f01182c44d7d5cf6522c24e6 100644 (file)
@@ -436,22 +436,20 @@ static int mxc_rtc_probe(struct platform_device *pdev)
                pdata->irq = -1;
        }
 
-       if (pdata->irq >=0)
+       if (pdata->irq >= 0)
                device_init_wakeup(&pdev->dev, 1);
 
        rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
                                  THIS_MODULE);
        if (IS_ERR(rtc)) {
                ret = PTR_ERR(rtc);
-               goto exit_clr_drvdata;
+               goto exit_put_clk;
        }
 
        pdata->rtc = rtc;
 
        return 0;
 
-exit_clr_drvdata:
-       platform_set_drvdata(pdev, NULL);
 exit_put_clk:
        clk_disable_unprepare(pdata->clk);
 
@@ -465,7 +463,6 @@ static int mxc_rtc_remove(struct platform_device *pdev)
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
        clk_disable_unprepare(pdata->clk);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index d592e2fe43f7a7fd29be1592080c03d854ed22d3..22861c5e0c596fff3c87182b1beb1f1c9cdaf109 100644 (file)
@@ -260,15 +260,7 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit nuc900_rtc_remove(struct platform_device *pdev)
-{
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
 static struct platform_driver nuc900_rtc_driver = {
-       .remove         = __exit_p(nuc900_rtc_remove),
        .driver         = {
                .name   = "nuc900-rtc",
                .owner  = THIS_MODULE,
index b0ba3fc991ea2352de71d1839480f967ef8a52b0..c6ffbaec32a4b509609fe03dad3e57b2db16e439 100644 (file)
@@ -23,9 +23,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/pm_runtime.h>
-
-#include <asm/io.h>
-
+#include <linux/io.h>
 
 /* The OMAP1 RTC is a year/month/day/hours/minutes/seconds BCD clock
  * with century-range alarm matching, driven by the 32kHz clock.
@@ -423,6 +421,8 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
         *    is write-only, and always reads as zero...)
         */
 
+       device_init_wakeup(&pdev->dev, true);
+
        if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT)
                pr_info("%s: split power mode\n", pdev->name);
 
index 50204d474eb7f76526cec457b5ca86d69ed248f4..a1fecc8d97fc5e0f30f3c06b8e3d00b466289420 100644 (file)
@@ -265,6 +265,7 @@ static int palmas_rtc_probe(struct platform_device *pdev)
 
        palmas_rtc->irq = platform_get_irq(pdev, 0);
 
+       device_init_wakeup(&pdev->dev, 1);
        palmas_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                                &palmas_rtc_ops, THIS_MODULE);
        if (IS_ERR(palmas_rtc->rtc)) {
@@ -283,7 +284,6 @@ static int palmas_rtc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       device_set_wakeup_capable(&pdev->dev, 1);
        return 0;
 }
 
index 539a90b98bc5e1f8bb6f0dd39086c111110aafd9..40b5c630bc7d0288fc86fb91e2b89ac9b67cbcd4 100644 (file)
@@ -156,10 +156,8 @@ static int __init pcap_rtc_probe(struct platform_device *pdev)
 
        pcap_rtc->rtc = devm_rtc_device_register(&pdev->dev, "pcap",
                                        &pcap_rtc_ops, THIS_MODULE);
-       if (IS_ERR(pcap_rtc->rtc)) {
-               err = PTR_ERR(pcap_rtc->rtc);
-               goto fail;
-       }
+       if (IS_ERR(pcap_rtc->rtc))
+               return PTR_ERR(pcap_rtc->rtc);
 
        timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ);
        alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA);
@@ -167,17 +165,14 @@ static int __init pcap_rtc_probe(struct platform_device *pdev)
        err = devm_request_irq(&pdev->dev, timer_irq, pcap_rtc_irq, 0,
                                "RTC Timer", pcap_rtc);
        if (err)
-               goto fail;
+               return err;
 
        err = devm_request_irq(&pdev->dev, alarm_irq, pcap_rtc_irq, 0,
                                "RTC Alarm", pcap_rtc);
        if (err)
-               goto fail;
+               return err;
 
        return 0;
-fail:
-       platform_set_drvdata(pdev, NULL);
-       return err;
 }
 
 static int __exit pcap_rtc_remove(struct platform_device *pdev)
index 796a6c5067dd58bc106f746f39e3b9f221838d97..1725b5090e33d1ea8a768c07f65302f0b61831d7 100644 (file)
  * should look something like:
  *
  * static struct spi_board_info ek_spi_devices[] = {
- *     ...
- *     {
- *             .modalias               = "rtc-pcf2123",
- *             .chip_select            = 1,
- *             .controller_data        = (void *)AT91_PIN_PA10,
+ *     ...
+ *     {
+ *             .modalias               = "rtc-pcf2123",
+ *             .chip_select            = 1,
+ *             .controller_data        = (void *)AT91_PIN_PA10,
  *             .max_speed_hz           = 1000 * 1000,
  *             .mode                   = SPI_CS_HIGH,
  *             .bus_num                = 0,
@@ -94,8 +94,9 @@ static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
 
        r = container_of(attr, struct pcf2123_sysfs_reg, attr);
 
-       if (strict_strtoul(r->name, 16, &reg))
-               return -EINVAL;
+       ret = kstrtoul(r->name, 16, &reg);
+       if (ret)
+               return ret;
 
        txbuf[0] = PCF2123_READ | reg;
        ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
@@ -117,9 +118,13 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
 
        r = container_of(attr, struct pcf2123_sysfs_reg, attr);
 
-       if (strict_strtoul(r->name, 16, &reg)
-               || strict_strtoul(buffer, 10, &val))
-               return -EINVAL;
+       ret = kstrtoul(r->name, 16, &reg);
+       if (ret)
+               return ret;
+
+       ret = kstrtoul(buffer, 10, &val);
+       if (ret)
+               return ret;
 
        txbuf[0] = PCF2123_WRITE | reg;
        txbuf[1] = val;
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
new file mode 100644 (file)
index 0000000..205b9f7
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * An I2C driver for the NXP PCF2127 RTC
+ * Copyright 2013 Til-Technologies
+ *
+ * Author: Renaud Cerrato <r.cerrato@til-technologies.fr>
+ *
+ * based on the other drivers in this same directory.
+ *
+ * http://www.nxp.com/documents/data_sheet/PCF2127AT.pdf
+ *
+ * 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/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#define DRV_VERSION "0.0.1"
+
+#define PCF2127_REG_CTRL1       (0x00)  /* Control Register 1 */
+#define PCF2127_REG_CTRL2       (0x01)  /* Control Register 2 */
+#define PCF2127_REG_CTRL3       (0x02)  /* Control Register 3 */
+#define PCF2127_REG_SC          (0x03)  /* datetime */
+#define PCF2127_REG_MN          (0x04)
+#define PCF2127_REG_HR          (0x05)
+#define PCF2127_REG_DM          (0x06)
+#define PCF2127_REG_DW          (0x07)
+#define PCF2127_REG_MO          (0x08)
+#define PCF2127_REG_YR          (0x09)
+
+static struct i2c_driver pcf2127_driver;
+
+struct pcf2127 {
+       struct rtc_device *rtc;
+       int voltage_low; /* indicates if a low_voltage was detected */
+};
+
+/*
+ * In the routines that deal directly with the pcf2127 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
+ */
+static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+       struct pcf2127 *pcf2127 = i2c_get_clientdata(client);
+       unsigned char buf[10] = { PCF2127_REG_CTRL1 };
+
+       /* read registers */
+       if (i2c_master_send(client, buf, 1) != 1 ||
+               i2c_master_recv(client, buf, sizeof(buf)) != sizeof(buf)) {
+               dev_err(&client->dev, "%s: read error\n", __func__);
+               return -EIO;
+       }
+
+       if (buf[PCF2127_REG_CTRL3] & 0x04) {
+               pcf2127->voltage_low = 1;
+               dev_info(&client->dev,
+                       "low voltage detected, date/time is not reliable.\n");
+       }
+
+       dev_dbg(&client->dev,
+               "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, "
+               "sec=%02x, min=%02x, hr=%02x, "
+               "mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
+               __func__,
+               buf[0], buf[1], buf[2],
+               buf[3], buf[4], buf[5],
+               buf[6], buf[7], buf[8], buf[9]);
+
+
+       tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F);
+       tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F);
+       tm->tm_hour = bcd2bin(buf[PCF2127_REG_HR] & 0x3F); /* rtc hr 0-23 */
+       tm->tm_mday = bcd2bin(buf[PCF2127_REG_DM] & 0x3F);
+       tm->tm_wday = buf[PCF2127_REG_DW] & 0x07;
+       tm->tm_mon = bcd2bin(buf[PCF2127_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
+       tm->tm_year = bcd2bin(buf[PCF2127_REG_YR]);
+       if (tm->tm_year < 70)
+               tm->tm_year += 100;     /* assume we are in 1970...2069 */
+
+       dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+               "mday=%d, mon=%d, year=%d, wday=%d\n",
+               __func__,
+               tm->tm_sec, tm->tm_min, tm->tm_hour,
+               tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+       /* the clock can give out invalid datetime, but we cannot return
+        * -EINVAL otherwise hwclock will refuse to set the time on bootup.
+        */
+       if (rtc_valid_tm(tm) < 0)
+               dev_err(&client->dev, "retrieved date/time is not valid.\n");
+
+       return 0;
+}
+
+static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+       unsigned char buf[8];
+       int i = 0, err;
+
+       dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
+               "mday=%d, mon=%d, year=%d, wday=%d\n",
+               __func__,
+               tm->tm_sec, tm->tm_min, tm->tm_hour,
+               tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+       /* start register address */
+       buf[i++] = PCF2127_REG_SC;
+
+       /* hours, minutes and seconds */
+       buf[i++] = bin2bcd(tm->tm_sec);
+       buf[i++] = bin2bcd(tm->tm_min);
+       buf[i++] = bin2bcd(tm->tm_hour);
+       buf[i++] = bin2bcd(tm->tm_mday);
+       buf[i++] = tm->tm_wday & 0x07;
+
+       /* month, 1 - 12 */
+       buf[i++] = bin2bcd(tm->tm_mon + 1);
+
+       /* year */
+       buf[i++] = bin2bcd(tm->tm_year % 100);
+
+       /* write register's data */
+       err = i2c_master_send(client, buf, i);
+       if (err != i) {
+               dev_err(&client->dev,
+                       "%s: err=%d", __func__, err);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+static int pcf2127_rtc_ioctl(struct device *dev,
+                               unsigned int cmd, unsigned long arg)
+{
+       struct pcf2127 *pcf2127 = i2c_get_clientdata(to_i2c_client(dev));
+
+       switch (cmd) {
+       case RTC_VL_READ:
+               if (pcf2127->voltage_low)
+                       dev_info(dev, "low voltage detected, date/time is not reliable.\n");
+
+               if (copy_to_user((void __user *)arg, &pcf2127->voltage_low,
+                                       sizeof(int)))
+                       return -EFAULT;
+               return 0;
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+#else
+#define pcf2127_rtc_ioctl NULL
+#endif
+
+static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       return pcf2127_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int pcf2127_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       return pcf2127_set_datetime(to_i2c_client(dev), tm);
+}
+
+static const struct rtc_class_ops pcf2127_rtc_ops = {
+       .ioctl          = pcf2127_rtc_ioctl,
+       .read_time      = pcf2127_rtc_read_time,
+       .set_time       = pcf2127_rtc_set_time,
+};
+
+static int pcf2127_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct pcf2127 *pcf2127;
+
+       dev_dbg(&client->dev, "%s\n", __func__);
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       pcf2127 = devm_kzalloc(&client->dev, sizeof(struct pcf2127),
+                               GFP_KERNEL);
+       if (!pcf2127)
+               return -ENOMEM;
+
+       dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+       i2c_set_clientdata(client, pcf2127);
+
+       pcf2127->rtc = devm_rtc_device_register(&client->dev,
+                               pcf2127_driver.driver.name,
+                               &pcf2127_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(pcf2127->rtc))
+               return PTR_ERR(pcf2127->rtc);
+
+       return 0;
+}
+
+static int pcf2127_remove(struct i2c_client *client)
+{
+       return 0;
+}
+
+static const struct i2c_device_id pcf2127_id[] = {
+       { "pcf2127", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, pcf2127_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcf2127_of_match[] = {
+       { .compatible = "nxp,pcf2127" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, pcf2127_of_match);
+#endif
+
+static struct i2c_driver pcf2127_driver = {
+       .driver         = {
+               .name   = "rtc-pcf2127",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(pcf2127_of_match),
+       },
+       .probe          = pcf2127_probe,
+       .remove         = pcf2127_remove,
+       .id_table       = pcf2127_id,
+};
+
+module_i2c_driver(pcf2127_driver);
+
+MODULE_AUTHOR("Renaud Cerrato <r.cerrato@til-technologies.fr>");
+MODULE_DESCRIPTION("NXP PCF2127 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
index 305c9515e5bb4b578b74a2b0ff44bcbbce18d4e6..5c8f8226c8485af61dc6b82b52c56861619a3f52 100644 (file)
@@ -317,11 +317,6 @@ static int pcf8523_probe(struct i2c_client *client,
        return 0;
 }
 
-static int pcf8523_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static const struct i2c_device_id pcf8523_id[] = {
        { "pcf8523", 0 },
        { }
@@ -343,7 +338,6 @@ static struct i2c_driver pcf8523_driver = {
                .of_match_table = of_match_ptr(pcf8523_of_match),
        },
        .probe = pcf8523_probe,
-       .remove = pcf8523_remove,
        .id_table = pcf8523_id,
 };
 module_i2c_driver(pcf8523_driver);
index 97b354a26a4468d125ed3e3566a9d87ce7584ddc..710c3a5aa6fff215ed960a9680d14b1ec32120a2 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/err.h>
 
 #define DRV_VERSION "0.4.3"
 
@@ -263,15 +264,7 @@ static int pcf8563_probe(struct i2c_client *client,
                                pcf8563_driver.driver.name,
                                &pcf8563_rtc_ops, THIS_MODULE);
 
-       if (IS_ERR(pcf8563->rtc))
-               return PTR_ERR(pcf8563->rtc);
-
-       return 0;
-}
-
-static int pcf8563_remove(struct i2c_client *client)
-{
-       return 0;
+       return PTR_RET(pcf8563->rtc);
 }
 
 static const struct i2c_device_id pcf8563_id[] = {
@@ -296,7 +289,6 @@ static struct i2c_driver pcf8563_driver = {
                .of_match_table = of_match_ptr(pcf8563_of_match),
        },
        .probe          = pcf8563_probe,
-       .remove         = pcf8563_remove,
        .id_table       = pcf8563_id,
 };
 
index 95886dcf4a39b6156d31c340d25c3bddb9ecf194..843a745c42f34adeef54b1c79ffa7146e5943f4a 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/rtc.h>
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/bcd.h>
 
@@ -188,7 +189,8 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
                dev_warn(dev, "resetting control %02x -> %02x\n",
                        ctrl, new_ctrl);
 
-               if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0)
+               err = pcf8583_set_ctrl(client, &new_ctrl);
+               if (err < 0)
                        return err;
        }
 
@@ -283,15 +285,7 @@ static int pcf8583_probe(struct i2c_client *client,
                                pcf8583_driver.driver.name,
                                &pcf8583_rtc_ops, THIS_MODULE);
 
-       if (IS_ERR(pcf8583->rtc))
-               return PTR_ERR(pcf8583->rtc);
-
-       return 0;
-}
-
-static int pcf8583_remove(struct i2c_client *client)
-{
-       return 0;
+       return PTR_RET(pcf8583->rtc);
 }
 
 static const struct i2c_device_id pcf8583_id[] = {
@@ -306,7 +300,6 @@ static struct i2c_driver pcf8583_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = pcf8583_probe,
-       .remove         = pcf8583_remove,
        .id_table       = pcf8583_id,
 };
 
index f1a6557261f39c36a0dda30e68e5bd143e2a06e6..03f8f75d5af2267ae89c99e843d17ca0f60ff062 100644 (file)
@@ -395,7 +395,7 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
        if (pdata != NULL)
                rtc_write_enable = pdata->rtc_write_enable;
 
-       rtc_dd = kzalloc(sizeof(*rtc_dd), GFP_KERNEL);
+       rtc_dd = devm_kzalloc(&pdev->dev, sizeof(*rtc_dd), GFP_KERNEL);
        if (rtc_dd == NULL) {
                dev_err(&pdev->dev, "Unable to allocate memory!\n");
                return -ENOMEM;
@@ -407,16 +407,14 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
        rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
        if (rtc_dd->rtc_alarm_irq < 0) {
                dev_err(&pdev->dev, "Alarm IRQ resource absent!\n");
-               rc = -ENXIO;
-               goto fail_rtc_enable;
+               return -ENXIO;
        }
 
        rtc_resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
                                                        "pmic_rtc_base");
        if (!(rtc_resource && rtc_resource->start)) {
                dev_err(&pdev->dev, "RTC IO resource absent!\n");
-               rc = -ENXIO;
-               goto fail_rtc_enable;
+               return -ENXIO;
        }
 
        rtc_dd->rtc_base = rtc_resource->start;
@@ -432,7 +430,7 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
        rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1);
        if (rc < 0) {
                dev_err(&pdev->dev, "RTC control register read failed!\n");
-               goto fail_rtc_enable;
+               return rc;
        }
 
        if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {
@@ -442,7 +440,7 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
                if (rc < 0) {
                        dev_err(&pdev->dev, "Write to RTC control register "
                                                                "failed\n");
-                       goto fail_rtc_enable;
+                       return rc;
                }
        }
 
@@ -453,13 +451,12 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, rtc_dd);
 
        /* Register the RTC device */
-       rtc_dd->rtc = rtc_device_register("pm8xxx_rtc", &pdev->dev,
+       rtc_dd->rtc = devm_rtc_device_register(&pdev->dev, "pm8xxx_rtc",
                                &pm8xxx_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc_dd->rtc)) {
                dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n",
                                        __func__, PTR_ERR(rtc_dd->rtc));
-               rc = PTR_ERR(rtc_dd->rtc);
-               goto fail_rtc_enable;
+               return PTR_ERR(rtc_dd->rtc);
        }
 
        /* Request the alarm IRQ */
@@ -468,7 +465,7 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
                                 "pm8xxx_rtc_alarm", rtc_dd);
        if (rc < 0) {
                dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc);
-               goto fail_req_irq;
+               return rc;
        }
 
        device_init_wakeup(&pdev->dev, 1);
@@ -476,13 +473,6 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
        dev_dbg(&pdev->dev, "Probe success !!\n");
 
        return 0;
-
-fail_req_irq:
-       rtc_device_unregister(rtc_dd->rtc);
-fail_rtc_enable:
-       platform_set_drvdata(pdev, NULL);
-       kfree(rtc_dd);
-       return rc;
 }
 
 static int pm8xxx_rtc_remove(struct platform_device *pdev)
@@ -491,9 +481,6 @@ static int pm8xxx_rtc_remove(struct platform_device *pdev)
 
        device_init_wakeup(&pdev->dev, 0);
        free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
-       rtc_device_unregister(rtc_dd->rtc);
-       platform_set_drvdata(pdev, NULL);
-       kfree(rtc_dd);
 
        return 0;
 }
index 4bb825bb5804d73823d9142c6b829a5bcd968820..554ada5e9b76141769ac041c3b8d56b79b3a26fc 100644 (file)
@@ -71,17 +71,11 @@ static int __init ps3_rtc_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __exit ps3_rtc_remove(struct platform_device *dev)
-{
-       return 0;
-}
-
 static struct platform_driver ps3_rtc_driver = {
        .driver = {
                .name = "rtc-ps3",
                .owner = THIS_MODULE,
        },
-       .remove = __exit_p(ps3_rtc_remove),
 };
 
 module_platform_driver_probe(ps3_rtc_driver, ps3_rtc_probe);
index 72f437170d2ebabae7c2a4d2659854b9c25bb5d8..402732cfb32a5574f6fda08f5637ba04a6d1fb0d 100644 (file)
@@ -224,7 +224,6 @@ static int puv3_rtc_remove(struct platform_device *dev)
 {
        struct rtc_device *rtc = platform_get_drvdata(dev);
 
-       platform_set_drvdata(dev, NULL);
        rtc_device_unregister(rtc);
 
        puv3_rtc_setpie(&dev->dev, 0);
index ed037ae91c5fcddf2fb21b644da0bb91a79c0402..a355f2b82bb8f24e6fb27346890b92bd0e02d584 100644 (file)
@@ -324,37 +324,35 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
        int ret;
        u32 rttr;
 
-       pxa_rtc = kzalloc(sizeof(struct pxa_rtc), GFP_KERNEL);
+       pxa_rtc = devm_kzalloc(dev, sizeof(*pxa_rtc), GFP_KERNEL);
        if (!pxa_rtc)
                return -ENOMEM;
 
        spin_lock_init(&pxa_rtc->lock);
        platform_set_drvdata(pdev, pxa_rtc);
 
-       ret = -ENXIO;
        pxa_rtc->ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!pxa_rtc->ress) {
                dev_err(dev, "No I/O memory resource defined\n");
-               goto err_ress;
+               return -ENXIO;
        }
 
        pxa_rtc->irq_1Hz = platform_get_irq(pdev, 0);
        if (pxa_rtc->irq_1Hz < 0) {
                dev_err(dev, "No 1Hz IRQ resource defined\n");
-               goto err_ress;
+               return -ENXIO;
        }
        pxa_rtc->irq_Alrm = platform_get_irq(pdev, 1);
        if (pxa_rtc->irq_Alrm < 0) {
                dev_err(dev, "No alarm IRQ resource defined\n");
-               goto err_ress;
+               return -ENXIO;
        }
        pxa_rtc_open(dev);
-       ret = -ENOMEM;
-       pxa_rtc->base = ioremap(pxa_rtc->ress->start,
+       pxa_rtc->base = devm_ioremap(dev, pxa_rtc->ress->start,
                                resource_size(pxa_rtc->ress));
        if (!pxa_rtc->base) {
-               dev_err(&pdev->dev, "Unable to map pxa RTC I/O memory\n");
-               goto err_map;
+               dev_err(dev, "Unable to map pxa RTC I/O memory\n");
+               return -ENOMEM;
        }
 
        /*
@@ -370,41 +368,24 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
 
        rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE);
 
-       pxa_rtc->rtc = rtc_device_register("pxa-rtc", &pdev->dev, &pxa_rtc_ops,
-                                          THIS_MODULE);
-       ret = PTR_ERR(pxa_rtc->rtc);
+       pxa_rtc->rtc = devm_rtc_device_register(&pdev->dev, "pxa-rtc",
+                                               &pxa_rtc_ops, THIS_MODULE);
        if (IS_ERR(pxa_rtc->rtc)) {
+               ret = PTR_ERR(pxa_rtc->rtc);
                dev_err(dev, "Failed to register RTC device -> %d\n", ret);
-               goto err_rtc_reg;
+               return ret;
        }
 
        device_init_wakeup(dev, 1);
 
        return 0;
-
-err_rtc_reg:
-        iounmap(pxa_rtc->base);
-err_ress:
-err_map:
-       kfree(pxa_rtc);
-       return ret;
 }
 
 static int __exit pxa_rtc_remove(struct platform_device *pdev)
 {
-       struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev);
-
        struct device *dev = &pdev->dev;
-       pxa_rtc_release(dev);
-
-       rtc_device_unregister(pxa_rtc->rtc);
-
-       spin_lock_irq(&pxa_rtc->lock);
-       iounmap(pxa_rtc->base);
-       spin_unlock_irq(&pxa_rtc->lock);
-
-       kfree(pxa_rtc);
 
+       pxa_rtc_release(dev);
        return 0;
 }
 
index 8eabcf51b35a05f21f0f43abe9bd563e7f5b5588..e53e9b1c69b3a315df0252dc0bba6665a1ffa6c6 100644 (file)
@@ -273,7 +273,7 @@ static int rc5t583_rtc_probe(struct platform_device *pdev)
  */
 static int rc5t583_rtc_remove(struct platform_device *pdev)
 {
-       struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(&pdev->dev);
+       struct rc5t583_rtc *rc5t583_rtc = platform_get_drvdata(pdev);
 
        rc5t583_rtc_alarm_irq_enable(&rc5t583_rtc->rtc->dev, 0);
        return 0;
index 873c689f01c36e6f09e7482691d25cfe333d2883..89d073679267eea3b33827b5338e54bdda1656c3 100644 (file)
@@ -251,21 +251,15 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev)
 
        rtc = devm_rtc_device_register(&dev->dev, "rtc-rp5c01", &rp5c01_rtc_ops,
                                  THIS_MODULE);
-       if (IS_ERR(rtc)) {
-               error = PTR_ERR(rtc);
-               goto out;
-       }
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
        priv->rtc = rtc;
 
        error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr);
        if (error)
-               goto out;
+               return error;
 
        return 0;
-
-out:
-       platform_set_drvdata(dev, NULL);
-       return error;
 }
 
 static int __exit rp5c01_rtc_remove(struct platform_device *dev)
index 8089fc63e403c11601994b79ca3b97566f4dcc25..68f7856422f16c8c0858268f7bf7f31160d455db 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/bcd.h>
 #include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
 #define DRV_NAME       "rs5c313"
-#define DRV_VERSION    "1.13"
+#define DRV_VERSION    "1.13"
 
 #ifdef CONFIG_SH_LANDISK
 /*****************************************************/
@@ -301,7 +301,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
        rs5c313_write_reg(RS5C313_ADDR_SEC10, (data >> 4));
 
        data = bin2bcd(tm->tm_min);
-       rs5c313_write_reg(RS5C313_ADDR_MIN, data );
+       rs5c313_write_reg(RS5C313_ADDR_MIN, data);
        rs5c313_write_reg(RS5C313_ADDR_MIN10, (data >> 4));
 
        data = bin2bcd(tm->tm_hour);
@@ -310,7 +310,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
 
        data = bin2bcd(tm->tm_mday);
        rs5c313_write_reg(RS5C313_ADDR_DAY, data);
-       rs5c313_write_reg(RS5C313_ADDR_DAY10, (data>> 4));
+       rs5c313_write_reg(RS5C313_ADDR_DAY10, (data >> 4));
 
        data = bin2bcd(tm->tm_mon + 1);
        rs5c313_write_reg(RS5C313_ADDR_MON, data);
@@ -349,9 +349,9 @@ static void rs5c313_check_xstp_bit(void)
                }
 
                memset(&tm, 0, sizeof(struct rtc_time));
-               tm.tm_mday      = 1;
-               tm.tm_mon       = 1 - 1;
-               tm.tm_year      = 2000 - 1900;
+               tm.tm_mday      = 1;
+               tm.tm_mon       = 1 - 1;
+               tm.tm_year      = 2000 - 1900;
 
                rs5c313_rtc_set_time(NULL, &tm);
                pr_err("invalid value, resetting to 1 Jan 2000\n");
@@ -378,18 +378,12 @@ static int rs5c313_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int rs5c313_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static struct platform_driver rs5c313_rtc_platform_driver = {
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
        },
-       .probe  = rs5c313_rtc_probe,
-       .remove = rs5c313_rtc_remove,
+       .probe  = rs5c313_rtc_probe,
 };
 
 static int __init rs5c313_rtc_init(void)
@@ -408,7 +402,7 @@ static int __init rs5c313_rtc_init(void)
 
 static void __exit rs5c313_rtc_exit(void)
 {
-       platform_driver_unregister( &rs5c313_rtc_platform_driver );
+       platform_driver_unregister(&rs5c313_rtc_platform_driver);
 }
 
 module_init(rs5c313_rtc_init);
index 2c37df3586c745bb2396f43a340f6e6937532804..f7a90a116a39bcc0dda39a8c31ec866a0dde29fb 100644 (file)
@@ -218,18 +218,12 @@ static int rs5c348_probe(struct spi_device *spi)
        return ret;
 }
 
-static int rs5c348_remove(struct spi_device *spi)
-{
-       return 0;
-}
-
 static struct spi_driver rs5c348_driver = {
        .driver = {
                .name   = "rtc-rs5c348",
                .owner  = THIS_MODULE,
        },
        .probe  = rs5c348_probe,
-       .remove = rs5c348_remove,
 };
 
 module_spi_driver(rs5c348_driver);
index 5032c24ec15938d2341927960de9e52a077b9773..1a779a67ff6683567ff9d8dbc40fc7f92ef9767f 100644 (file)
@@ -310,7 +310,7 @@ static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client,
                dev_dbg(&client->dev, "alarm IRQ armed\n");
        } else {
                /* disable AIE irq */
-               ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1);
+               ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 0);
                if (ret)
                        return ret;
 
@@ -412,17 +412,11 @@ static int rv3029c2_probe(struct i2c_client *client,
        return 0;
 }
 
-static int rv3029c2_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static struct i2c_driver rv3029c2_driver = {
        .driver = {
                .name = "rtc-rv3029c2",
        },
        .probe = rv3029c2_probe,
-       .remove = rv3029c2_remove,
        .id_table = rv3029c2_id,
 };
 
index 84eb08d65d3053ee200bfec8d6736d1456518d5b..6889222f9ed64e8f991047aca26dfdcc30fd2d73 100644 (file)
@@ -282,11 +282,6 @@ static int rx4581_probe(struct spi_device *spi)
        return 0;
 }
 
-static int rx4581_remove(struct spi_device *spi)
-{
-       return 0;
-}
-
 static const struct spi_device_id rx4581_id[] = {
        { "rx4581", 0 },
        { }
@@ -299,7 +294,6 @@ static struct spi_driver rx4581_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = rx4581_probe,
-       .remove = rx4581_remove,
        .id_table = rx4581_id,
 };
 
index 0722d36b9c9adcdb5e112105baa0eb77a95c1ac7..8fa23eabcb68109d6636b44405cfaf9965aa6be6 100644 (file)
@@ -549,7 +549,7 @@ static int rx8025_probe(struct i2c_client *client,
                goto errout;
        }
 
-       rx8025 = kzalloc(sizeof(*rx8025), GFP_KERNEL);
+       rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL);
        if (!rx8025) {
                dev_err(&adapter->dev, "failed to alloc memory\n");
                err = -ENOMEM;
@@ -562,7 +562,7 @@ static int rx8025_probe(struct i2c_client *client,
 
        err = rx8025_init_client(client, &need_reset);
        if (err)
-               goto errout_free;
+               goto errout;
 
        if (need_reset) {
                struct rtc_time tm;
@@ -572,12 +572,12 @@ static int rx8025_probe(struct i2c_client *client,
                rx8025_set_time(&client->dev, &tm);
        }
 
-       rx8025->rtc = rtc_device_register(client->name, &client->dev,
+       rx8025->rtc = devm_rtc_device_register(&client->dev, client->name,
                                          &rx8025_rtc_ops, THIS_MODULE);
        if (IS_ERR(rx8025->rtc)) {
                err = PTR_ERR(rx8025->rtc);
                dev_err(&client->dev, "unable to register the class device\n");
-               goto errout_free;
+               goto errout;
        }
 
        if (client->irq > 0) {
@@ -586,7 +586,7 @@ static int rx8025_probe(struct i2c_client *client,
                                  0, "rx8025", client);
                if (err) {
                        dev_err(&client->dev, "unable to request IRQ\n");
-                       goto errout_reg;
+                       goto errout;
                }
        }
 
@@ -603,12 +603,6 @@ errout_irq:
        if (client->irq > 0)
                free_irq(client->irq, client);
 
-errout_reg:
-       rtc_device_unregister(rx8025->rtc);
-
-errout_free:
-       kfree(rx8025);
-
 errout:
        dev_err(&adapter->dev, "probing for rx8025 failed\n");
        return err;
@@ -629,8 +623,6 @@ static int rx8025_remove(struct i2c_client *client)
        }
 
        rx8025_sysfs_unregister(&client->dev);
-       rtc_device_unregister(rx8025->rtc);
-       kfree(rx8025);
        return 0;
 }
 
index 07f3037b18f4c640b69f67abdf8f5360d72fe403..00b0eb7fe166ec29ada4eb2f0020c0fcf00fb254 100644 (file)
@@ -251,11 +251,6 @@ static int rx8581_probe(struct i2c_client *client,
        return 0;
 }
 
-static int rx8581_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static const struct i2c_device_id rx8581_id[] = {
        { "rx8581", 0 },
        { }
@@ -268,7 +263,6 @@ static struct i2c_driver rx8581_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = rx8581_probe,
-       .remove         = rx8581_remove,
        .id_table       = rx8581_id,
 };
 
index 0b495e8b8e66958d0781086264b7c8653b3d0eed..7afd373b9595ff68b16238fc37688102dbaa04f4 100644 (file)
@@ -421,8 +421,6 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
 
 static int s3c_rtc_remove(struct platform_device *dev)
 {
-       platform_set_drvdata(dev, NULL);
-
        s3c_rtc_setaie(&dev->dev, 0);
 
        clk_unprepare(rtc_clk);
@@ -549,23 +547,20 @@ static int s3c_rtc_probe(struct platform_device *pdev)
                          0,  "s3c2410-rtc alarm", rtc);
        if (ret) {
                dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
-               goto err_alarm_irq;
+               goto err_nortc;
        }
 
        ret = devm_request_irq(&pdev->dev, s3c_rtc_tickno, s3c_rtc_tickirq,
                          0,  "s3c2410-rtc tick", rtc);
        if (ret) {
                dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
-               goto err_alarm_irq;
+               goto err_nortc;
        }
 
        clk_disable(rtc_clk);
 
        return 0;
 
- err_alarm_irq:
-       platform_set_drvdata(pdev, NULL);
-
  err_nortc:
        s3c_rtc_enable(pdev, 0);
        clk_disable_unprepare(rtc_clk);
index 00605601dbf7eb53d874973eb11a6031b1273e58..0f7adeb1944a8f1acd93cae653a4af6c709380b9 100644 (file)
@@ -249,7 +249,7 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
 
        ret = clk_prepare_enable(info->clk);
        if (ret)
-               goto err_enable_clk;
+               return ret;
        /*
         * According to the manual we should be able to let RTTR be zero
         * and then a default diviser for a 32.768KHz clock is used.
@@ -303,8 +303,6 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
        return 0;
 err_dev:
        clk_disable_unprepare(info->clk);
-err_enable_clk:
-       platform_set_drvdata(pdev, NULL);
        return ret;
 }
 
@@ -312,10 +310,8 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
 {
        struct sa1100_rtc *info = platform_get_drvdata(pdev);
 
-       if (info) {
+       if (info)
                clk_disable_unprepare(info->clk);
-               platform_set_drvdata(pdev, NULL);
-       }
 
        return 0;
 }
index 8d5bd2e367765e55fadedd78c86df0bbfee62d29..6d87e26355a3020b25a4242f7459c1e0cb98244b 100644 (file)
@@ -593,7 +593,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
        char clk_name[6];
        int clk_id, ret;
 
-       rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL);
+       rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
        if (unlikely(!rtc))
                return -ENOMEM;
 
@@ -602,9 +602,8 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
        /* get periodic/carry/alarm irqs */
        ret = platform_get_irq(pdev, 0);
        if (unlikely(ret <= 0)) {
-               ret = -ENOENT;
                dev_err(&pdev->dev, "No IRQ resource\n");
-               goto err_badres;
+               return -ENOENT;
        }
 
        rtc->periodic_irq = ret;
@@ -613,24 +612,21 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (unlikely(res == NULL)) {
-               ret = -ENOENT;
                dev_err(&pdev->dev, "No IO resource\n");
-               goto err_badres;
+               return -ENOENT;
        }
 
        rtc->regsize = resource_size(res);
 
-       rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name);
-       if (unlikely(!rtc->res)) {
-               ret = -EBUSY;
-               goto err_badres;
-       }
+       rtc->res = devm_request_mem_region(&pdev->dev, res->start,
+                                       rtc->regsize, pdev->name);
+       if (unlikely(!rtc->res))
+               return -EBUSY;
 
-       rtc->regbase = ioremap_nocache(rtc->res->start, rtc->regsize);
-       if (unlikely(!rtc->regbase)) {
-               ret = -EINVAL;
-               goto err_badmap;
-       }
+       rtc->regbase = devm_ioremap_nocache(&pdev->dev, rtc->res->start,
+                                       rtc->regsize);
+       if (unlikely(!rtc->regbase))
+               return -EINVAL;
 
        clk_id = pdev->id;
        /* With a single device, the clock id is still "rtc0" */
@@ -639,7 +635,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
 
        snprintf(clk_name, sizeof(clk_name), "rtc%d", clk_id);
 
-       rtc->clk = clk_get(&pdev->dev, clk_name);
+       rtc->clk = devm_clk_get(&pdev->dev, clk_name);
        if (IS_ERR(rtc->clk)) {
                /*
                 * No error handling for rtc->clk intentionally, not all
@@ -665,8 +661,8 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
 
        if (rtc->carry_irq <= 0) {
                /* register shared periodic/carry/alarm irq */
-               ret = request_irq(rtc->periodic_irq, sh_rtc_shared,
-                                 0, "sh-rtc", rtc);
+               ret = devm_request_irq(&pdev->dev, rtc->periodic_irq,
+                               sh_rtc_shared, 0, "sh-rtc", rtc);
                if (unlikely(ret)) {
                        dev_err(&pdev->dev,
                                "request IRQ failed with %d, IRQ %d\n", ret,
@@ -675,8 +671,8 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
                }
        } else {
                /* register periodic/carry/alarm irqs */
-               ret = request_irq(rtc->periodic_irq, sh_rtc_periodic,
-                                 0, "sh-rtc period", rtc);
+               ret = devm_request_irq(&pdev->dev, rtc->periodic_irq,
+                               sh_rtc_periodic, 0, "sh-rtc period", rtc);
                if (unlikely(ret)) {
                        dev_err(&pdev->dev,
                                "request period IRQ failed with %d, IRQ %d\n",
@@ -684,24 +680,21 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
                        goto err_unmap;
                }
 
-               ret = request_irq(rtc->carry_irq, sh_rtc_interrupt,
-                                 0, "sh-rtc carry", rtc);
+               ret = devm_request_irq(&pdev->dev, rtc->carry_irq,
+                               sh_rtc_interrupt, 0, "sh-rtc carry", rtc);
                if (unlikely(ret)) {
                        dev_err(&pdev->dev,
                                "request carry IRQ failed with %d, IRQ %d\n",
                                ret, rtc->carry_irq);
-                       free_irq(rtc->periodic_irq, rtc);
                        goto err_unmap;
                }
 
-               ret = request_irq(rtc->alarm_irq, sh_rtc_alarm,
-                                 0, "sh-rtc alarm", rtc);
+               ret = devm_request_irq(&pdev->dev, rtc->alarm_irq,
+                               sh_rtc_alarm, 0, "sh-rtc alarm", rtc);
                if (unlikely(ret)) {
                        dev_err(&pdev->dev,
                                "request alarm IRQ failed with %d, IRQ %d\n",
                                ret, rtc->alarm_irq);
-                       free_irq(rtc->carry_irq, rtc);
-                       free_irq(rtc->periodic_irq, rtc);
                        goto err_unmap;
                }
        }
@@ -714,13 +707,10 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
        sh_rtc_setaie(&pdev->dev, 0);
        sh_rtc_setcie(&pdev->dev, 0);
 
-       rtc->rtc_dev = rtc_device_register("sh", &pdev->dev,
+       rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, "sh",
                                           &sh_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc->rtc_dev)) {
                ret = PTR_ERR(rtc->rtc_dev);
-               free_irq(rtc->periodic_irq, rtc);
-               free_irq(rtc->carry_irq, rtc);
-               free_irq(rtc->alarm_irq, rtc);
                goto err_unmap;
        }
 
@@ -737,12 +727,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
 
 err_unmap:
        clk_disable(rtc->clk);
-       clk_put(rtc->clk);
-       iounmap(rtc->regbase);
-err_badmap:
-       release_mem_region(rtc->res->start, rtc->regsize);
-err_badres:
-       kfree(rtc);
 
        return ret;
 }
@@ -751,28 +735,12 @@ static int __exit sh_rtc_remove(struct platform_device *pdev)
 {
        struct sh_rtc *rtc = platform_get_drvdata(pdev);
 
-       rtc_device_unregister(rtc->rtc_dev);
        sh_rtc_irq_set_state(&pdev->dev, 0);
 
        sh_rtc_setaie(&pdev->dev, 0);
        sh_rtc_setcie(&pdev->dev, 0);
 
-       free_irq(rtc->periodic_irq, rtc);
-
-       if (rtc->carry_irq > 0) {
-               free_irq(rtc->carry_irq, rtc);
-               free_irq(rtc->alarm_irq, rtc);
-       }
-
-       iounmap(rtc->regbase);
-       release_mem_region(rtc->res->start, rtc->regsize);
-
        clk_disable(rtc->clk);
-       clk_put(rtc->clk);
-
-       platform_set_drvdata(pdev, NULL);
-
-       kfree(rtc);
 
        return 0;
 }
diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c
new file mode 100644 (file)
index 0000000..aa7ed4b
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * SiRFSoC Real Time Clock interface for Linux
+ *
+ * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/rtc/sirfsoc_rtciobrg.h>
+
+
+#define RTC_CN                 0x00
+#define RTC_ALARM0             0x04
+#define RTC_ALARM1             0x18
+#define RTC_STATUS             0x08
+#define RTC_SW_VALUE            0x40
+#define SIRFSOC_RTC_AL1E       (1<<6)
+#define SIRFSOC_RTC_AL1                (1<<4)
+#define SIRFSOC_RTC_HZE                (1<<3)
+#define SIRFSOC_RTC_AL0E       (1<<2)
+#define SIRFSOC_RTC_HZ         (1<<1)
+#define SIRFSOC_RTC_AL0                (1<<0)
+#define RTC_DIV                        0x0c
+#define RTC_DEEP_CTRL          0x14
+#define RTC_CLOCK_SWITCH       0x1c
+#define SIRFSOC_RTC_CLK                0x03    /* others are reserved */
+
+/* Refer to RTC DIV switch */
+#define RTC_HZ                 16
+
+/* This macro is also defined in arch/arm/plat-sirfsoc/cpu.c */
+#define RTC_SHIFT              4
+
+#define INTR_SYSRTC_CN         0x48
+
+struct sirfsoc_rtc_drv {
+       struct rtc_device       *rtc;
+       u32                     rtc_base;
+       u32                     irq;
+       /* Overflow for every 8 years extra time */
+       u32                     overflow_rtc;
+#ifdef CONFIG_PM
+       u32             saved_counter;
+       u32             saved_overflow_rtc;
+#endif
+};
+
+static int sirfsoc_rtc_read_alarm(struct device *dev,
+               struct rtc_wkalrm *alrm)
+{
+       unsigned long rtc_alarm, rtc_count;
+       struct sirfsoc_rtc_drv *rtcdrv;
+
+       rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev);
+
+       local_irq_disable();
+
+       rtc_count = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
+
+       rtc_alarm = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_ALARM0);
+       memset(alrm, 0, sizeof(struct rtc_wkalrm));
+
+       /*
+        * assume alarm interval not beyond one round counter overflow_rtc:
+        * 0->0xffffffff
+        */
+       /* if alarm is in next overflow cycle */
+       if (rtc_count > rtc_alarm)
+               rtc_time_to_tm((rtcdrv->overflow_rtc + 1)
+                               << (BITS_PER_LONG - RTC_SHIFT)
+                               | rtc_alarm >> RTC_SHIFT, &(alrm->time));
+       else
+               rtc_time_to_tm(rtcdrv->overflow_rtc
+                               << (BITS_PER_LONG - RTC_SHIFT)
+                               | rtc_alarm >> RTC_SHIFT, &(alrm->time));
+       if (sirfsoc_rtc_iobrg_readl(
+                       rtcdrv->rtc_base + RTC_STATUS) & SIRFSOC_RTC_AL0E)
+               alrm->enabled = 1;
+       local_irq_enable();
+
+       return 0;
+}
+
+static int sirfsoc_rtc_set_alarm(struct device *dev,
+               struct rtc_wkalrm *alrm)
+{
+       unsigned long rtc_status_reg, rtc_alarm;
+       struct sirfsoc_rtc_drv *rtcdrv;
+       rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev);
+
+       if (alrm->enabled) {
+               rtc_tm_to_time(&(alrm->time), &rtc_alarm);
+
+               local_irq_disable();
+
+               rtc_status_reg = sirfsoc_rtc_iobrg_readl(
+                               rtcdrv->rtc_base + RTC_STATUS);
+               if (rtc_status_reg & SIRFSOC_RTC_AL0E) {
+                       /*
+                        * An ongoing alarm in progress - ingore it and not
+                        * to return EBUSY
+                        */
+                       dev_info(dev, "An old alarm was set, will be replaced by a new one\n");
+               }
+
+               sirfsoc_rtc_iobrg_writel(
+                       rtc_alarm << RTC_SHIFT, rtcdrv->rtc_base + RTC_ALARM0);
+               rtc_status_reg &= ~0x07; /* mask out the lower status bits */
+               /*
+                * This bit RTC_AL sets it as a wake-up source for Sleep Mode
+                * Writing 1 into this bit will clear it
+                */
+               rtc_status_reg |= SIRFSOC_RTC_AL0;
+               /* enable the RTC alarm interrupt */
+               rtc_status_reg |= SIRFSOC_RTC_AL0E;
+               sirfsoc_rtc_iobrg_writel(
+                       rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
+               local_irq_enable();
+       } else {
+               /*
+                * if this function was called with enabled=0
+                * then it could mean that the application is
+                * trying to cancel an ongoing alarm
+                */
+               local_irq_disable();
+
+               rtc_status_reg = sirfsoc_rtc_iobrg_readl(
+                               rtcdrv->rtc_base + RTC_STATUS);
+               if (rtc_status_reg & SIRFSOC_RTC_AL0E) {
+                       /* clear the RTC status register's alarm bit */
+                       rtc_status_reg &= ~0x07;
+                       /* write 1 into SIRFSOC_RTC_AL0 to force a clear */
+                       rtc_status_reg |= (SIRFSOC_RTC_AL0);
+                       /* Clear the Alarm enable bit */
+                       rtc_status_reg &= ~(SIRFSOC_RTC_AL0E);
+
+                       sirfsoc_rtc_iobrg_writel(rtc_status_reg,
+                                       rtcdrv->rtc_base + RTC_STATUS);
+               }
+
+               local_irq_enable();
+       }
+
+       return 0;
+}
+
+static int sirfsoc_rtc_read_time(struct device *dev,
+               struct rtc_time *tm)
+{
+       unsigned long tmp_rtc = 0;
+       struct sirfsoc_rtc_drv *rtcdrv;
+       rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev);
+       /*
+        * This patch is taken from WinCE - Need to validate this for
+        * correctness. To work around sirfsoc RTC counter double sync logic
+        * fail, read several times to make sure get stable value.
+        */
+       do {
+               tmp_rtc = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
+               cpu_relax();
+       } while (tmp_rtc != sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN));
+
+       rtc_time_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) |
+                                       tmp_rtc >> RTC_SHIFT, tm);
+       return 0;
+}
+
+static int sirfsoc_rtc_set_time(struct device *dev,
+               struct rtc_time *tm)
+{
+       unsigned long rtc_time;
+       struct sirfsoc_rtc_drv *rtcdrv;
+       rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev);
+
+       rtc_tm_to_time(tm, &rtc_time);
+
+       rtcdrv->overflow_rtc = rtc_time >> (BITS_PER_LONG - RTC_SHIFT);
+
+       sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc,
+                       rtcdrv->rtc_base + RTC_SW_VALUE);
+       sirfsoc_rtc_iobrg_writel(
+                       rtc_time << RTC_SHIFT, rtcdrv->rtc_base + RTC_CN);
+
+       return 0;
+}
+
+static int sirfsoc_rtc_ioctl(struct device *dev, unsigned int cmd,
+               unsigned long arg)
+{
+       switch (cmd) {
+       case RTC_PIE_ON:
+       case RTC_PIE_OFF:
+       case RTC_UIE_ON:
+       case RTC_UIE_OFF:
+       case RTC_AIE_ON:
+       case RTC_AIE_OFF:
+               return 0;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static const struct rtc_class_ops sirfsoc_rtc_ops = {
+       .read_time = sirfsoc_rtc_read_time,
+       .set_time = sirfsoc_rtc_set_time,
+       .read_alarm = sirfsoc_rtc_read_alarm,
+       .set_alarm = sirfsoc_rtc_set_alarm,
+       .ioctl = sirfsoc_rtc_ioctl
+};
+
+static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata)
+{
+       struct sirfsoc_rtc_drv *rtcdrv = pdata;
+       unsigned long rtc_status_reg = 0x0;
+       unsigned long events = 0x0;
+
+       rtc_status_reg = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_STATUS);
+       /* this bit will be set ONLY if an alarm was active
+        * and it expired NOW
+        * So this is being used as an ASSERT
+        */
+       if (rtc_status_reg & SIRFSOC_RTC_AL0) {
+               /*
+                * clear the RTC status register's alarm bit
+                * mask out the lower status bits
+                */
+               rtc_status_reg &= ~0x07;
+               /* write 1 into SIRFSOC_RTC_AL0 to ACK the alarm interrupt */
+               rtc_status_reg |= (SIRFSOC_RTC_AL0);
+               /* Clear the Alarm enable bit */
+               rtc_status_reg &= ~(SIRFSOC_RTC_AL0E);
+       }
+       sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
+       /* this should wake up any apps polling/waiting on the read
+        * after setting the alarm
+        */
+       events |= RTC_IRQF | RTC_AF;
+       rtc_update_irq(rtcdrv->rtc, 1, events);
+
+       return IRQ_HANDLED;
+}
+
+static const struct of_device_id sirfsoc_rtc_of_match[] = {
+       { .compatible = "sirf,prima2-sysrtc"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, sirfsoc_rtc_of_match);
+
+static int sirfsoc_rtc_probe(struct platform_device *pdev)
+{
+       int err;
+       unsigned long rtc_div;
+       struct sirfsoc_rtc_drv *rtcdrv;
+       struct device_node *np = pdev->dev.of_node;
+
+       rtcdrv = devm_kzalloc(&pdev->dev,
+               sizeof(struct sirfsoc_rtc_drv), GFP_KERNEL);
+       if (rtcdrv == NULL) {
+               dev_err(&pdev->dev,
+                       "%s: can't alloc mem for drv struct\n",
+                       pdev->name);
+               return -ENOMEM;
+       }
+
+       err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base);
+       if (err) {
+               dev_err(&pdev->dev, "unable to find base address of rtc node in dtb\n");
+               goto error;
+       }
+
+       platform_set_drvdata(pdev, rtcdrv);
+
+       /* Register rtc alarm as a wakeup source */
+       device_init_wakeup(&pdev->dev, 1);
+
+       /*
+        * Set SYS_RTC counter in RTC_HZ HZ Units
+        * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1
+        * If 16HZ, therefore RTC_DIV = 1023;
+        */
+       rtc_div = ((32768 / RTC_HZ) / 2) - 1;
+       sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV);
+
+       rtcdrv->rtc = rtc_device_register(pdev->name, &(pdev->dev),
+                       &sirfsoc_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtcdrv->rtc)) {
+               err = PTR_ERR(rtcdrv->rtc);
+               dev_err(&pdev->dev, "can't register RTC device\n");
+               return err;
+       }
+
+       /* 0x3 -> RTC_CLK */
+       sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK,
+                       rtcdrv->rtc_base + RTC_CLOCK_SWITCH);
+
+       /* reset SYS RTC ALARM0 */
+       sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM0);
+
+       /* reset SYS RTC ALARM1 */
+       sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM1);
+
+       /* Restore RTC Overflow From Register After Command Reboot */
+       rtcdrv->overflow_rtc =
+               sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
+
+       rtcdrv->irq = platform_get_irq(pdev, 0);
+       err = devm_request_irq(
+                       &pdev->dev,
+                       rtcdrv->irq,
+                       sirfsoc_rtc_irq_handler,
+                       IRQF_SHARED,
+                       pdev->name,
+                       rtcdrv);
+       if (err) {
+               dev_err(&pdev->dev, "Unable to register for the SiRF SOC RTC IRQ\n");
+               goto error;
+       }
+
+       return 0;
+
+error:
+       if (rtcdrv->rtc)
+               rtc_device_unregister(rtcdrv->rtc);
+
+       return err;
+}
+
+static int sirfsoc_rtc_remove(struct platform_device *pdev)
+{
+       struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
+
+       device_init_wakeup(&pdev->dev, 0);
+       rtc_device_unregister(rtcdrv->rtc);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int sirfsoc_rtc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
+       rtcdrv->overflow_rtc =
+               sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
+
+       rtcdrv->saved_counter =
+               sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
+       rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc;
+       if (device_may_wakeup(&pdev->dev))
+               enable_irq_wake(rtcdrv->irq);
+
+       return 0;
+}
+
+static int sirfsoc_rtc_freeze(struct device *dev)
+{
+       sirfsoc_rtc_suspend(dev);
+
+       return 0;
+}
+
+static int sirfsoc_rtc_thaw(struct device *dev)
+{
+       u32 tmp;
+       struct sirfsoc_rtc_drv *rtcdrv;
+       rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev);
+
+       /*
+        * if resume from snapshot and the rtc power is losed,
+        * restroe the rtc settings
+        */
+       if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl(
+                       rtcdrv->rtc_base + RTC_CLOCK_SWITCH)) {
+               u32 rtc_div;
+               /* 0x3 -> RTC_CLK */
+               sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK,
+                       rtcdrv->rtc_base + RTC_CLOCK_SWITCH);
+               /*
+                * Set SYS_RTC counter in RTC_HZ HZ Units
+                * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1
+                * If 16HZ, therefore RTC_DIV = 1023;
+                */
+               rtc_div = ((32768 / RTC_HZ) / 2) - 1;
+
+               sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV);
+
+               /* reset SYS RTC ALARM0 */
+               sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM0);
+
+               /* reset SYS RTC ALARM1 */
+               sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM1);
+       }
+       rtcdrv->overflow_rtc = rtcdrv->saved_overflow_rtc;
+
+       /*
+        * if current counter is small than previous,
+        * it means overflow in sleep
+        */
+       tmp = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
+       if (tmp <= rtcdrv->saved_counter)
+               rtcdrv->overflow_rtc++;
+       /*
+        *PWRC Value Be Changed When Suspend, Restore Overflow
+        * In Memory To Register
+        */
+       sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc,
+                       rtcdrv->rtc_base + RTC_SW_VALUE);
+
+       return 0;
+}
+
+static int sirfsoc_rtc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
+       sirfsoc_rtc_thaw(dev);
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(rtcdrv->irq);
+
+       return 0;
+}
+
+static int sirfsoc_rtc_restore(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(rtcdrv->irq);
+       return 0;
+}
+
+#else
+#define sirfsoc_rtc_suspend    NULL
+#define sirfsoc_rtc_resume     NULL
+#define sirfsoc_rtc_freeze     NULL
+#define sirfsoc_rtc_thaw       NULL
+#define sirfsoc_rtc_restore    NULL
+#endif
+
+static const struct dev_pm_ops sirfsoc_rtc_pm_ops = {
+       .suspend = sirfsoc_rtc_suspend,
+       .resume = sirfsoc_rtc_resume,
+       .freeze = sirfsoc_rtc_freeze,
+       .thaw = sirfsoc_rtc_thaw,
+       .restore = sirfsoc_rtc_restore,
+};
+
+static struct platform_driver sirfsoc_rtc_driver = {
+       .driver = {
+               .name = "sirfsoc-rtc",
+               .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm = &sirfsoc_rtc_pm_ops,
+#endif
+               .of_match_table = of_match_ptr(sirfsoc_rtc_of_match),
+       },
+       .probe = sirfsoc_rtc_probe,
+       .remove = sirfsoc_rtc_remove,
+};
+module_platform_driver(sirfsoc_rtc_driver);
+
+MODULE_DESCRIPTION("SiRF SoC rtc driver");
+MODULE_AUTHOR("Xianglong Du <Xianglong.Du@csr.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sirfsoc-rtc");
index b04f09a1df2a75a650b6852abf4beb913397c3a2..316a342115b28440b804c08031ccb1143f17e260 100644 (file)
@@ -294,11 +294,6 @@ static int snvs_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int snvs_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int snvs_rtc_suspend(struct device *dev)
 {
@@ -337,7 +332,6 @@ static struct platform_driver snvs_rtc_driver = {
                .of_match_table = of_match_ptr(snvs_dt_ids),
        },
        .probe          = snvs_rtc_probe,
-       .remove         = snvs_rtc_remove,
 };
 module_platform_driver(snvs_rtc_driver);
 
index 574359c48f65c39c9dce16dbefebaabf68ad4528..c492cf0ab8cd64c113f34754c865768d30007468 100644 (file)
@@ -417,7 +417,6 @@ static int spear_rtc_probe(struct platform_device *pdev)
        return 0;
 
 err_disable_clock:
-       platform_set_drvdata(pdev, NULL);
        clk_disable_unprepare(config->clk);
 
        return status;
index 987b5ec0ae56b76fbfa727a2ece3c120e5bdb58c..f7d8a6db8078d9af88e9cdff08b2175d28b49b41 100644 (file)
@@ -51,17 +51,11 @@ static int __init starfire_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit starfire_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static struct platform_driver starfire_rtc_driver = {
        .driver         = {
                .name   = "rtc-starfire",
                .owner  = THIS_MODULE,
        },
-       .remove         = __exit_p(starfire_rtc_remove),
 };
 
 module_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe);
index 483ce086990b75b9ed979dab5749dd6047b0a75c..90a3e864b8fe0c7d1a2efcf7a7551f1c10683610 100644 (file)
@@ -225,7 +225,6 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev)
 
        writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN,
                        rtc_data->io + STMP3XXX_RTC_CTRL_CLR);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
@@ -274,25 +273,19 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev)
 
        rtc_data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                                &stmp3xxx_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc_data->rtc)) {
-               err = PTR_ERR(rtc_data->rtc);
-               goto out;
-       }
+       if (IS_ERR(rtc_data->rtc))
+               return PTR_ERR(rtc_data->rtc);
 
        err = devm_request_irq(&pdev->dev, rtc_data->irq_alarm,
                        stmp3xxx_rtc_interrupt, 0, "RTC alarm", &pdev->dev);
        if (err) {
                dev_err(&pdev->dev, "Cannot claim IRQ%d\n",
                        rtc_data->irq_alarm);
-               goto out;
+               return err;
        }
 
        stmp3xxx_wdt_register(pdev);
        return 0;
-
-out:
-       platform_set_drvdata(pdev, NULL);
-       return err;
 }
 
 #ifdef CONFIG_PM_SLEEP
index ce42e5fa9e09f6e57f43afda93ab5e39ba74bbd1..bc97ff91341d402339f6ecad70331ae61ec95b34 100644 (file)
@@ -92,17 +92,11 @@ static int __init sun4v_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit sun4v_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static struct platform_driver sun4v_rtc_driver = {
        .driver         = {
                .name   = "rtc-sun4v",
                .owner  = THIS_MODULE,
        },
-       .remove         = __exit_p(sun4v_rtc_remove),
 };
 
 module_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe);
index b70e2bb6364500fb7d02c2dffb6c01575e1771e4..4b26f8672b2df03b5b31d811c6f28a2e4a18ccc2 100644 (file)
@@ -164,6 +164,7 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
 {
        ssize_t retval;
        unsigned long now, alarm;
+       unsigned long push = 0;
        struct rtc_wkalrm alm;
        struct rtc_device *rtc = to_rtc_device(dev);
        char *buf_ptr;
@@ -180,13 +181,17 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
        buf_ptr = (char *)buf;
        if (*buf_ptr == '+') {
                buf_ptr++;
-               adjust = 1;
+               if (*buf_ptr == '=') {
+                       buf_ptr++;
+                       push = 1;
+               } else
+                       adjust = 1;
        }
        alarm = simple_strtoul(buf_ptr, NULL, 0);
        if (adjust) {
                alarm += now;
        }
-       if (alarm > now) {
+       if (alarm > now || push) {
                /* Avoid accidentally clobbering active alarms; we can't
                 * entirely prevent that here, without even the minimal
                 * locking from the /dev/rtcN api.
@@ -194,9 +199,14 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
                retval = rtc_read_alarm(rtc, &alm);
                if (retval < 0)
                        return retval;
-               if (alm.enabled)
-                       return -EBUSY;
-
+               if (alm.enabled) {
+                       if (push) {
+                               rtc_tm_to_time(&alm.time, &push);
+                               alarm += push;
+                       } else
+                               return -EBUSY;
+               } else if (push)
+                       return -EINVAL;
                alm.enabled = 1;
        } else {
                alm.enabled = 0;
index fc3dee95f16618a86ec59d86272947b27882500c..ff9632eb79f203662b4fcfe577c0ee9ddf72bbd8 100644 (file)
@@ -91,23 +91,12 @@ static int tile_rtc_probe(struct platform_device *dev)
        return 0;
 }
 
-/*
- * Device cleanup routine.
- */
-static int tile_rtc_remove(struct platform_device *dev)
-{
-       platform_set_drvdata(dev, NULL);
-
-       return 0;
-}
-
 static struct platform_driver tile_rtc_platform_driver = {
        .driver         = {
                .name   = "rtc-tile",
                .owner  = THIS_MODULE,
        },
        .probe          = tile_rtc_probe,
-       .remove         = tile_rtc_remove,
 };
 
 /*
index 72662eafb938337da346490bf995c740792a35b9..3e400dce2d064b01a18cd7172e779b58485d8a3f 100644 (file)
@@ -298,11 +298,6 @@ static int tps80031_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int tps80031_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int tps80031_rtc_suspend(struct device *dev)
 {
@@ -333,7 +328,6 @@ static struct platform_driver tps80031_rtc_driver = {
                .pm     = &tps80031_pm_ops,
        },
        .probe  = tps80031_rtc_probe,
-       .remove = tps80031_rtc_remove,
 };
 
 module_platform_driver(tps80031_rtc_driver);
index b2eab34f38d96b84e61c1fa0e72b5ad4e90e2897..02faf3c4e0d51d13cd6fd7c55b2de4f09776f08f 100644 (file)
@@ -213,12 +213,24 @@ static int mask_rtc_irq_bit(unsigned char bit)
 
 static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
 {
+       struct platform_device *pdev = to_platform_device(dev);
+       int irq = platform_get_irq(pdev, 0);
+       static bool twl_rtc_wake_enabled;
        int ret;
 
-       if (enabled)
+       if (enabled) {
                ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
-       else
+               if (device_can_wakeup(dev) && !twl_rtc_wake_enabled) {
+                       enable_irq_wake(irq);
+                       twl_rtc_wake_enabled = true;
+               }
+       } else {
                ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+               if (twl_rtc_wake_enabled) {
+                       disable_irq_wake(irq);
+                       twl_rtc_wake_enabled = false;
+               }
+       }
 
        return ret;
 }
@@ -469,6 +481,12 @@ static int twl_rtc_probe(struct platform_device *pdev)
        if (irq <= 0)
                goto out1;
 
+       /* Initialize the register map */
+       if (twl_class_is_4030())
+               rtc_reg_map = (u8 *)twl4030_rtc_reg_map;
+       else
+               rtc_reg_map = (u8 *)twl6030_rtc_reg_map;
+
        ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
        if (ret < 0)
                goto out1;
@@ -556,7 +574,6 @@ static int twl_rtc_remove(struct platform_device *pdev)
        free_irq(irq, rtc);
 
        rtc_device_unregister(rtc);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
@@ -609,22 +626,7 @@ static struct platform_driver twl4030rtc_driver = {
        },
 };
 
-static int __init twl_rtc_init(void)
-{
-       if (twl_class_is_4030())
-               rtc_reg_map = (u8 *) twl4030_rtc_reg_map;
-       else
-               rtc_reg_map = (u8 *) twl6030_rtc_reg_map;
-
-       return platform_driver_register(&twl4030rtc_driver);
-}
-module_init(twl_rtc_init);
-
-static void __exit twl_rtc_exit(void)
-{
-       platform_driver_unregister(&twl4030rtc_driver);
-}
-module_exit(twl_rtc_exit);
+module_platform_driver(twl4030rtc_driver);
 
 MODULE_AUTHOR("Texas Instruments, MontaVista Software");
 MODULE_LICENSE("GPL");
index 6e0cba8f47d5e70f61dc089d8ee127b49c8d8597..d07d8982302054cd18cf34d619c6fb0200df9c21 100644 (file)
@@ -16,7 +16,7 @@
  *                             - Use the generic rtc class
  *
  *  ??-???-2004: Someone at Compulab
- *                     - Initial driver creation.
+ *                     - Initial driver creation.
  *
  */
 #include <linux/platform_device.h>
@@ -278,13 +278,13 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt)
        dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
 
        /* Write all the values to ram... */
-       v3020_set_reg(chip, V3020_SECONDS,      bin2bcd(dt->tm_sec));
-       v3020_set_reg(chip, V3020_MINUTES,      bin2bcd(dt->tm_min));
-       v3020_set_reg(chip, V3020_HOURS,        bin2bcd(dt->tm_hour));
+       v3020_set_reg(chip, V3020_SECONDS,      bin2bcd(dt->tm_sec));
+       v3020_set_reg(chip, V3020_MINUTES,      bin2bcd(dt->tm_min));
+       v3020_set_reg(chip, V3020_HOURS,        bin2bcd(dt->tm_hour));
        v3020_set_reg(chip, V3020_MONTH_DAY,    bin2bcd(dt->tm_mday));
-       v3020_set_reg(chip, V3020_MONTH,     bin2bcd(dt->tm_mon + 1));
-       v3020_set_reg(chip, V3020_WEEK_DAY,     bin2bcd(dt->tm_wday));
-       v3020_set_reg(chip, V3020_YEAR,         bin2bcd(dt->tm_year % 100));
+       v3020_set_reg(chip, V3020_MONTH,        bin2bcd(dt->tm_mon + 1));
+       v3020_set_reg(chip, V3020_WEEK_DAY,     bin2bcd(dt->tm_wday));
+       v3020_set_reg(chip, V3020_YEAR,         bin2bcd(dt->tm_year % 100));
 
        /* ...and set the clock. */
        v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0);
@@ -320,7 +320,7 @@ static int rtc_probe(struct platform_device *pdev)
 
        retval = chip->ops->map_io(chip, pdev, pdata);
        if (retval)
-               goto err_chip;
+               return retval;
 
        /* Make sure the v3020 expects a communication cycle
         * by reading 8 times */
@@ -364,7 +364,7 @@ static int rtc_probe(struct platform_device *pdev)
 
 err_io:
        chip->ops->unmap_io(chip);
-err_chip:
+
        return retval;
 }
 
index f91be04b90508e3ede7791a5257ae251a120da2a..54e104e197e384640c30e18bc8e73dc08b8e2f34 100644 (file)
@@ -103,7 +103,7 @@ static inline unsigned long read_elapsed_second(void)
                second_mid = rtc1_read(ETIMEMREG);
                second_high = rtc1_read(ETIMEHREG);
        } while (first_low != second_low || first_mid != second_mid ||
-                first_high != second_high);
+                first_high != second_high);
 
        return (first_high << 17) | (first_mid << 1) | (first_low >> 15);
 }
@@ -154,7 +154,7 @@ static int vr41xx_rtc_set_time(struct device *dev, struct rtc_time *time)
 
        epoch_sec = mktime(epoch, 1, 1, 0, 0, 0);
        current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
-                            time->tm_hour, time->tm_min, time->tm_sec);
+                            time->tm_hour, time->tm_min, time->tm_sec);
 
        write_elapsed_second(current_sec - epoch_sec);
 
@@ -186,7 +186,7 @@ static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
        struct rtc_time *time = &wkalrm->time;
 
        alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
-                          time->tm_hour, time->tm_min, time->tm_sec);
+                          time->tm_hour, time->tm_min, time->tm_sec);
 
        spin_lock_irq(&rtc_lock);
 
@@ -334,16 +334,18 @@ static int rtc_probe(struct platform_device *pdev)
        }
 
        retval = request_irq(aie_irq, elapsedtime_interrupt, 0,
-                            "elapsed_time", pdev);
+                            "elapsed_time", pdev);
        if (retval < 0)
                goto err_device_unregister;
 
        pie_irq = platform_get_irq(pdev, 1);
-       if (pie_irq <= 0)
+       if (pie_irq <= 0) {
+               retval = -EBUSY;
                goto err_free_irq;
+       }
 
        retval = request_irq(pie_irq, rtclong1_interrupt, 0,
-                            "rtclong1", pdev);
+                            "rtclong1", pdev);
        if (retval < 0)
                goto err_free_irq;
 
@@ -381,8 +383,6 @@ static int rtc_remove(struct platform_device *pdev)
        if (rtc)
                rtc_device_unregister(rtc);
 
-       platform_set_drvdata(pdev, NULL);
-
        free_irq(aie_irq, pdev);
        free_irq(pie_irq, pdev);
        if (rtc1_base)
index d89efee6d29e051d89761c33205434aa39a1e90e..c2d6331fc712c7244a87d33ef1e2d6d3cfa7fdca 100644 (file)
@@ -282,8 +282,6 @@ static int vt8500_rtc_remove(struct platform_device *pdev)
        /* Disable alarm matching */
        writel(0, vt8500_rtc->regbase + VT8500_RTC_IS);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 8d65b94e5a7eb428fccfadf3d3db77f38a22f1ed..75aea4c4d334bbaef61d8325762b223fa8735e8b 100644 (file)
@@ -460,11 +460,6 @@ err:
        return ret;
 }
 
-static int wm831x_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static const struct dev_pm_ops wm831x_rtc_pm_ops = {
        .suspend = wm831x_rtc_suspend,
        .resume = wm831x_rtc_resume,
@@ -478,7 +473,6 @@ static const struct dev_pm_ops wm831x_rtc_pm_ops = {
 
 static struct platform_driver wm831x_rtc_driver = {
        .probe = wm831x_rtc_probe,
-       .remove = wm831x_rtc_remove,
        .driver = {
                .name = "wm831x-rtc",
                .pm = &wm831x_rtc_pm_ops,
index fa9b0679fb60e951120da06a91befb75f9fb5d7f..365dc6505148758dfac6621390133a2a2c7fc210 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2005 Alessandro Zummo
  *
  * please send all reports to:
- *     Karen Spearel <kas111 at gmail dot com>
+ *     Karen Spearel <kas111 at gmail dot com>
  *     Alessandro Zummo <a.zummo@towertech.it>
  *
  * based on a lot of other RTC drivers.
@@ -215,12 +215,14 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
                        buf[i] |= 0x80;
 
        /* this sequence is required to unlock the chip */
-       if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
+       xfer = i2c_master_send(client, wel, 3);
+       if (xfer != 3) {
                dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer);
                return -EIO;
        }
 
-       if ((xfer = i2c_master_send(client, rwel, 3)) != 3) {
+       xfer = i2c_master_send(client, rwel, 3);
+       if (xfer != 3) {
                dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer);
                return -EIO;
        }
@@ -269,7 +271,8 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
        }
 
        /* disable further writes */
-       if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
+       xfer = i2c_master_send(client, diswe, 3);
+       if (xfer != 3) {
                dev_err(&client->dev, "%s: diswe - %d\n", __func__, xfer);
                return -EIO;
        }
@@ -375,8 +378,7 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim)
        return 0;
 }
 
-struct x1205_limit
-{
+struct x1205_limit {
        unsigned char reg, mask, min, max;
 };
 
@@ -430,7 +432,8 @@ static int x1205_validate_client(struct i2c_client *client)
                        },
                };
 
-               if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
+               xfer = i2c_transfer(client->adapter, msgs, 2);
+               if (xfer != 2) {
                        dev_err(&client->dev,
                                "%s: could not read register %x\n",
                                __func__, probe_zero_pattern[i]);
@@ -467,7 +470,8 @@ static int x1205_validate_client(struct i2c_client *client)
                        },
                };
 
-               if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
+               xfer = i2c_transfer(client->adapter, msgs, 2);
+               if (xfer != 2) {
                        dev_err(&client->dev,
                                "%s: could not read register %x\n",
                                __func__, probe_limits_pattern[i].reg);
@@ -548,10 +552,12 @@ static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
 {
        int err, dtrim, atrim;
 
-       if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0)
+       err = x1205_get_dtrim(to_i2c_client(dev), &dtrim);
+       if (!err)
                seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim);
 
-       if ((err = x1205_get_atrim(to_i2c_client(dev), &atrim)) == 0)
+       err = x1205_get_atrim(to_i2c_client(dev), &atrim);
+       if (!err)
                seq_printf(seq, "analog_trim\t: %d.%02d pF\n",
                        atrim / 1000, atrim % 1000);
        return 0;
@@ -639,7 +645,8 @@ static int x1205_probe(struct i2c_client *client,
        i2c_set_clientdata(client, rtc);
 
        /* Check for power failures and eventually enable the osc */
-       if ((err = x1205_get_status(client, &sr)) == 0) {
+       err = x1205_get_status(client, &sr);
+       if (!err) {
                if (sr & X1205_SR_RTCF) {
                        dev_err(&client->dev,
                                "power failure detected, "
@@ -647,9 +654,9 @@ static int x1205_probe(struct i2c_client *client,
                        udelay(50);
                        x1205_fix_osc(client);
                }
-       }
-       else
+       } else {
                dev_err(&client->dev, "couldn't read status\n");
+       }
 
        err = x1205_sysfs_register(&client->dev);
        if (err)
index d72a9216ee2e970d73a4758fbf1ccd1ccc366066..17150a77898433c27e58b2a8ac9ccb81bd228ddb 100644 (file)
@@ -38,9 +38,6 @@
  */
 #define DASD_CHANQ_MAX_SIZE 4
 
-#define DASD_SLEEPON_START_TAG (void *) 1
-#define DASD_SLEEPON_END_TAG   (void *) 2
-
 /*
  * SECTION: exported variables of dasd.c
  */
@@ -1787,11 +1784,11 @@ static void __dasd_device_process_ccw_queue(struct dasd_device *device,
        list_for_each_safe(l, n, &device->ccw_queue) {
                cqr = list_entry(l, struct dasd_ccw_req, devlist);
 
-               /* Stop list processing at the first non-final request. */
+               /* Skip any non-final request. */
                if (cqr->status == DASD_CQR_QUEUED ||
                    cqr->status == DASD_CQR_IN_IO ||
                    cqr->status == DASD_CQR_CLEAR_PENDING)
-                       break;
+                       continue;
                if (cqr->status == DASD_CQR_ERROR) {
                        __dasd_device_recovery(device, cqr);
                }
@@ -2183,7 +2180,7 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
                    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
                    (!dasd_eer_enabled(device))) {
                        cqr->status = DASD_CQR_FAILED;
-                       cqr->intrc = -EAGAIN;
+                       cqr->intrc = -ENOLINK;
                        continue;
                }
                /* Don't try to start requests if device is stopped */
@@ -2402,8 +2399,7 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
  * Cancels a request that was started with dasd_sleep_on_req.
  * This is useful to timeout requests. The request will be
  * terminated if it is currently in i/o.
- * Returns 1 if the request has been terminated.
- *        0 if there was no need to terminate the request (not started yet)
+ * Returns 0 if request termination was successful
  *        negative error code if termination failed
  * Cancellation of a request is an asynchronous operation! The calling
  * function has to wait until the request is properly returned via callback.
@@ -2440,7 +2436,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr)
        return rc;
 }
 
-
 /*
  * SECTION: Operations of the dasd_block layer.
  */
@@ -2537,6 +2532,16 @@ static void __dasd_process_request_queue(struct dasd_block *block)
                        __blk_end_request_all(req, -EIO);
                        continue;
                }
+               if (test_bit(DASD_FLAG_ABORTALL, &basedev->flags) &&
+                   (basedev->features & DASD_FEATURE_FAILFAST ||
+                    blk_noretry_request(req))) {
+                       DBF_DEV_EVENT(DBF_ERR, basedev,
+                                     "Rejecting failfast request %p",
+                                     req);
+                       blk_start_request(req);
+                       __blk_end_request_all(req, -ETIMEDOUT);
+                       continue;
+               }
                cqr = basedev->discipline->build_cp(basedev, block, req);
                if (IS_ERR(cqr)) {
                        if (PTR_ERR(cqr) == -EBUSY)
@@ -2575,8 +2580,10 @@ static void __dasd_process_request_queue(struct dasd_block *block)
                 */
                cqr->callback_data = (void *) req;
                cqr->status = DASD_CQR_FILLED;
+               req->completion_data = cqr;
                blk_start_request(req);
                list_add_tail(&cqr->blocklist, &block->ccw_queue);
+               INIT_LIST_HEAD(&cqr->devlist);
                dasd_profile_start(block, cqr, req);
        }
 }
@@ -2590,8 +2597,17 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
        req = (struct request *) cqr->callback_data;
        dasd_profile_end(cqr->block, cqr, req);
        status = cqr->block->base->discipline->free_cp(cqr, req);
-       if (status <= 0)
-               error = status ? status : -EIO;
+       if (status < 0)
+               error = status;
+       else if (status == 0) {
+               if (cqr->intrc == -EPERM)
+                       error = -EBADE;
+               else if (cqr->intrc == -ENOLINK ||
+                        cqr->intrc == -ETIMEDOUT)
+                       error = cqr->intrc;
+               else
+                       error = -EIO;
+       }
        __blk_end_request_all(req, error);
 }
 
@@ -2692,6 +2708,7 @@ static void __dasd_block_start_head(struct dasd_block *block)
                    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
                    (!dasd_eer_enabled(block->base))) {
                        cqr->status = DASD_CQR_FAILED;
+                       cqr->intrc = -ENOLINK;
                        dasd_schedule_block_bh(block);
                        continue;
                }
@@ -2863,6 +2880,82 @@ static void do_dasd_request(struct request_queue *queue)
        spin_unlock(&block->queue_lock);
 }
 
+/*
+ * Block timeout callback, called from the block layer
+ *
+ * request_queue lock is held on entry.
+ *
+ * Return values:
+ * BLK_EH_RESET_TIMER if the request should be left running
+ * BLK_EH_NOT_HANDLED if the request is handled or terminated
+ *                   by the driver.
+ */
+enum blk_eh_timer_return dasd_times_out(struct request *req)
+{
+       struct dasd_ccw_req *cqr = req->completion_data;
+       struct dasd_block *block = req->q->queuedata;
+       struct dasd_device *device;
+       int rc = 0;
+
+       if (!cqr)
+               return BLK_EH_NOT_HANDLED;
+
+       device = cqr->startdev ? cqr->startdev : block->base;
+       if (!device->blk_timeout)
+               return BLK_EH_RESET_TIMER;
+       DBF_DEV_EVENT(DBF_WARNING, device,
+                     " dasd_times_out cqr %p status %x",
+                     cqr, cqr->status);
+
+       spin_lock(&block->queue_lock);
+       spin_lock(get_ccwdev_lock(device->cdev));
+       cqr->retries = -1;
+       cqr->intrc = -ETIMEDOUT;
+       if (cqr->status >= DASD_CQR_QUEUED) {
+               spin_unlock(get_ccwdev_lock(device->cdev));
+               rc = dasd_cancel_req(cqr);
+       } else if (cqr->status == DASD_CQR_FILLED ||
+                  cqr->status == DASD_CQR_NEED_ERP) {
+               cqr->status = DASD_CQR_TERMINATED;
+               spin_unlock(get_ccwdev_lock(device->cdev));
+       } else if (cqr->status == DASD_CQR_IN_ERP) {
+               struct dasd_ccw_req *searchcqr, *nextcqr, *tmpcqr;
+
+               list_for_each_entry_safe(searchcqr, nextcqr,
+                                        &block->ccw_queue, blocklist) {
+                       tmpcqr = searchcqr;
+                       while (tmpcqr->refers)
+                               tmpcqr = tmpcqr->refers;
+                       if (tmpcqr != cqr)
+                               continue;
+                       /* searchcqr is an ERP request for cqr */
+                       searchcqr->retries = -1;
+                       searchcqr->intrc = -ETIMEDOUT;
+                       if (searchcqr->status >= DASD_CQR_QUEUED) {
+                               spin_unlock(get_ccwdev_lock(device->cdev));
+                               rc = dasd_cancel_req(searchcqr);
+                               spin_lock(get_ccwdev_lock(device->cdev));
+                       } else if ((searchcqr->status == DASD_CQR_FILLED) ||
+                                  (searchcqr->status == DASD_CQR_NEED_ERP)) {
+                               searchcqr->status = DASD_CQR_TERMINATED;
+                               rc = 0;
+                       } else if (searchcqr->status == DASD_CQR_IN_ERP) {
+                               /*
+                                * Shouldn't happen; most recent ERP
+                                * request is at the front of queue
+                                */
+                               continue;
+                       }
+                       break;
+               }
+               spin_unlock(get_ccwdev_lock(device->cdev));
+       }
+       dasd_schedule_block_bh(block);
+       spin_unlock(&block->queue_lock);
+
+       return rc ? BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED;
+}
+
 /*
  * Allocate and initialize request queue and default I/O scheduler.
  */
index a71bb8aaca1de2a86497f1c7b9e07155019c47a0..58bc6eb49de1da7ee1e3061a7ade5865f1c8d800 100644 (file)
@@ -1240,6 +1240,101 @@ dasd_expires_store(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store);
 
+static ssize_t
+dasd_retries_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct dasd_device *device;
+       int len;
+
+       device = dasd_device_from_cdev(to_ccwdev(dev));
+       if (IS_ERR(device))
+               return -ENODEV;
+       len = snprintf(buf, PAGE_SIZE, "%lu\n", device->default_retries);
+       dasd_put_device(device);
+       return len;
+}
+
+static ssize_t
+dasd_retries_store(struct device *dev, struct device_attribute *attr,
+                  const char *buf, size_t count)
+{
+       struct dasd_device *device;
+       unsigned long val;
+
+       device = dasd_device_from_cdev(to_ccwdev(dev));
+       if (IS_ERR(device))
+               return -ENODEV;
+
+       if ((strict_strtoul(buf, 10, &val) != 0) ||
+           (val > DASD_RETRIES_MAX)) {
+               dasd_put_device(device);
+               return -EINVAL;
+       }
+
+       if (val)
+               device->default_retries = val;
+
+       dasd_put_device(device);
+       return count;
+}
+
+static DEVICE_ATTR(retries, 0644, dasd_retries_show, dasd_retries_store);
+
+static ssize_t
+dasd_timeout_show(struct device *dev, struct device_attribute *attr,
+                 char *buf)
+{
+       struct dasd_device *device;
+       int len;
+
+       device = dasd_device_from_cdev(to_ccwdev(dev));
+       if (IS_ERR(device))
+               return -ENODEV;
+       len = snprintf(buf, PAGE_SIZE, "%lu\n", device->blk_timeout);
+       dasd_put_device(device);
+       return len;
+}
+
+static ssize_t
+dasd_timeout_store(struct device *dev, struct device_attribute *attr,
+                  const char *buf, size_t count)
+{
+       struct dasd_device *device;
+       struct request_queue *q;
+       unsigned long val, flags;
+
+       device = dasd_device_from_cdev(to_ccwdev(dev));
+       if (IS_ERR(device) || !device->block)
+               return -ENODEV;
+
+       if ((strict_strtoul(buf, 10, &val) != 0) ||
+           val > UINT_MAX / HZ) {
+               dasd_put_device(device);
+               return -EINVAL;
+       }
+       q = device->block->request_queue;
+       if (!q) {
+               dasd_put_device(device);
+               return -ENODEV;
+       }
+       spin_lock_irqsave(&device->block->request_queue_lock, flags);
+       if (!val)
+               blk_queue_rq_timed_out(q, NULL);
+       else
+               blk_queue_rq_timed_out(q, dasd_times_out);
+
+       device->blk_timeout = val;
+
+       blk_queue_rq_timeout(q, device->blk_timeout * HZ);
+       spin_unlock_irqrestore(&device->block->request_queue_lock, flags);
+
+       dasd_put_device(device);
+       return count;
+}
+
+static DEVICE_ATTR(timeout, 0644,
+                  dasd_timeout_show, dasd_timeout_store);
+
 static ssize_t dasd_reservation_policy_show(struct device *dev,
                                            struct device_attribute *attr,
                                            char *buf)
@@ -1350,6 +1445,8 @@ static struct attribute * dasd_attrs[] = {
        &dev_attr_erplog.attr,
        &dev_attr_failfast.attr,
        &dev_attr_expires.attr,
+       &dev_attr_retries.attr,
+       &dev_attr_timeout.attr,
        &dev_attr_reservation_policy.attr,
        &dev_attr_last_known_reservation_state.attr,
        &dev_attr_safe_offline.attr,
index cc06033585226d04a7e52cf5b1f1ca9fbc6e9a29..feca317b33debfb78409540fab75b1841c0019a0 100644 (file)
@@ -359,6 +359,7 @@ dasd_diag_check_device(struct dasd_device *device)
        }
 
        device->default_expires = DIAG_TIMEOUT;
+       device->default_retries = DIAG_MAX_RETRIES;
 
        /* Figure out position of label block */
        switch (private->rdc_data.vdev_class) {
@@ -555,7 +556,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
                        recid++;
                }
        }
-       cqr->retries = DIAG_MAX_RETRIES;
+       cqr->retries = memdev->default_retries;
        cqr->buildclk = get_tod_clock();
        if (blk_noretry_request(req) ||
            block->base->features & DASD_FEATURE_FAILFAST)
@@ -582,7 +583,10 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
 
 static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)
 {
-       cqr->status = DASD_CQR_FILLED;
+       if (cqr->retries < 0)
+               cqr->status = DASD_CQR_FAILED;
+       else
+               cqr->status = DASD_CQR_FILLED;
 };
 
 /* Fill in IOCTL data for device. */
index 6a44b27623ed1a8378e8201facad2afb22c75e92..e61a6deea3c0fc6bc406c7ac2555b6eda1015dc3 100644 (file)
@@ -1682,6 +1682,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
 
        /* set default timeout */
        device->default_expires = DASD_EXPIRES;
+       /* set default retry count */
+       device->default_retries = DASD_RETRIES;
+
        if (private->gneq) {
                value = 1;
                for (i = 0; i < private->gneq->timeout.value; i++)
@@ -2378,6 +2381,10 @@ sleep:
 
 static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
 {
+       if (cqr->retries < 0) {
+               cqr->status = DASD_CQR_FAILED;
+               return;
+       }
        cqr->status = DASD_CQR_FILLED;
        if (cqr->block && (cqr->startdev != cqr->block->base)) {
                dasd_eckd_reset_ccw_to_base_io(cqr);
@@ -2659,7 +2666,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
        cqr->block = block;
        cqr->expires = startdev->default_expires * HZ;  /* default 5 minutes */
        cqr->lpm = startdev->path_data.ppm;
-       cqr->retries = 256;
+       cqr->retries = startdev->default_retries;
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
        return cqr;
@@ -2834,7 +2841,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
        cqr->block = block;
        cqr->expires = startdev->default_expires * HZ;  /* default 5 minutes */
        cqr->lpm = startdev->path_data.ppm;
-       cqr->retries = 256;
+       cqr->retries = startdev->default_retries;
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
        return cqr;
@@ -2968,7 +2975,7 @@ static int prepare_itcw(struct itcw *itcw,
 
        dcw = itcw_add_dcw(itcw, pfx_cmd, 0,
                     &pfxdata, sizeof(pfxdata), total_data_size);
-       return IS_ERR(dcw) ? PTR_ERR(dcw) : 0;
+       return PTR_RET(dcw);
 }
 
 static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
@@ -3127,7 +3134,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
        cqr->block = block;
        cqr->expires = startdev->default_expires * HZ;  /* default 5 minutes */
        cqr->lpm = startdev->path_data.ppm;
-       cqr->retries = 256;
+       cqr->retries = startdev->default_retries;
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
        return cqr;
@@ -3330,7 +3337,7 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
        cqr->block = block;
        cqr->expires = startdev->default_expires * HZ;
        cqr->lpm = startdev->path_data.ppm;
-       cqr->retries = 256;
+       cqr->retries = startdev->default_retries;
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
 
index 3250cb471f787493a0e57d630f6af451efc92840..8d11f773a75224a74745f20a03be731ea9dad267 100644 (file)
@@ -159,6 +159,14 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
        struct dasd_device *device;
 
        device = cqr->startdev;
+       if (cqr->intrc == -ETIMEDOUT) {
+               dev_err(&device->cdev->dev, "cqr %p timeout error", cqr);
+               return;
+       }
+       if (cqr->intrc == -ENOLINK) {
+               dev_err(&device->cdev->dev, "cqr %p transport error", cqr);
+               return;
+       }
        /* dump sense data */
        if (device->discipline && device->discipline->dump_sense)
                device->discipline->dump_sense(device, cqr, irb);
index 4dd0e2f6047ef3e406718dfe6707ca23acda5c72..9cbc8c32ba595739cdff63da752a8f080b51e0de 100644 (file)
@@ -29,6 +29,8 @@
 #endif                         /* PRINTK_HEADER */
 #define PRINTK_HEADER "dasd(fba):"
 
+#define FBA_DEFAULT_RETRIES 32
+
 #define DASD_FBA_CCW_WRITE 0x41
 #define DASD_FBA_CCW_READ 0x42
 #define DASD_FBA_CCW_LOCATE 0x43
@@ -167,6 +169,7 @@ dasd_fba_check_characteristics(struct dasd_device *device)
        }
 
        device->default_expires = DASD_EXPIRES;
+       device->default_retries = FBA_DEFAULT_RETRIES;
        device->path_data.opm = LPM_ANYPATH;
 
        readonly = dasd_device_is_ro(device);
@@ -369,7 +372,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
        cqr->memdev = memdev;
        cqr->block = block;
        cqr->expires = memdev->default_expires * HZ;    /* default 5 minutes */
-       cqr->retries = 32;
+       cqr->retries = memdev->default_retries;
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
        return cqr;
@@ -425,7 +428,10 @@ out:
 
 static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr)
 {
-       cqr->status = DASD_CQR_FILLED;
+       if (cqr->retries < 0)
+               cqr->status = DASD_CQR_FAILED;
+       else
+               cqr->status = DASD_CQR_FILLED;
 };
 
 static int
index 0785bd9bd5b60ddeca4a4bd3894e9949b76d661d..690001af0d09b990405d482d7675faf28a3847bb 100644 (file)
@@ -224,6 +224,8 @@ struct dasd_ccw_req {
 /* default expiration time*/
 #define DASD_EXPIRES     300
 #define DASD_EXPIRES_MAX  40000000
+#define DASD_RETRIES     256
+#define DASD_RETRIES_MAX  32768
 
 /* per dasd_ccw_req flags */
 #define DASD_CQR_FLAGS_USE_ERP   0     /* use ERP for this request */
@@ -466,6 +468,9 @@ struct dasd_device {
 
        /* default expiration time in s */
        unsigned long default_expires;
+       unsigned long default_retries;
+
+       unsigned long blk_timeout;
 
        struct dentry *debugfs_dentry;
        struct dasd_profile profile;
@@ -519,7 +524,10 @@ struct dasd_block {
 #define DASD_FLAG_SUSPENDED    9       /* The device was suspended */
 #define DASD_FLAG_SAFE_OFFLINE 10      /* safe offline processing requested*/
 #define DASD_FLAG_SAFE_OFFLINE_RUNNING 11      /* safe offline running */
+#define DASD_FLAG_ABORTALL     12      /* Abort all noretry requests */
 
+#define DASD_SLEEPON_START_TAG ((void *) 1)
+#define DASD_SLEEPON_END_TAG   ((void *) 2)
 
 void dasd_put_device_wake(struct dasd_device *);
 
@@ -660,6 +668,8 @@ void dasd_free_device(struct dasd_device *);
 struct dasd_block *dasd_alloc_block(void);
 void dasd_free_block(struct dasd_block *);
 
+enum blk_eh_timer_return dasd_times_out(struct request *req);
+
 void dasd_enable_device(struct dasd_device *);
 void dasd_set_target_state(struct dasd_device *, int);
 void dasd_kick_device(struct dasd_device *);
index 8be1b51e9311a4e0ec528620947e058095caecd5..25a0f2f8b0b98c93376294e25512e43c53701f72 100644 (file)
@@ -140,6 +140,59 @@ static int dasd_ioctl_resume(struct dasd_block *block)
        return 0;
 }
 
+/*
+ * Abort all failfast I/O on a device.
+ */
+static int dasd_ioctl_abortio(struct dasd_block *block)
+{
+       unsigned long flags;
+       struct dasd_device *base;
+       struct dasd_ccw_req *cqr, *n;
+
+       base = block->base;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (test_and_set_bit(DASD_FLAG_ABORTALL, &base->flags))
+               return 0;
+       DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag set");
+
+       spin_lock_irqsave(&block->request_queue_lock, flags);
+       spin_lock(&block->queue_lock);
+       list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) {
+               if (test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+                   cqr->callback_data &&
+                   cqr->callback_data != DASD_SLEEPON_START_TAG &&
+                   cqr->callback_data != DASD_SLEEPON_END_TAG) {
+                       spin_unlock(&block->queue_lock);
+                       blk_abort_request(cqr->callback_data);
+                       spin_lock(&block->queue_lock);
+               }
+       }
+       spin_unlock(&block->queue_lock);
+       spin_unlock_irqrestore(&block->request_queue_lock, flags);
+
+       dasd_schedule_block_bh(block);
+       return 0;
+}
+
+/*
+ * Allow I/O on a device
+ */
+static int dasd_ioctl_allowio(struct dasd_block *block)
+{
+       struct dasd_device *base;
+
+       base = block->base;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (test_and_clear_bit(DASD_FLAG_ABORTALL, &base->flags))
+               DBF_DEV_EVENT(DBF_NOTICE, base, "%s", "abortall flag unset");
+
+       return 0;
+}
+
 /*
  * performs formatting of _device_ according to _fdata_
  * Note: The discipline's format_function is assumed to deliver formatting
@@ -458,6 +511,12 @@ int dasd_ioctl(struct block_device *bdev, fmode_t mode,
        case BIODASDRESUME:
                rc = dasd_ioctl_resume(block);
                break;
+       case BIODASDABORTIO:
+               rc = dasd_ioctl_abortio(block);
+               break;
+       case BIODASDALLOWIO:
+               rc = dasd_ioctl_allowio(block);
+               break;
        case BIODASDFMT:
                rc = dasd_ioctl_format(bdev, argp);
                break;
index f3c325207445513c5aca471d413845b6a90980d3..17821a026c9ca9b4ae6878bb57c04a56692850e4 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
-        sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o
+        sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
index bd6871bf545a67200a5e4af4c672fb18f0193f0c..3e4fb4e858da7514eb7a1c5677d23577acba7793 100644 (file)
@@ -50,11 +50,42 @@ static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 /* Suspend request */
 static DECLARE_COMPLETION(sclp_request_queue_flushed);
 
+/* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */
+int sclp_console_pages = SCLP_CONSOLE_PAGES;
+/* Flag to indicate if buffer pages are dropped on buffer full condition */
+int sclp_console_drop = 0;
+/* Number of times the console dropped buffer pages */
+unsigned long sclp_console_full;
+
 static void sclp_suspend_req_cb(struct sclp_req *req, void *data)
 {
        complete(&sclp_request_queue_flushed);
 }
 
+static int __init sclp_setup_console_pages(char *str)
+{
+       int pages, rc;
+
+       rc = kstrtoint(str, 0, &pages);
+       if (!rc && pages >= SCLP_CONSOLE_PAGES)
+               sclp_console_pages = pages;
+       return 1;
+}
+
+__setup("sclp_con_pages=", sclp_setup_console_pages);
+
+static int __init sclp_setup_console_drop(char *str)
+{
+       int drop, rc;
+
+       rc = kstrtoint(str, 0, &drop);
+       if (!rc && drop)
+               sclp_console_drop = 1;
+       return 1;
+}
+
+__setup("sclp_con_drop=", sclp_setup_console_drop);
+
 static struct sclp_req sclp_suspend_req;
 
 /* Timer for request retries. */
@@ -117,14 +148,19 @@ static int sclp_init(void);
 int
 sclp_service_call(sclp_cmdw_t command, void *sccb)
 {
-       int cc;
+       int cc = 4; /* Initialize for program check handling */
 
        asm volatile(
-               "       .insn   rre,0xb2200000,%1,%2\n"  /* servc %1,%2 */
-               "       ipm     %0\n"
-               "       srl     %0,28"
-               : "=&d" (cc) : "d" (command), "a" (__pa(sccb))
+               "0:     .insn   rre,0xb2200000,%1,%2\n"  /* servc %1,%2 */
+               "1:     ipm     %0\n"
+               "       srl     %0,28\n"
+               "2:\n"
+               EX_TABLE(0b, 2b)
+               EX_TABLE(1b, 2b)
+               : "+&d" (cc) : "d" (command), "a" (__pa(sccb))
                : "cc", "memory");
+       if (cc == 4)
+               return -EINVAL;
        if (cc == 3)
                return -EIO;
        if (cc == 2)
@@ -1013,11 +1049,47 @@ static const struct dev_pm_ops sclp_pm_ops = {
        .restore        = sclp_restore,
 };
 
+static ssize_t sclp_show_console_pages(struct device_driver *dev, char *buf)
+{
+       return sprintf(buf, "%i\n", sclp_console_pages);
+}
+
+static DRIVER_ATTR(con_pages, S_IRUSR, sclp_show_console_pages, NULL);
+
+static ssize_t sclp_show_con_drop(struct device_driver *dev, char *buf)
+{
+       return sprintf(buf, "%i\n", sclp_console_drop);
+}
+
+static DRIVER_ATTR(con_drop, S_IRUSR, sclp_show_con_drop, NULL);
+
+static ssize_t sclp_show_console_full(struct device_driver *dev, char *buf)
+{
+       return sprintf(buf, "%lu\n", sclp_console_full);
+}
+
+static DRIVER_ATTR(con_full, S_IRUSR, sclp_show_console_full, NULL);
+
+static struct attribute *sclp_drv_attrs[] = {
+       &driver_attr_con_pages.attr,
+       &driver_attr_con_drop.attr,
+       &driver_attr_con_full.attr,
+       NULL,
+};
+static struct attribute_group sclp_drv_attr_group = {
+       .attrs = sclp_drv_attrs,
+};
+static const struct attribute_group *sclp_drv_attr_groups[] = {
+       &sclp_drv_attr_group,
+       NULL,
+};
+
 static struct platform_driver sclp_pdrv = {
        .driver = {
                .name   = "sclp",
                .owner  = THIS_MODULE,
                .pm     = &sclp_pm_ops,
+               .groups = sclp_drv_attr_groups,
        },
 };
 
@@ -1096,10 +1168,12 @@ static __init int sclp_initcall(void)
        rc = platform_driver_register(&sclp_pdrv);
        if (rc)
                return rc;
+
        sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0);
-       rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0;
+       rc = PTR_RET(sclp_pdev);
        if (rc)
                goto fail_platform_driver_unregister;
+
        rc = atomic_notifier_chain_register(&panic_notifier_list,
                                            &sclp_on_panic_nb);
        if (rc)
index 25bcd4c0ed82d35f522f4d0efdd7477ec6076a01..40d1406289ed2533f6bd4bdffda0b0e19a80a79e 100644 (file)
@@ -15,7 +15,7 @@
 
 /* maximum number of pages concerning our own memory management */
 #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3)
-#define MAX_CONSOLE_PAGES      6
+#define SCLP_CONSOLE_PAGES     6
 
 #define EVTYP_OPCMD            0x01
 #define EVTYP_MSG              0x02
@@ -171,10 +171,15 @@ int sclp_remove_processed(struct sccb_header *sccb);
 int sclp_deactivate(void);
 int sclp_reactivate(void);
 int sclp_service_call(sclp_cmdw_t command, void *sccb);
+int sclp_sync_request(sclp_cmdw_t command, void *sccb);
 
 int sclp_sdias_init(void);
 void sclp_sdias_exit(void);
 
+extern int sclp_console_pages;
+extern int sclp_console_drop;
+extern unsigned long sclp_console_full;
+
 /* useful inlines */
 
 /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */
index bf07c3a188d4c0f5b694b51d84f053ab3b526838..8cd34bf644b3ee4b34065814fab4300774c8ad23 100644 (file)
@@ -195,7 +195,7 @@ static void sclp_sync_callback(struct sclp_req *req, void *data)
        complete(completion);
 }
 
-static int do_sync_request(sclp_cmdw_t cmd, void *sccb)
+int sclp_sync_request(sclp_cmdw_t cmd, void *sccb)
 {
        struct completion completion;
        struct sclp_req *request;
@@ -270,7 +270,7 @@ int sclp_get_cpu_info(struct sclp_cpu_info *info)
        if (!sccb)
                return -ENOMEM;
        sccb->header.length = sizeof(*sccb);
-       rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb);
+       rc = sclp_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb);
        if (rc)
                goto out;
        if (sccb->header.response_code != 0x0010) {
@@ -304,7 +304,7 @@ static int do_cpu_configure(sclp_cmdw_t cmd)
        if (!sccb)
                return -ENOMEM;
        sccb->header.length = sizeof(*sccb);
-       rc = do_sync_request(cmd, sccb);
+       rc = sclp_sync_request(cmd, sccb);
        if (rc)
                goto out;
        switch (sccb->header.response_code) {
@@ -374,7 +374,7 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn)
                return -ENOMEM;
        sccb->header.length = PAGE_SIZE;
        sccb->rn = rn;
-       rc = do_sync_request(cmd, sccb);
+       rc = sclp_sync_request(cmd, sccb);
        if (rc)
                goto out;
        switch (sccb->header.response_code) {
@@ -429,7 +429,7 @@ static int sclp_attach_storage(u8 id)
        if (!sccb)
                return -ENOMEM;
        sccb->header.length = PAGE_SIZE;
-       rc = do_sync_request(0x00080001 | id << 8, sccb);
+       rc = sclp_sync_request(0x00080001 | id << 8, sccb);
        if (rc)
                goto out;
        switch (sccb->header.response_code) {
@@ -627,7 +627,7 @@ static int __init sclp_detect_standby_memory(void)
        for (id = 0; id <= sclp_max_storage_id; id++) {
                memset(sccb, 0, PAGE_SIZE);
                sccb->header.length = PAGE_SIZE;
-               rc = do_sync_request(0x00040001 | id << 8, sccb);
+               rc = sclp_sync_request(0x00040001 | id << 8, sccb);
                if (rc)
                        goto out;
                switch (sccb->header.response_code) {
@@ -668,7 +668,7 @@ static int __init sclp_detect_standby_memory(void)
        if (rc)
                goto out;
        sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0);
-       rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0;
+       rc = PTR_RET(sclp_pdev);
        if (rc)
                goto out_driver;
        sclp_add_standby_memory();
@@ -714,7 +714,7 @@ static int do_pci_configure(sclp_cmdw_t cmd, u32 fid)
        sccb->header.length = PAGE_SIZE;
        sccb->atype = SCLP_RECONFIG_PCI_ATPYE;
        sccb->aid = fid;
-       rc = do_sync_request(cmd, sccb);
+       rc = sclp_sync_request(cmd, sccb);
        if (rc)
                goto out;
        switch (sccb->header.response_code) {
@@ -771,7 +771,7 @@ static int do_chp_configure(sclp_cmdw_t cmd)
        if (!sccb)
                return -ENOMEM;
        sccb->header.length = sizeof(*sccb);
-       rc = do_sync_request(cmd, sccb);
+       rc = sclp_sync_request(cmd, sccb);
        if (rc)
                goto out;
        switch (sccb->header.response_code) {
@@ -846,7 +846,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info)
        if (!sccb)
                return -ENOMEM;
        sccb->header.length = sizeof(*sccb);
-       rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb);
+       rc = sclp_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb);
        if (rc)
                goto out;
        if (sccb->header.response_code != 0x0010) {
index ecf45c54f8c469c84da45049e006225593283a90..5880def98fc1be4dbfedbfa166d725a52ffc35c2 100644 (file)
@@ -129,6 +129,31 @@ sclp_console_timeout(unsigned long data)
        sclp_conbuf_emit();
 }
 
+/*
+ * Drop oldest console buffer if sclp_con_drop is set
+ */
+static int
+sclp_console_drop_buffer(void)
+{
+       struct list_head *list;
+       struct sclp_buffer *buffer;
+       void *page;
+
+       if (!sclp_console_drop)
+               return 0;
+       list = sclp_con_outqueue.next;
+       if (sclp_con_queue_running)
+               /* The first element is in I/O */
+               list = list->next;
+       if (list == &sclp_con_outqueue)
+               return 0;
+       list_del(list);
+       buffer = list_entry(list, struct sclp_buffer, list);
+       page = sclp_unmake_buffer(buffer);
+       list_add_tail((struct list_head *) page, &sclp_con_pages);
+       return 1;
+}
+
 /*
  * Writes the given message to S390 system console
  */
@@ -150,9 +175,13 @@ sclp_console_write(struct console *console, const char *message,
        do {
                /* make sure we have a console output buffer */
                if (sclp_conbuf == NULL) {
+                       if (list_empty(&sclp_con_pages))
+                               sclp_console_full++;
                        while (list_empty(&sclp_con_pages)) {
                                if (sclp_con_suspended)
                                        goto out;
+                               if (sclp_console_drop_buffer())
+                                       break;
                                spin_unlock_irqrestore(&sclp_con_lock, flags);
                                sclp_sync_wait();
                                spin_lock_irqsave(&sclp_con_lock, flags);
@@ -297,7 +326,7 @@ sclp_console_init(void)
                return rc;
        /* Allocate pages for output buffering */
        INIT_LIST_HEAD(&sclp_con_pages);
-       for (i = 0; i < MAX_CONSOLE_PAGES; i++) {
+       for (i = 0; i < sclp_console_pages; i++) {
                page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
                list_add_tail(page, &sclp_con_pages);
        }
diff --git a/drivers/s390/char/sclp_ctl.c b/drivers/s390/char/sclp_ctl.c
new file mode 100644 (file)
index 0000000..648cb86
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * IOCTL interface for SCLP
+ *
+ * Copyright IBM Corp. 2012
+ *
+ * Author: Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#include <linux/compat.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <asm/compat.h>
+#include <asm/sclp_ctl.h>
+#include <asm/sclp.h>
+
+#include "sclp.h"
+
+/*
+ * Supported command words
+ */
+static unsigned int sclp_ctl_sccb_wlist[] = {
+       0x00400002,
+       0x00410002,
+};
+
+/*
+ * Check if command word is supported
+ */
+static int sclp_ctl_cmdw_supported(unsigned int cmdw)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sclp_ctl_sccb_wlist); i++) {
+               if (cmdw == sclp_ctl_sccb_wlist[i])
+                       return 1;
+       }
+       return 0;
+}
+
+static void __user *u64_to_uptr(u64 value)
+{
+       if (is_compat_task())
+               return compat_ptr(value);
+       else
+               return (void __user *)(unsigned long)value;
+}
+
+/*
+ * Start SCLP request
+ */
+static int sclp_ctl_ioctl_sccb(void __user *user_area)
+{
+       struct sclp_ctl_sccb ctl_sccb;
+       struct sccb_header *sccb;
+       int rc;
+
+       if (copy_from_user(&ctl_sccb, user_area, sizeof(ctl_sccb)))
+               return -EFAULT;
+       if (!sclp_ctl_cmdw_supported(ctl_sccb.cmdw))
+               return -EOPNOTSUPP;
+       sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!sccb)
+               return -ENOMEM;
+       if (copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), sizeof(*sccb))) {
+               rc = -EFAULT;
+               goto out_free;
+       }
+       if (sccb->length > PAGE_SIZE || sccb->length < 8)
+               return -EINVAL;
+       if (copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), sccb->length)) {
+               rc = -EFAULT;
+               goto out_free;
+       }
+       rc = sclp_sync_request(ctl_sccb.cmdw, sccb);
+       if (rc)
+               goto out_free;
+       if (copy_to_user(u64_to_uptr(ctl_sccb.sccb), sccb, sccb->length))
+               rc = -EFAULT;
+out_free:
+       free_page((unsigned long) sccb);
+       return rc;
+}
+
+/*
+ * SCLP SCCB ioctl function
+ */
+static long sclp_ctl_ioctl(struct file *filp, unsigned int cmd,
+                          unsigned long arg)
+{
+       void __user *argp;
+
+       if (is_compat_task())
+               argp = compat_ptr(arg);
+       else
+               argp = (void __user *) arg;
+       switch (cmd) {
+       case SCLP_CTL_SCCB:
+               return sclp_ctl_ioctl_sccb(argp);
+       default: /* unknown ioctl number */
+               return -ENOTTY;
+       }
+}
+
+/*
+ * File operations
+ */
+static const struct file_operations sclp_ctl_fops = {
+       .owner = THIS_MODULE,
+       .open = nonseekable_open,
+       .unlocked_ioctl = sclp_ctl_ioctl,
+       .compat_ioctl = sclp_ctl_ioctl,
+       .llseek = no_llseek,
+};
+
+/*
+ * Misc device definition
+ */
+static struct miscdevice sclp_ctl_device = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "sclp",
+       .fops = &sclp_ctl_fops,
+};
+
+/*
+ * Register sclp_ctl misc device
+ */
+static int __init sclp_ctl_init(void)
+{
+       return misc_register(&sclp_ctl_device);
+}
+module_init(sclp_ctl_init);
+
+/*
+ * Deregister sclp_ctl misc device
+ */
+static void __exit sclp_ctl_exit(void)
+{
+       misc_deregister(&sclp_ctl_device);
+}
+module_exit(sclp_ctl_exit);
index 5aaaa2ec8df44f4547c70b9f80d5c628c6d9d591..4eed38cd0af629b87108289174a81a9c5dedb44c 100644 (file)
@@ -362,6 +362,31 @@ sclp_vt220_timeout(unsigned long data)
 
 #define BUFFER_MAX_DELAY       HZ/20
 
+/*
+ * Drop oldest console buffer if sclp_con_drop is set
+ */
+static int
+sclp_vt220_drop_buffer(void)
+{
+       struct list_head *list;
+       struct sclp_vt220_request *request;
+       void *page;
+
+       if (!sclp_console_drop)
+               return 0;
+       list = sclp_vt220_outqueue.next;
+       if (sclp_vt220_queue_running)
+               /* The first element is in I/O */
+               list = list->next;
+       if (list == &sclp_vt220_outqueue)
+               return 0;
+       list_del(list);
+       request = list_entry(list, struct sclp_vt220_request, list);
+       page = request->sclp_req.sccb;
+       list_add_tail((struct list_head *) page, &sclp_vt220_empty);
+       return 1;
+}
+
 /* 
  * Internal implementation of the write function. Write COUNT bytes of data
  * from memory at BUF
@@ -390,12 +415,16 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
        do {
                /* Create an sclp output buffer if none exists yet */
                if (sclp_vt220_current_request == NULL) {
+                       if (list_empty(&sclp_vt220_empty))
+                               sclp_console_full++;
                        while (list_empty(&sclp_vt220_empty)) {
-                               spin_unlock_irqrestore(&sclp_vt220_lock, flags);
                                if (may_fail || sclp_vt220_suspended)
                                        goto out;
-                               else
-                                       sclp_sync_wait();
+                               if (sclp_vt220_drop_buffer())
+                                       break;
+                               spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+
+                               sclp_sync_wait();
                                spin_lock_irqsave(&sclp_vt220_lock, flags);
                        }
                        page = (void *) sclp_vt220_empty.next;
@@ -428,8 +457,8 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
                sclp_vt220_timer.expires = jiffies + BUFFER_MAX_DELAY;
                add_timer(&sclp_vt220_timer);
        }
-       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
 out:
+       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
        return overall_written;
 }
 
@@ -803,7 +832,7 @@ sclp_vt220_con_init(void)
 
        if (!CONSOLE_IS_SCLP)
                return 0;
-       rc = __sclp_vt220_init(MAX_CONSOLE_PAGES);
+       rc = __sclp_vt220_init(sclp_console_pages);
        if (rc)
                return rc;
        /* Attach linux console */
index 54b3c79203f5103964e93b80c73e7cc1f13ae9a6..91c3c642c76e44e97f8538da6e58672339c98e55 100644 (file)
@@ -77,7 +77,7 @@ struct tape_class_device *register_tape_dev(
        tcd->class_device = device_create(tape_class, device,
                                          tcd->char_device->dev, NULL,
                                          "%s", tcd->device_name);
-       rc = IS_ERR(tcd->class_device) ? PTR_ERR(tcd->class_device) : 0;
+       rc = PTR_RET(tcd->class_device);
        if (rc)
                goto fail_with_cdev;
        rc = sysfs_create_link(
index e9b72311e2549a370f1d213c9a8277e7c233186f..d5eac985976b42b5b5617f5f14c762b505a8ece0 100644 (file)
@@ -112,7 +112,8 @@ static int vmwdt_keepalive(void)
 
 static int vmwdt_disable(void)
 {
-       int ret = __diag288(wdt_cancel, 0, "", 0);
+       char cmd[] = {'\0'};
+       int ret = __diag288(wdt_cancel, 0, cmd, 0);
        WARN_ON(ret != 0);
        clear_bit(VMWDT_RUNNING, &vmwdt_is_open);
        return ret;
@@ -124,7 +125,7 @@ static int __init vmwdt_probe(void)
         * so we try initializing it with a NOP command ("BEGIN")
         * that won't cause any harm even if the following disable
         * fails for some reason */
-       static char __initdata ebc_begin[] = {
+       char ebc_begin[] = {
                194, 197, 199, 201, 213
        };
        if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0)
index bc10220f684700e2909ed45a8ece94015d1b44ba..91edbd7ee80640d7d624280722843cbfb69093a8 100644 (file)
  */
 
 #include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/rculist.h>
 #include <linux/slab.h>
-#include <linux/rcupdate.h>
 
 #include <asm/airq.h>
 #include <asm/isc.h>
 
 #include "cio.h"
 #include "cio_debug.h"
+#include "ioasm.h"
 
-#define NR_AIRQS               32
-#define NR_AIRQS_PER_WORD      sizeof(unsigned long)
-#define NR_AIRQ_WORDS          (NR_AIRQS / NR_AIRQS_PER_WORD)
-
-union indicator_t {
-       unsigned long word[NR_AIRQ_WORDS];
-       unsigned char byte[NR_AIRQS];
-} __attribute__((packed));
-
-struct airq_t {
-       adapter_int_handler_t handler;
-       void *drv_data;
-};
-
-static union indicator_t indicators[MAX_ISC+1];
-static struct airq_t *airqs[MAX_ISC+1][NR_AIRQS];
-
-static int register_airq(struct airq_t *airq, u8 isc)
-{
-       int i;
-
-       for (i = 0; i < NR_AIRQS; i++)
-               if (!cmpxchg(&airqs[isc][i], NULL, airq))
-                       return i;
-       return -ENOMEM;
-}
+static DEFINE_SPINLOCK(airq_lists_lock);
+static struct hlist_head airq_lists[MAX_ISC+1];
 
 /**
- * s390_register_adapter_interrupt() - register adapter interrupt handler
- * @handler: adapter handler to be registered
- * @drv_data: driver data passed with each call to the handler
- * @isc: isc for which the handler should be called
+ * register_adapter_interrupt() - register adapter interrupt handler
+ * @airq: pointer to adapter interrupt descriptor
  *
- * Returns:
- *  Pointer to the indicator to be used on success
- *  ERR_PTR() if registration failed
+ * Returns 0 on success, or -EINVAL.
  */
-void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
-                                     void *drv_data, u8 isc)
+int register_adapter_interrupt(struct airq_struct *airq)
 {
-       struct airq_t *airq;
-       char dbf_txt[16];
-       int ret;
-
-       if (isc > MAX_ISC)
-               return ERR_PTR(-EINVAL);
-       airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
-       if (!airq) {
-               ret = -ENOMEM;
-               goto out;
+       char dbf_txt[32];
+
+       if (!airq->handler || airq->isc > MAX_ISC)
+               return -EINVAL;
+       if (!airq->lsi_ptr) {
+               airq->lsi_ptr = kzalloc(1, GFP_KERNEL);
+               if (!airq->lsi_ptr)
+                       return -ENOMEM;
+               airq->flags |= AIRQ_PTR_ALLOCATED;
        }
-       airq->handler = handler;
-       airq->drv_data = drv_data;
-
-       ret = register_airq(airq, isc);
-out:
-       snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
+       if (!airq->lsi_mask)
+               airq->lsi_mask = 0xff;
+       snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%p", airq);
        CIO_TRACE_EVENT(4, dbf_txt);
-       if (ret < 0) {
-               kfree(airq);
-               return ERR_PTR(ret);
-       } else
-               return &indicators[isc].byte[ret];
+       isc_register(airq->isc);
+       spin_lock(&airq_lists_lock);
+       hlist_add_head_rcu(&airq->list, &airq_lists[airq->isc]);
+       spin_unlock(&airq_lists_lock);
+       return 0;
 }
-EXPORT_SYMBOL(s390_register_adapter_interrupt);
+EXPORT_SYMBOL(register_adapter_interrupt);
 
 /**
- * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
- * @ind: indicator for which the handler is to be unregistered
- * @isc: interruption subclass
+ * unregister_adapter_interrupt - unregister adapter interrupt handler
+ * @airq: pointer to adapter interrupt descriptor
  */
-void s390_unregister_adapter_interrupt(void *ind, u8 isc)
+void unregister_adapter_interrupt(struct airq_struct *airq)
 {
-       struct airq_t *airq;
-       char dbf_txt[16];
-       int i;
+       char dbf_txt[32];
 
-       i = (int) ((addr_t) ind) - ((addr_t) &indicators[isc].byte[0]);
-       snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
+       if (hlist_unhashed(&airq->list))
+               return;
+       snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%p", airq);
        CIO_TRACE_EVENT(4, dbf_txt);
-       indicators[isc].byte[i] = 0;
-       airq = xchg(&airqs[isc][i], NULL);
-       /*
-        * Allow interrupts to complete. This will ensure that the airq handle
-        * is no longer referenced by any interrupt handler.
-        */
-       synchronize_sched();
-       kfree(airq);
+       spin_lock(&airq_lists_lock);
+       hlist_del_rcu(&airq->list);
+       spin_unlock(&airq_lists_lock);
+       synchronize_rcu();
+       isc_unregister(airq->isc);
+       if (airq->flags & AIRQ_PTR_ALLOCATED) {
+               kfree(airq->lsi_ptr);
+               airq->lsi_ptr = NULL;
+               airq->flags &= ~AIRQ_PTR_ALLOCATED;
+       }
 }
-EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
-
-#define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
+EXPORT_SYMBOL(unregister_adapter_interrupt);
 
 void do_adapter_IO(u8 isc)
 {
-       int w;
-       int i;
-       unsigned long word;
-       struct airq_t *airq;
-
-       /*
-        * Access indicator array in word-sized chunks to minimize storage
-        * fetch operations.
-        */
-       for (w = 0; w < NR_AIRQ_WORDS; w++) {
-               word = indicators[isc].word[w];
-               i = w * NR_AIRQS_PER_WORD;
-               /*
-                * Check bytes within word for active indicators.
-                */
-               while (word) {
-                       if (word & INDICATOR_MASK) {
-                               airq = airqs[isc][i];
-                               /* Make sure gcc reads from airqs only once. */
-                               barrier();
-                               if (likely(airq))
-                                       airq->handler(&indicators[isc].byte[i],
-                                                     airq->drv_data);
-                               else
-                                       /*
-                                        * Reset ill-behaved indicator.
-                                        */
-                                       indicators[isc].byte[i] = 0;
-                       }
-                       word <<= 8;
-                       i++;
-               }
-       }
+       struct airq_struct *airq;
+       struct hlist_head *head;
+
+       head = &airq_lists[isc];
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(airq, head, list)
+               if ((*airq->lsi_ptr & airq->lsi_mask) != 0)
+                       airq->handler(airq);
+       rcu_read_unlock();
 }
index 8ea7d9b2c671a3555c7c5d2c57b505d9f338033c..13299f902676e647d43dce13d95f864c81300f53 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/chpid.h>
 #include <asm/chsc.h>
 #include <asm/crw.h>
+#include <asm/isc.h>
 
 #include "css.h"
 #include "cio.h"
@@ -144,6 +145,65 @@ out:
        return ret;
 }
 
+/**
+ * chsc_ssqd() - store subchannel QDIO data (SSQD)
+ * @schid: id of the subchannel on which SSQD is performed
+ * @ssqd: request and response block for SSQD
+ *
+ * Returns 0 on success.
+ */
+int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd)
+{
+       memset(ssqd, 0, sizeof(*ssqd));
+       ssqd->request.length = 0x0010;
+       ssqd->request.code = 0x0024;
+       ssqd->first_sch = schid.sch_no;
+       ssqd->last_sch = schid.sch_no;
+       ssqd->ssid = schid.ssid;
+
+       if (chsc(ssqd))
+               return -EIO;
+
+       return chsc_error_from_response(ssqd->response.code);
+}
+EXPORT_SYMBOL_GPL(chsc_ssqd);
+
+/**
+ * chsc_sadc() - set adapter device controls (SADC)
+ * @schid: id of the subchannel on which SADC is performed
+ * @scssc: request and response block for SADC
+ * @summary_indicator_addr: summary indicator address
+ * @subchannel_indicator_addr: subchannel indicator address
+ *
+ * Returns 0 on success.
+ */
+int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc,
+             u64 summary_indicator_addr, u64 subchannel_indicator_addr)
+{
+       memset(scssc, 0, sizeof(*scssc));
+       scssc->request.length = 0x0fe0;
+       scssc->request.code = 0x0021;
+       scssc->operation_code = 0;
+
+       scssc->summary_indicator_addr = summary_indicator_addr;
+       scssc->subchannel_indicator_addr = subchannel_indicator_addr;
+
+       scssc->ks = PAGE_DEFAULT_KEY >> 4;
+       scssc->kc = PAGE_DEFAULT_KEY >> 4;
+       scssc->isc = QDIO_AIRQ_ISC;
+       scssc->schid = schid;
+
+       /* enable the time delay disablement facility */
+       if (css_general_characteristics.aif_tdd)
+               scssc->word_with_d_bit = 0x10000000;
+
+       if (chsc(scssc))
+               return -EIO;
+
+       return chsc_error_from_response(scssc->response.code);
+}
+EXPORT_SYMBOL_GPL(chsc_sadc);
+
 static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data)
 {
        spin_lock_irq(sch->lock);
index e7ef2a683b8fbc617368ad855f4f18d6832b3eb6..23d072e70eb2f4e87e1a9dbefcd244c35a98b977 100644 (file)
@@ -7,14 +7,10 @@
 #include <asm/chpid.h>
 #include <asm/chsc.h>
 #include <asm/schid.h>
+#include <asm/qdio.h>
 
 #define CHSC_SDA_OC_MSS   0x2
 
-struct chsc_header {
-       u16 length;
-       u16 code;
-} __attribute__ ((packed));
-
 #define NR_MEASUREMENT_CHARS 5
 struct cmg_chars {
        u32 values[NR_MEASUREMENT_CHARS];
@@ -77,6 +73,40 @@ struct chsc_ssd_info {
        u16 fla[8];
 };
 
+struct chsc_ssqd_area {
+       struct chsc_header request;
+       u16:10;
+       u8 ssid:2;
+       u8 fmt:4;
+       u16 first_sch;
+       u16:16;
+       u16 last_sch;
+       u32:32;
+       struct chsc_header response;
+       u32:32;
+       struct qdio_ssqd_desc qdio_ssqd;
+} __packed;
+
+struct chsc_scssc_area {
+       struct chsc_header request;
+       u16 operation_code;
+       u16:16;
+       u32:32;
+       u32:32;
+       u64 summary_indicator_addr;
+       u64 subchannel_indicator_addr;
+       u32 ks:4;
+       u32 kc:4;
+       u32:21;
+       u32 isc:3;
+       u32 word_with_d_bit;
+       u32:32;
+       struct subchannel_id schid;
+       u32 reserved[1004];
+       struct chsc_header response;
+       u32:32;
+} __packed;
+
 struct chsc_scpd {
        struct chsc_header request;
        u32:2;
@@ -116,7 +146,9 @@ int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
 void chsc_chp_online(struct chp_id chpid);
 void chsc_chp_offline(struct chp_id chpid);
 int chsc_get_channel_measurement_chars(struct channel_path *chp);
-
+int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd);
+int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc,
+             u64 summary_indicator_addr, u64 subchannel_indicator_addr);
 int chsc_error_from_response(int response);
 
 int chsc_siosl(struct subchannel_id schid);
index facdf809113f22a6fe9e070b3f8938942bbaf480..7b29d0be0ca33b610443a2059374a54fb0802f26 100644 (file)
 static debug_info_t *chsc_debug_msg_id;
 static debug_info_t *chsc_debug_log_id;
 
+static struct chsc_request *on_close_request;
+static struct chsc_async_area *on_close_chsc_area;
+static DEFINE_MUTEX(on_close_mutex);
+
 #define CHSC_MSG(imp, args...) do {                                    \
                debug_sprintf_event(chsc_debug_msg_id, imp , ##args);   \
        } while (0)
@@ -258,7 +262,7 @@ static int chsc_async(struct chsc_async_area *chsc_area,
                CHSC_LOG(2, "schid");
                CHSC_LOG_HEX(2, &sch->schid, sizeof(sch->schid));
                cc = chsc(chsc_area);
-               sprintf(dbf, "cc:%d", cc);
+               snprintf(dbf, sizeof(dbf), "cc:%d", cc);
                CHSC_LOG(2, dbf);
                switch (cc) {
                case 0:
@@ -287,11 +291,11 @@ static int chsc_async(struct chsc_async_area *chsc_area,
        return ret;
 }
 
-static void chsc_log_command(struct chsc_async_area *chsc_area)
+static void chsc_log_command(void *chsc_area)
 {
        char dbf[10];
 
-       sprintf(dbf, "CHSC:%x", chsc_area->header.code);
+       snprintf(dbf, sizeof(dbf), "CHSC:%x", ((uint16_t *)chsc_area)[1]);
        CHSC_LOG(0, dbf);
        CHSC_LOG_HEX(0, chsc_area, 32);
 }
@@ -355,13 +359,106 @@ static int chsc_ioctl_start(void __user *user_area)
                if (copy_to_user(user_area, chsc_area, PAGE_SIZE))
                        ret = -EFAULT;
 out_free:
-       sprintf(dbf, "ret:%d", ret);
+       snprintf(dbf, sizeof(dbf), "ret:%d", ret);
        CHSC_LOG(0, dbf);
        kfree(request);
        free_page((unsigned long)chsc_area);
        return ret;
 }
 
+static int chsc_ioctl_on_close_set(void __user *user_area)
+{
+       char dbf[13];
+       int ret;
+
+       mutex_lock(&on_close_mutex);
+       if (on_close_chsc_area) {
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       on_close_request = kzalloc(sizeof(*on_close_request), GFP_KERNEL);
+       if (!on_close_request) {
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
+       on_close_chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL);
+       if (!on_close_chsc_area) {
+               ret = -ENOMEM;
+               goto out_free_request;
+       }
+       if (copy_from_user(on_close_chsc_area, user_area, PAGE_SIZE)) {
+               ret = -EFAULT;
+               goto out_free_chsc;
+       }
+       ret = 0;
+       goto out_unlock;
+
+out_free_chsc:
+       free_page((unsigned long)on_close_chsc_area);
+       on_close_chsc_area = NULL;
+out_free_request:
+       kfree(on_close_request);
+       on_close_request = NULL;
+out_unlock:
+       mutex_unlock(&on_close_mutex);
+       snprintf(dbf, sizeof(dbf), "ocsret:%d", ret);
+       CHSC_LOG(0, dbf);
+       return ret;
+}
+
+static int chsc_ioctl_on_close_remove(void)
+{
+       char dbf[13];
+       int ret;
+
+       mutex_lock(&on_close_mutex);
+       if (!on_close_chsc_area) {
+               ret = -ENOENT;
+               goto out_unlock;
+       }
+       free_page((unsigned long)on_close_chsc_area);
+       on_close_chsc_area = NULL;
+       kfree(on_close_request);
+       on_close_request = NULL;
+       ret = 0;
+out_unlock:
+       mutex_unlock(&on_close_mutex);
+       snprintf(dbf, sizeof(dbf), "ocrret:%d", ret);
+       CHSC_LOG(0, dbf);
+       return ret;
+}
+
+static int chsc_ioctl_start_sync(void __user *user_area)
+{
+       struct chsc_sync_area *chsc_area;
+       int ret, ccode;
+
+       chsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!chsc_area)
+               return -ENOMEM;
+       if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+       if (chsc_area->header.code & 0x4000) {
+               ret = -EINVAL;
+               goto out_free;
+       }
+       chsc_log_command(chsc_area);
+       ccode = chsc(chsc_area);
+       if (ccode != 0) {
+               ret = -EIO;
+               goto out_free;
+       }
+       if (copy_to_user(user_area, chsc_area, PAGE_SIZE))
+               ret = -EFAULT;
+       else
+               ret = 0;
+out_free:
+       free_page((unsigned long)chsc_area);
+       return ret;
+}
+
 static int chsc_ioctl_info_channel_path(void __user *user_cd)
 {
        struct chsc_chp_cd *cd;
@@ -795,6 +892,8 @@ static long chsc_ioctl(struct file *filp, unsigned int cmd,
        switch (cmd) {
        case CHSC_START:
                return chsc_ioctl_start(argp);
+       case CHSC_START_SYNC:
+               return chsc_ioctl_start_sync(argp);
        case CHSC_INFO_CHANNEL_PATH:
                return chsc_ioctl_info_channel_path(argp);
        case CHSC_INFO_CU:
@@ -809,14 +908,60 @@ static long chsc_ioctl(struct file *filp, unsigned int cmd,
                return chsc_ioctl_chpd(argp);
        case CHSC_INFO_DCAL:
                return chsc_ioctl_dcal(argp);
+       case CHSC_ON_CLOSE_SET:
+               return chsc_ioctl_on_close_set(argp);
+       case CHSC_ON_CLOSE_REMOVE:
+               return chsc_ioctl_on_close_remove();
        default: /* unknown ioctl number */
                return -ENOIOCTLCMD;
        }
 }
 
+static atomic_t chsc_ready_for_use = ATOMIC_INIT(1);
+
+static int chsc_open(struct inode *inode, struct file *file)
+{
+       if (!atomic_dec_and_test(&chsc_ready_for_use)) {
+               atomic_inc(&chsc_ready_for_use);
+               return -EBUSY;
+       }
+       return nonseekable_open(inode, file);
+}
+
+static int chsc_release(struct inode *inode, struct file *filp)
+{
+       char dbf[13];
+       int ret;
+
+       mutex_lock(&on_close_mutex);
+       if (!on_close_chsc_area)
+               goto out_unlock;
+       init_completion(&on_close_request->completion);
+       CHSC_LOG(0, "on_close");
+       chsc_log_command(on_close_chsc_area);
+       spin_lock_irq(&chsc_lock);
+       ret = chsc_async(on_close_chsc_area, on_close_request);
+       spin_unlock_irq(&chsc_lock);
+       if (ret == -EINPROGRESS) {
+               wait_for_completion(&on_close_request->completion);
+               ret = chsc_examine_irb(on_close_request);
+       }
+       snprintf(dbf, sizeof(dbf), "relret:%d", ret);
+       CHSC_LOG(0, dbf);
+       free_page((unsigned long)on_close_chsc_area);
+       on_close_chsc_area = NULL;
+       kfree(on_close_request);
+       on_close_request = NULL;
+out_unlock:
+       mutex_unlock(&on_close_mutex);
+       atomic_inc(&chsc_ready_for_use);
+       return 0;
+}
+
 static const struct file_operations chsc_fops = {
        .owner = THIS_MODULE,
-       .open = nonseekable_open,
+       .open = chsc_open,
+       .release = chsc_release,
        .unlocked_ioctl = chsc_ioctl,
        .compat_ioctl = chsc_ioctl,
        .llseek = no_llseek,
index 935d80b4e9cedb5361d6d18aab013c73f4eab456..4eeb4a6bf2074cd0f72a988ab6ee5f5ea23cb764 100644 (file)
@@ -568,7 +568,7 @@ out:
  */
 void __irq_entry do_IRQ(struct pt_regs *regs)
 {
-       struct tpi_info *tpi_info;
+       struct tpi_info *tpi_info = (struct tpi_info *) &regs->int_code;
        struct subchannel *sch;
        struct irb *irb;
        struct pt_regs *old_regs;
@@ -579,46 +579,34 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
        if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
                /* Serve timer interrupts first. */
                clock_comparator_work();
-       /*
-        * Get interrupt information from lowcore
-        */
-       tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
-       irb = (struct irb *)&S390_lowcore.irb;
-       do {
-               kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
-               if (tpi_info->adapter_IO) {
-                       do_adapter_IO(tpi_info->isc);
-                       continue;
-               }
-               sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
-               if (!sch) {
-                       /* Clear pending interrupt condition. */
-                       inc_irq_stat(IRQIO_CIO);
-                       tsch(tpi_info->schid, irb);
-                       continue;
-               }
-               spin_lock(sch->lock);
-               /* Store interrupt response block to lowcore. */
-               if (tsch(tpi_info->schid, irb) == 0) {
-                       /* Keep subchannel information word up to date. */
-                       memcpy (&sch->schib.scsw, &irb->scsw,
-                               sizeof (irb->scsw));
-                       /* Call interrupt handler if there is one. */
-                       if (sch->driver && sch->driver->irq)
-                               sch->driver->irq(sch);
-                       else
-                               inc_irq_stat(IRQIO_CIO);
-               } else
+
+       kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
+       irb = (struct irb *) &S390_lowcore.irb;
+       if (tpi_info->adapter_IO) {
+               do_adapter_IO(tpi_info->isc);
+               goto out;
+       }
+       sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
+       if (!sch) {
+               /* Clear pending interrupt condition. */
+               inc_irq_stat(IRQIO_CIO);
+               tsch(tpi_info->schid, irb);
+               goto out;
+       }
+       spin_lock(sch->lock);
+       /* Store interrupt response block to lowcore. */
+       if (tsch(tpi_info->schid, irb) == 0) {
+               /* Keep subchannel information word up to date. */
+               memcpy (&sch->schib.scsw, &irb->scsw, sizeof (irb->scsw));
+               /* Call interrupt handler if there is one. */
+               if (sch->driver && sch->driver->irq)
+                       sch->driver->irq(sch);
+               else
                        inc_irq_stat(IRQIO_CIO);
-               spin_unlock(sch->lock);
-               /*
-                * Are more interrupts pending?
-                * If so, the tpi instruction will update the lowcore
-                * to hold the info for the next interrupt.
-                * We don't do this for VM because a tpi drops the cpu
-                * out of the sie which costs more cycles than it saves.
-                */
-       } while (MACHINE_IS_LPAR && tpi(NULL) != 0);
+       } else
+               inc_irq_stat(IRQIO_CIO);
+       spin_unlock(sch->lock);
+out:
        irq_exit();
        set_irq_regs(old_regs);
 }
index 5132554d7917f0994f543aea947dcdfdcdcb17d4..8acaae18bd11c404d4b6a25e4771846c39e4c837 100644 (file)
@@ -140,40 +140,6 @@ struct siga_flag {
        u8:3;
 } __attribute__ ((packed));
 
-struct chsc_ssqd_area {
-       struct chsc_header request;
-       u16:10;
-       u8 ssid:2;
-       u8 fmt:4;
-       u16 first_sch;
-       u16:16;
-       u16 last_sch;
-       u32:32;
-       struct chsc_header response;
-       u32:32;
-       struct qdio_ssqd_desc qdio_ssqd;
-} __attribute__ ((packed));
-
-struct scssc_area {
-       struct chsc_header request;
-       u16 operation_code;
-       u16:16;
-       u32:32;
-       u32:32;
-       u64 summary_indicator_addr;
-       u64 subchannel_indicator_addr;
-       u32 ks:4;
-       u32 kc:4;
-       u32:21;
-       u32 isc:3;
-       u32 word_with_d_bit;
-       u32:32;
-       struct subchannel_id schid;
-       u32 reserved[1004];
-       struct chsc_header response;
-       u32:32;
-} __attribute__ ((packed));
-
 struct qdio_dev_perf_stat {
        unsigned int adapter_int;
        unsigned int qdio_int;
index 843051bc20f19ab438c568b0cac9a35233db1789..fb1c1e0483ed30213343620da6542ba5ca6b43bb 100644 (file)
@@ -608,50 +608,6 @@ static inline int contains_aobs(struct qdio_q *q)
        return !q->is_input_q && q->u.out.use_cq;
 }
 
-static inline void qdio_trace_aob(struct qdio_irq *irq, struct qdio_q *q,
-                               int i, struct qaob *aob)
-{
-       int tmp;
-
-       DBF_DEV_EVENT(DBF_INFO, irq, "AOB%d:%lx", i,
-                       (unsigned long) virt_to_phys(aob));
-       DBF_DEV_EVENT(DBF_INFO, irq, "RES00:%lx",
-                       (unsigned long) aob->res0[0]);
-       DBF_DEV_EVENT(DBF_INFO, irq, "RES01:%lx",
-                       (unsigned long) aob->res0[1]);
-       DBF_DEV_EVENT(DBF_INFO, irq, "RES02:%lx",
-                       (unsigned long) aob->res0[2]);
-       DBF_DEV_EVENT(DBF_INFO, irq, "RES03:%lx",
-                       (unsigned long) aob->res0[3]);
-       DBF_DEV_EVENT(DBF_INFO, irq, "RES04:%lx",
-                       (unsigned long) aob->res0[4]);
-       DBF_DEV_EVENT(DBF_INFO, irq, "RES05:%lx",
-                       (unsigned long) aob->res0[5]);
-       DBF_DEV_EVENT(DBF_INFO, irq, "RES1:%x", aob->res1);
-       DBF_DEV_EVENT(DBF_INFO, irq, "RES2:%x", aob->res2);
-       DBF_DEV_EVENT(DBF_INFO, irq, "RES3:%x", aob->res3);
-       DBF_DEV_EVENT(DBF_INFO, irq, "AORC:%u", aob->aorc);
-       DBF_DEV_EVENT(DBF_INFO, irq, "FLAGS:%u", aob->flags);
-       DBF_DEV_EVENT(DBF_INFO, irq, "CBTBS:%u", aob->cbtbs);
-       DBF_DEV_EVENT(DBF_INFO, irq, "SBC:%u", aob->sb_count);
-       for (tmp = 0; tmp < QDIO_MAX_ELEMENTS_PER_BUFFER; ++tmp) {
-               DBF_DEV_EVENT(DBF_INFO, irq, "SBA%d:%lx", tmp,
-                               (unsigned long) aob->sba[tmp]);
-               DBF_DEV_EVENT(DBF_INFO, irq, "rSBA%d:%lx", tmp,
-                               (unsigned long) q->sbal[i]->element[tmp].addr);
-               DBF_DEV_EVENT(DBF_INFO, irq, "DC%d:%u", tmp, aob->dcount[tmp]);
-               DBF_DEV_EVENT(DBF_INFO, irq, "rDC%d:%u", tmp,
-                               q->sbal[i]->element[tmp].length);
-       }
-       DBF_DEV_EVENT(DBF_INFO, irq, "USER0:%lx", (unsigned long) aob->user0);
-       for (tmp = 0; tmp < 2; ++tmp) {
-               DBF_DEV_EVENT(DBF_INFO, irq, "RES4%d:%lx", tmp,
-                       (unsigned long) aob->res4[tmp]);
-       }
-       DBF_DEV_EVENT(DBF_INFO, irq, "USER1:%lx", (unsigned long) aob->user1);
-       DBF_DEV_EVENT(DBF_INFO, irq, "USER2:%lx", (unsigned long) aob->user2);
-}
-
 static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count)
 {
        unsigned char state = 0;
index 16ecd35b8e5137dbd675f2e51527224ea0370557..f5f4a91fab44e71b3c7d8ca5e307c19b2b139912 100644 (file)
@@ -254,40 +254,31 @@ int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr,
        int rc;
 
        DBF_EVENT("getssqd:%4x", schid->sch_no);
-       if (irq_ptr != NULL)
-               ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page;
-       else
+       if (!irq_ptr) {
                ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL);
-       memset(ssqd, 0, PAGE_SIZE);
-
-       ssqd->request = (struct chsc_header) {
-               .length = 0x0010,
-               .code   = 0x0024,
-       };
-       ssqd->first_sch = schid->sch_no;
-       ssqd->last_sch = schid->sch_no;
-       ssqd->ssid = schid->ssid;
-
-       if (chsc(ssqd))
-               return -EIO;
-       rc = chsc_error_from_response(ssqd->response.code);
+               if (!ssqd)
+                       return -ENOMEM;
+       } else {
+               ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page;
+       }
+
+       rc = chsc_ssqd(*schid, ssqd);
        if (rc)
-               return rc;
+               goto out;
 
        if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) ||
            !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) ||
            (ssqd->qdio_ssqd.sch != schid->sch_no))
-               return -EINVAL;
-
-       if (irq_ptr != NULL)
-               memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd,
-                      sizeof(struct qdio_ssqd_desc));
-       else {
-               memcpy(data, &ssqd->qdio_ssqd,
-                      sizeof(struct qdio_ssqd_desc));
+               rc = -EINVAL;
+
+       if (!rc)
+               memcpy(data, &ssqd->qdio_ssqd, sizeof(*data));
+
+out:
+       if (!irq_ptr)
                free_page((unsigned long)ssqd);
-       }
-       return 0;
+
+       return rc;
 }
 
 void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr)
@@ -295,7 +286,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr)
        unsigned char qdioac;
        int rc;
 
-       rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL);
+       rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, &irq_ptr->ssqd_desc);
        if (rc) {
                DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no);
                DBF_ERROR("rc:%x", rc);
index bde5255200dc3864687fa955e69440503bd46b4b..5d06253c2a7a385df2a2d951c49992a006d21600 100644 (file)
@@ -36,8 +36,13 @@ struct indicator_t {
 static LIST_HEAD(tiq_list);
 static DEFINE_MUTEX(tiq_list_lock);
 
-/* adapter local summary indicator */
-static u8 *tiqdio_alsi;
+/* Adapter interrupt definitions */
+static void tiqdio_thinint_handler(struct airq_struct *airq);
+
+static struct airq_struct tiqdio_airq = {
+       .handler = tiqdio_thinint_handler,
+       .isc = QDIO_AIRQ_ISC,
+};
 
 static struct indicator_t *q_indicators;
 
@@ -176,7 +181,7 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
  * @alsi: pointer to adapter local summary indicator
  * @data: NULL
  */
-static void tiqdio_thinint_handler(void *alsi, void *data)
+static void tiqdio_thinint_handler(struct airq_struct *airq)
 {
        u32 si_used = clear_shared_ind();
        struct qdio_q *q;
@@ -208,51 +213,31 @@ static void tiqdio_thinint_handler(void *alsi, void *data)
 
 static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset)
 {
-       struct scssc_area *scssc_area;
+       struct chsc_scssc_area *scssc = (void *)irq_ptr->chsc_page;
+       u64 summary_indicator_addr, subchannel_indicator_addr;
        int rc;
 
-       scssc_area = (struct scssc_area *)irq_ptr->chsc_page;
-       memset(scssc_area, 0, PAGE_SIZE);
-
        if (reset) {
-               scssc_area->summary_indicator_addr = 0;
-               scssc_area->subchannel_indicator_addr = 0;
+               summary_indicator_addr = 0;
+               subchannel_indicator_addr = 0;
        } else {
-               scssc_area->summary_indicator_addr = virt_to_phys(tiqdio_alsi);
-               scssc_area->subchannel_indicator_addr =
-                       virt_to_phys(irq_ptr->dsci);
+               summary_indicator_addr = virt_to_phys(tiqdio_airq.lsi_ptr);
+               subchannel_indicator_addr = virt_to_phys(irq_ptr->dsci);
        }
 
-       scssc_area->request = (struct chsc_header) {
-               .length = 0x0fe0,
-               .code   = 0x0021,
-       };
-       scssc_area->operation_code = 0;
-       scssc_area->ks = PAGE_DEFAULT_KEY >> 4;
-       scssc_area->kc = PAGE_DEFAULT_KEY >> 4;
-       scssc_area->isc = QDIO_AIRQ_ISC;
-       scssc_area->schid = irq_ptr->schid;
-
-       /* enable the time delay disablement facility */
-       if (css_general_characteristics.aif_tdd)
-               scssc_area->word_with_d_bit = 0x10000000;
-
-       rc = chsc(scssc_area);
-       if (rc)
-               return -EIO;
-
-       rc = chsc_error_from_response(scssc_area->response.code);
+       rc = chsc_sadc(irq_ptr->schid, scssc, summary_indicator_addr,
+                      subchannel_indicator_addr);
        if (rc) {
                DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no,
-                         scssc_area->response.code);
-               DBF_ERROR_HEX(&scssc_area->response, sizeof(void *));
-               return rc;
+                         scssc->response.code);
+               goto out;
        }
 
        DBF_EVENT("setscind");
-       DBF_HEX(&scssc_area->summary_indicator_addr, sizeof(unsigned long));
-       DBF_HEX(&scssc_area->subchannel_indicator_addr, sizeof(unsigned long));
-       return 0;
+       DBF_HEX(&summary_indicator_addr, sizeof(summary_indicator_addr));
+       DBF_HEX(&subchannel_indicator_addr, sizeof(subchannel_indicator_addr));
+out:
+       return rc;
 }
 
 /* allocate non-shared indicators and shared indicator */
@@ -272,14 +257,12 @@ void tiqdio_free_memory(void)
 
 int __init tiqdio_register_thinints(void)
 {
-       isc_register(QDIO_AIRQ_ISC);
-       tiqdio_alsi = s390_register_adapter_interrupt(&tiqdio_thinint_handler,
-                                                     NULL, QDIO_AIRQ_ISC);
-       if (IS_ERR(tiqdio_alsi)) {
-               DBF_EVENT("RTI:%lx", PTR_ERR(tiqdio_alsi));
-               tiqdio_alsi = NULL;
-               isc_unregister(QDIO_AIRQ_ISC);
-               return -ENOMEM;
+       int rc;
+
+       rc = register_adapter_interrupt(&tiqdio_airq);
+       if (rc) {
+               DBF_EVENT("RTI:%x", rc);
+               return rc;
        }
        return 0;
 }
@@ -312,9 +295,5 @@ void qdio_shutdown_thinint(struct qdio_irq *irq_ptr)
 void __exit tiqdio_unregister_thinints(void)
 {
        WARN_ON(!list_empty(&tiq_list));
-
-       if (tiqdio_alsi) {
-               s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC);
-               isc_unregister(QDIO_AIRQ_ISC);
-       }
+       unregister_adapter_interrupt(&tiqdio_airq);
 }
index 9de41aa148965088c693815fe6ce165d5689414e..f446a7705c3b9fb9a2856b8fc79b82730e897f2b 100644 (file)
@@ -58,7 +58,7 @@ static inline void ap_schedule_poll_timer(void);
 static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags);
 static int ap_device_remove(struct device *dev);
 static int ap_device_probe(struct device *dev);
-static void ap_interrupt_handler(void *unused1, void *unused2);
+static void ap_interrupt_handler(struct airq_struct *airq);
 static void ap_reset(struct ap_device *ap_dev);
 static void ap_config_timeout(unsigned long ptr);
 static int ap_select_domain(void);
@@ -106,7 +106,6 @@ static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait);
 static struct task_struct *ap_poll_kthread = NULL;
 static DEFINE_MUTEX(ap_poll_thread_mutex);
 static DEFINE_SPINLOCK(ap_poll_timer_lock);
-static void *ap_interrupt_indicator;
 static struct hrtimer ap_poll_timer;
 /* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds.
  * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/
@@ -120,13 +119,21 @@ static int ap_suspend_flag;
 static int user_set_domain = 0;
 static struct bus_type ap_bus_type;
 
+/* Adapter interrupt definitions */
+static int ap_airq_flag;
+
+static struct airq_struct ap_airq = {
+       .handler = ap_interrupt_handler,
+       .isc = AP_ISC,
+};
+
 /**
  * ap_using_interrupts() - Returns non-zero if interrupt support is
  * available.
  */
 static inline int ap_using_interrupts(void)
 {
-       return ap_interrupt_indicator != NULL;
+       return ap_airq_flag;
 }
 
 /**
@@ -588,7 +595,7 @@ static int ap_init_queue(ap_qid_t qid)
                }
        }
        if (rc == 0 && ap_using_interrupts()) {
-               rc = ap_queue_enable_interruption(qid, ap_interrupt_indicator);
+               rc = ap_queue_enable_interruption(qid, ap_airq.lsi_ptr);
                /* If interruption mode is supported by the machine,
                * but an AP can not be enabled for interruption then
                * the AP will be discarded.    */
@@ -821,13 +828,22 @@ static int ap_bus_suspend(struct device *dev, pm_message_t state)
 
 static int ap_bus_resume(struct device *dev)
 {
-       int rc = 0;
        struct ap_device *ap_dev = to_ap_dev(dev);
+       int rc;
 
        if (ap_suspend_flag) {
                ap_suspend_flag = 0;
-               if (!ap_interrupts_available())
-                       ap_interrupt_indicator = NULL;
+               if (ap_interrupts_available()) {
+                       if (!ap_using_interrupts()) {
+                               rc = register_adapter_interrupt(&ap_airq);
+                               ap_airq_flag = (rc == 0);
+                       }
+               } else {
+                       if (ap_using_interrupts()) {
+                               unregister_adapter_interrupt(&ap_airq);
+                               ap_airq_flag = 0;
+                       }
+               }
                ap_query_configuration();
                if (!user_set_domain) {
                        ap_domain_index = -1;
@@ -848,7 +864,10 @@ static int ap_bus_resume(struct device *dev)
                        tasklet_schedule(&ap_tasklet);
                if (ap_thread_flag)
                        rc = ap_poll_thread_start();
-       }
+               else
+                       rc = 0;
+       } else
+               rc = 0;
        if (AP_QID_QUEUE(ap_dev->qid) != ap_domain_index) {
                spin_lock_bh(&ap_dev->lock);
                ap_dev->qid = AP_MKQID(AP_QID_DEVICE(ap_dev->qid),
@@ -1266,7 +1285,7 @@ out:
        return rc;
 }
 
-static void ap_interrupt_handler(void *unused1, void *unused2)
+static void ap_interrupt_handler(struct airq_struct *airq)
 {
        inc_irq_stat(IRQIO_APB);
        tasklet_schedule(&ap_tasklet);
@@ -1722,7 +1741,7 @@ static void ap_poll_all(unsigned long dummy)
         * important that no requests on any AP get lost.
         */
        if (ap_using_interrupts())
-               xchg((u8 *)ap_interrupt_indicator, 0);
+               xchg(ap_airq.lsi_ptr, 0);
        do {
                flags = 0;
                spin_lock(&ap_device_list_lock);
@@ -1795,7 +1814,7 @@ static int ap_poll_thread_start(void)
        mutex_lock(&ap_poll_thread_mutex);
        if (!ap_poll_kthread) {
                ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll");
-               rc = IS_ERR(ap_poll_kthread) ? PTR_ERR(ap_poll_kthread) : 0;
+               rc = PTR_RET(ap_poll_kthread);
                if (rc)
                        ap_poll_kthread = NULL;
        }
@@ -1881,13 +1900,8 @@ int __init ap_module_init(void)
                return -ENODEV;
        }
        if (ap_interrupts_available()) {
-               isc_register(AP_ISC);
-               ap_interrupt_indicator = s390_register_adapter_interrupt(
-                       &ap_interrupt_handler, NULL, AP_ISC);
-               if (IS_ERR(ap_interrupt_indicator)) {
-                       ap_interrupt_indicator = NULL;
-                       isc_unregister(AP_ISC);
-               }
+               rc = register_adapter_interrupt(&ap_airq);
+               ap_airq_flag = (rc == 0);
        }
 
        register_reset_call(&ap_reset_call);
@@ -1904,7 +1918,7 @@ int __init ap_module_init(void)
 
        /* Create /sys/devices/ap. */
        ap_root_device = root_device_register("ap");
-       rc = IS_ERR(ap_root_device) ? PTR_ERR(ap_root_device) : 0;
+       rc = PTR_RET(ap_root_device);
        if (rc)
                goto out_bus;
 
@@ -1955,10 +1969,8 @@ out_bus:
        bus_unregister(&ap_bus_type);
 out:
        unregister_reset_call(&ap_reset_call);
-       if (ap_using_interrupts()) {
-               s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC);
-               isc_unregister(AP_ISC);
-       }
+       if (ap_using_interrupts())
+               unregister_adapter_interrupt(&ap_airq);
        return rc;
 }
 
@@ -1994,10 +2006,8 @@ void ap_module_exit(void)
                bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
        bus_unregister(&ap_bus_type);
        unregister_reset_call(&ap_reset_call);
-       if (ap_using_interrupts()) {
-               s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC);
-               isc_unregister(AP_ISC);
-       }
+       if (ap_using_interrupts())
+               unregister_adapter_interrupt(&ap_airq);
 }
 
 module_init(ap_module_init);
index 83bc9c5fa0c190885656955458b342d2265362f9..fd7b3bd807896556d0743660069aff8a44c3e072 100644 (file)
@@ -3348,7 +3348,7 @@ static int __init claw_init(void)
        }
        CLAW_DBF_TEXT(2, setup, "init_mod");
        claw_root_dev = root_device_register("claw");
-       ret = IS_ERR(claw_root_dev) ? PTR_ERR(claw_root_dev) : 0;
+       ret = PTR_RET(claw_root_dev);
        if (ret)
                goto register_err;
        ret = ccw_driver_register(&claw_ccw_driver);
index 676f12049a3693056d58ba216b0f1c3eeacdf92c..70b3a023100ef769180d8234f2ac39c3caa91232 100644 (file)
@@ -1837,7 +1837,7 @@ static int __init ctcm_init(void)
        if (ret)
                goto out_err;
        ctcm_root_dev = root_device_register("ctcm");
-       ret = IS_ERR(ctcm_root_dev) ? PTR_ERR(ctcm_root_dev) : 0;
+       ret = PTR_RET(ctcm_root_dev);
        if (ret)
                goto register_err;
        ret = ccw_driver_register(&ctcm_ccw_driver);
index c645dc9e98af83359d13b4975221a4d609ace853..f404f55b31917a3daac4ea9787e130786ad6b3b8 100644 (file)
@@ -2441,7 +2441,7 @@ __init lcs_init_module(void)
        if (rc)
                goto out_err;
        lcs_root_dev = root_device_register("lcs");
-       rc = IS_ERR(lcs_root_dev) ? PTR_ERR(lcs_root_dev) : 0;
+       rc = PTR_RET(lcs_root_dev);
        if (rc)
                goto register_err;
        rc = ccw_driver_register(&lcs_ccw_driver);
index 6cd0fc1b203a2c6e8147dc37d980933ff9b7e89f..70ce6b6fce3be1648efcc9936136bc8980317c6c 100644 (file)
@@ -5705,7 +5705,7 @@ static int __init qeth_core_init(void)
        if (rc)
                goto out_err;
        qeth_core_root_dev = root_device_register("qeth");
-       rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0;
+       rc = PTR_RET(qeth_core_root_dev);
        if (rc)
                goto register_err;
        qeth_core_header_cache = kmem_cache_create("qeth_hdr",
index e70af2406ff9da388828660bb0bed2b73bf5cb71..d1c8025b0b037605c73f331b6ebd3178feed2767 100644 (file)
@@ -315,10 +315,8 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
        if (qeth_configure_cq(card, QETH_CQ_ENABLED))
                return -EPERM;
 
-       for (i = 0; i < 8; i++)
-               card->options.hsuid[i] = ' ';
-       card->options.hsuid[8] = '\0';
-       strncpy(card->options.hsuid, tmp, strlen(tmp));
+       snprintf(card->options.hsuid, sizeof(card->options.hsuid),
+                "%-8s", tmp);
        ASCEBC(card->options.hsuid, 8);
        if (card->dev)
                memcpy(card->dev->perm_addr, card->options.hsuid, 9);
index c487916a9d45ecd404c1abdaa12d5d2742aeffe9..c0f4f4290dd60dbeb836f547b097ca8b7141eaaf 100644 (file)
@@ -280,18 +280,7 @@ static struct platform_driver amiga_a3000_scsi_driver = {
        },
 };
 
-static int __init amiga_a3000_scsi_init(void)
-{
-       return platform_driver_probe(&amiga_a3000_scsi_driver,
-                                    amiga_a3000_scsi_probe);
-}
-module_init(amiga_a3000_scsi_init);
-
-static void __exit amiga_a3000_scsi_exit(void)
-{
-       platform_driver_unregister(&amiga_a3000_scsi_driver);
-}
-module_exit(amiga_a3000_scsi_exit);
+module_platform_driver_probe(amiga_a3000_scsi_driver, amiga_a3000_scsi_probe);
 
 MODULE_DESCRIPTION("Amiga 3000 built-in SCSI");
 MODULE_LICENSE("GPL");
index 23c76f41883cf46a00bfa5bd00b8b17795be620d..70c521f79f7c26fbc92b65645b780e927c7fcac3 100644 (file)
@@ -116,20 +116,7 @@ static struct platform_driver amiga_a4000t_scsi_driver = {
        },
 };
 
-static int __init amiga_a4000t_scsi_init(void)
-{
-       return platform_driver_probe(&amiga_a4000t_scsi_driver,
-                                    amiga_a4000t_scsi_probe);
-}
-
-module_init(amiga_a4000t_scsi_init);
-
-static void __exit amiga_a4000t_scsi_exit(void)
-{
-       platform_driver_unregister(&amiga_a4000t_scsi_driver);
-}
-
-module_exit(amiga_a4000t_scsi_exit);
+module_platform_driver_probe(amiga_a4000t_scsi_driver, amiga_a4000t_scsi_probe);
 
 MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / "
              "Kars de Jong <jongk@linux-m68k.org>");
index 1ef041bc60c89c17b9f130124e9e1273995adb11..d85ac1a9d2c0698b85c606ab6b2ff917cb0959ed 100644 (file)
@@ -318,7 +318,8 @@ return_fib:
                        kthread_stop(dev->thread);
                        ssleep(1);
                        dev->aif_thread = 0;
-                       dev->thread = kthread_run(aac_command_thread, dev, dev->name);
+                       dev->thread = kthread_run(aac_command_thread, dev,
+                                                 "%s", dev->name);
                        ssleep(1);
                }
                if (f.wait) {
index 1be0776a80c4b00e73b8a914378d1d8c8c79ba58..cab190af63455319ffaf009b486a69664b2a47d9 100644 (file)
@@ -1336,7 +1336,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
                if ((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(32))))
                        goto out;
        if (jafo) {
-               aac->thread = kthread_run(aac_command_thread, aac, aac->name);
+               aac->thread = kthread_run(aac_command_thread, aac, "%s",
+                                         aac->name);
                if (IS_ERR(aac->thread)) {
                        retval = PTR_ERR(aac->thread);
                        goto out;
index d24a2867bc21cb885506f9d35d0fbe397e27400a..a1f5ac7a9806dffb6c7905f15771283ae2766c33 100644 (file)
@@ -4996,7 +4996,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
 
        snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_%02x_wq",
                 phba->shost->host_no);
-       phba->wq = alloc_workqueue(phba->wq_name, WQ_MEM_RECLAIM, 1);
+       phba->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, phba->wq_name);
        if (!phba->wq) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
                            "BM_%d : beiscsi_dev_probe-"
index b63d534192e33a8defea70b6c0195293392ea98e..8e83d0474fe7c57560714dd488d4db1fcc1f4d15 100644 (file)
@@ -173,31 +173,9 @@ bfad_debugfs_open_reg(struct inode *inode, struct file *file)
 static loff_t
 bfad_debugfs_lseek(struct file *file, loff_t offset, int orig)
 {
-       struct bfad_debug_info *debug;
-       loff_t pos = file->f_pos;
-
-       debug = file->private_data;
-
-       switch (orig) {
-       case 0:
-               file->f_pos = offset;
-               break;
-       case 1:
-               file->f_pos += offset;
-               break;
-       case 2:
-               file->f_pos = debug->buffer_len + offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
-               file->f_pos = pos;
-               return -EINVAL;
-       }
-
-       return file->f_pos;
+       struct bfad_debug_info *debug = file->private_data;
+       return fixed_size_llseek(file, offset, orig,
+                               debug->buffer_len);
 }
 
 static ssize_t
index 85e1ffd0e5c5af17e53305ad016f28898d65c8f7..cbcb0121c84de5557852e641bcff6248881480e2 100644 (file)
@@ -164,20 +164,8 @@ static loff_t fnic_trace_debugfs_lseek(struct file *file,
                                        int howto)
 {
        fnic_dbgfs_t *fnic_dbg_prt = file->private_data;
-       loff_t pos = -1;
-
-       switch (howto) {
-       case 0:
-               pos = offset;
-               break;
-       case 1:
-               pos = file->f_pos + offset;
-               break;
-       case 2:
-               pos = fnic_dbg_prt->buffer_len + offset;
-       }
-       return (pos < 0 || pos > fnic_dbg_prt->buffer_len) ?
-                         -EINVAL : (file->f_pos = pos);
+       return fixed_size_llseek(file, offset, howto,
+                               fnic_dbg_prt->buffer_len);
 }
 
 /*
index 6c4cedb44c075fba2ba81999e187e4587901b5f0..168bc7b9f0573a124067ab99e814a0edbf5e6e43 100644 (file)
@@ -6662,7 +6662,6 @@ static bool ipr_qc_fill_rtf(struct ata_queued_cmd *qc)
        tf->hob_lbal = g->hob_lbal;
        tf->hob_lbam = g->hob_lbam;
        tf->hob_lbah = g->hob_lbah;
-       tf->ctl = g->alt_status;
 
        return true;
 }
index f525ecb7a9c6e187bf1097a6baf7aabad96377a4..60084e6ad2f24331c6bab3e74d4869f13a5dca0c 100644 (file)
@@ -1165,22 +1165,8 @@ out:
 static loff_t
 lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
 {
-       struct lpfc_debug *debug;
-       loff_t pos = -1;
-
-       debug = file->private_data;
-
-       switch (whence) {
-       case 0:
-               pos = off;
-               break;
-       case 1:
-               pos = file->f_pos + off;
-               break;
-       case 2:
-               pos = debug->len + off;
-       }
-       return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos);
+       struct lpfc_debug *debug = file->private_data;
+       return fixed_size_llseek(file, off, whence, debug->len);
 }
 
 /**
index 846f475f62c160890835f33a234f85c6a175a222..90c95a3385d18bb52f93093da10c8d400514f712 100644 (file)
@@ -2026,7 +2026,7 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor)
 static inline int
 make_local_pdev(adapter_t *adapter, struct pci_dev **pdev)
 {
-       *pdev = alloc_pci_dev();
+       *pdev = pci_alloc_dev(NULL);
 
        if( *pdev == NULL ) return -1;
 
index 0fab6b5c7b8293da875bce94b5bdca9a9c97e41a..9d86947d67fe25802b5e172fdd60cd2b08486e8e 100644 (file)
@@ -485,7 +485,7 @@ static int osd_probe(struct device *dev)
        oud->class_dev.class = &osd_uld_class;
        oud->class_dev.parent = dev;
        oud->class_dev.release = __remove;
-       error = dev_set_name(&oud->class_dev, disk->disk_name);
+       error = dev_set_name(&oud->class_dev, "%s", disk->disk_name);
        if (error) {
                OSD_ERR("dev_set_name failed => %d\n", error);
                goto err_put_cdev;
index 4d231c12463eb38ad29d5b3c4ca25f4af24d99fa..b246b3c26912a89f88c5738c31c296c3a67c32f9 100644 (file)
@@ -7060,8 +7060,8 @@ skip_retry_init:
        }
        INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
 
-       sprintf(buf, "qla4xxx_%lu_task", ha->host_no);
-       ha->task_wq = alloc_workqueue(buf, WQ_MEM_RECLAIM, 1);
+       ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM, 1,
+                                     ha->host_no);
        if (!ha->task_wq) {
                ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n");
                ret = -ENODEV;
index 42539ee2cb111f0e10a6b152d9a0d60cbb2d895b..4c5aabe21755cb82450876666145f1f2add7ad1f 100644 (file)
@@ -229,8 +229,6 @@ static int scsi_runtime_resume(struct device *dev)
 
 static int scsi_runtime_idle(struct device *dev)
 {
-       int err;
-
        dev_dbg(dev, "scsi_runtime_idle\n");
 
        /* Insert hooks here for targets, hosts, and transport classes */
@@ -240,14 +238,11 @@ static int scsi_runtime_idle(struct device *dev)
 
                if (sdev->request_queue->dev) {
                        pm_runtime_mark_last_busy(dev);
-                       err = pm_runtime_autosuspend(dev);
-               } else {
-                       err = pm_runtime_suspend(dev);
+                       pm_runtime_autosuspend(dev);
+                       return -EBUSY;
                }
-       } else {
-               err = pm_runtime_suspend(dev);
        }
-       return err;
+       return 0;
 }
 
 int scsi_autopm_get_device(struct scsi_device *sdev)
index e106c276aa00275ce1564ed5cccba739e62d6804..4628fd5e068859c4cec9cead369cb9a67a9409c8 100644 (file)
@@ -435,7 +435,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
 
        snprintf(fc_host->work_q_name, sizeof(fc_host->work_q_name),
                 "fc_wq_%d", shost->host_no);
-       fc_host->work_q = alloc_workqueue(fc_host->work_q_name, 0, 0);
+       fc_host->work_q = alloc_workqueue("%s", 0, 0, fc_host->work_q_name);
        if (!fc_host->work_q)
                return -ENOMEM;
 
@@ -443,8 +443,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
        snprintf(fc_host->devloss_work_q_name,
                 sizeof(fc_host->devloss_work_q_name),
                 "fc_dl_%d", shost->host_no);
-       fc_host->devloss_work_q =
-                       alloc_workqueue(fc_host->devloss_work_q_name, 0, 0);
+       fc_host->devloss_work_q = alloc_workqueue("%s", 0, 0,
+                                       fc_host->devloss_work_q_name);
        if (!fc_host->devloss_work_q) {
                destroy_workqueue(fc_host->work_q);
                fc_host->work_q = NULL;
index c1c555242d0d715d46c051955deacea4a819d634..8fa3d0b73ad9bf42164f9e4fbd633fb056018736 100644 (file)
@@ -2931,7 +2931,7 @@ static int sd_probe(struct device *dev)
        device_initialize(&sdkp->dev);
        sdkp->dev.parent = dev;
        sdkp->dev.class = &sd_disk_class;
-       dev_set_name(&sdkp->dev, dev_name(dev));
+       dev_set_name(&sdkp->dev, "%s", dev_name(dev));
 
        if (device_add(&sdkp->dev))
                goto out_free_index;
index 7715de2629c104de4e98a87836ea2ef308a743c4..74727851820df42e5b6471a0799357ad66e850e1 100644 (file)
@@ -63,12 +63,12 @@ void clk_rate_table_build(struct clk *clk,
                else
                        freq = clk->parent->rate * mult / div;
 
-               freq_table[i].index = i;
+               freq_table[i].driver_data = i;
                freq_table[i].frequency = freq;
        }
 
        /* Termination entry */
-       freq_table[i].index = i;
+       freq_table[i].driver_data = i;
        freq_table[i].frequency = CPUFREQ_TABLE_END;
 }
 
index afe9282629b900262da4e8ea178f3f6816b771bd..8afa5a4589f2dd03771acaac8be585447e8033c0 100644 (file)
@@ -25,7 +25,7 @@
 static int default_platform_runtime_idle(struct device *dev)
 {
        /* suspend synchronously to disable clocks immediately */
-       return pm_runtime_suspend(dev);
+       return 0;
 }
 
 static struct dev_pm_domain default_pm_domain = {
index a537f8dffc095b56e4658e2a7c703ba3a809428c..8a6bb37910dabeb018c4fab0bcd68d3936456aa8 100644 (file)
@@ -103,16 +103,6 @@ static void altera_spi_chipsel(struct spi_device *spi, int value)
        }
 }
 
-static int altera_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
-{
-       return 0;
-}
-
-static int altera_spi_setup(struct spi_device *spi)
-{
-       return 0;
-}
-
 static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
 {
        if (hw->tx) {
@@ -231,7 +221,6 @@ static int altera_spi_probe(struct platform_device *pdev)
        master->bus_num = pdev->id;
        master->num_chipselect = 16;
        master->mode_bits = SPI_CS_HIGH;
-       master->setup = altera_spi_setup;
 
        hw = spi_master_get_devdata(master);
        platform_set_drvdata(pdev, hw);
@@ -240,7 +229,6 @@ static int altera_spi_probe(struct platform_device *pdev)
        hw->bitbang.master = spi_master_get(master);
        if (!hw->bitbang.master)
                return err;
-       hw->bitbang.setup_transfer = altera_spi_setupxfer;
        hw->bitbang.chipselect = altera_spi_chipsel;
        hw->bitbang.txrx_bufs = altera_spi_txrx;
 
@@ -285,7 +273,6 @@ static int altera_spi_probe(struct platform_device *pdev)
 exit_busy:
        err = -EBUSY;
 exit:
-       platform_set_drvdata(pdev, NULL);
        spi_master_put(master);
        return err;
 }
@@ -296,7 +283,6 @@ static int altera_spi_remove(struct platform_device *dev)
        struct spi_master *master = hw->bitbang.master;
 
        spi_bitbang_stop(&hw->bitbang);
-       platform_set_drvdata(dev, NULL);
        spi_master_put(master);
        return 0;
 }
index e504b7636058b4aa31789c26a1be8752a531456b..0e06407a4670b14ac1ea7b40024f9092df5d0443 100644 (file)
@@ -155,9 +155,6 @@ static int ath79_spi_setup(struct spi_device *spi)
 {
        int status = 0;
 
-       if (spi->bits_per_word > 32)
-               return -EINVAL;
-
        if (!spi->controller_state) {
                status = ath79_spi_setup_cs(spi);
                if (status)
@@ -226,6 +223,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
 
        pdata = pdev->dev.platform_data;
 
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
        master->setup = ath79_spi_setup;
        master->cleanup = ath79_spi_cleanup;
        if (pdata) {
@@ -287,7 +285,6 @@ err_clk_put:
 err_unmap:
        iounmap(sp->base);
 err_put_master:
-       platform_set_drvdata(pdev, NULL);
        spi_master_put(sp->bitbang.master);
 
        return ret;
@@ -302,7 +299,6 @@ static int ath79_spi_remove(struct platform_device *pdev)
        clk_disable(sp->clk);
        clk_put(sp->clk);
        iounmap(sp->base);
-       platform_set_drvdata(pdev, NULL);
        spi_master_put(sp->bitbang.master);
 
        return 0;
index 380387a47b1d86fe4e6a8a7ef22a537bfb85517a..ea1ec009f44d3573b96e582dad2608c14c841f3f 100644 (file)
@@ -424,10 +424,15 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,
        return err;
 }
 
-static bool filter(struct dma_chan *chan, void *slave)
+static bool filter(struct dma_chan *chan, void *pdata)
 {
-       struct  at_dma_slave *sl = slave;
+       struct atmel_spi_dma *sl_pdata = pdata;
+       struct at_dma_slave *sl;
 
+       if (!sl_pdata)
+               return false;
+
+       sl = &sl_pdata->dma_slave;
        if (sl->dma_dev == chan->device->dev) {
                chan->private = sl;
                return true;
@@ -438,24 +443,31 @@ static bool filter(struct dma_chan *chan, void *slave)
 
 static int atmel_spi_configure_dma(struct atmel_spi *as)
 {
-       struct at_dma_slave *sdata = &as->dma.dma_slave;
        struct dma_slave_config slave_config;
+       struct device *dev = &as->pdev->dev;
        int err;
 
-       if (sdata && sdata->dma_dev) {
-               dma_cap_mask_t mask;
+       dma_cap_mask_t mask;
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
 
-               /* Try to grab two DMA channels */
-               dma_cap_zero(mask);
-               dma_cap_set(DMA_SLAVE, mask);
-               as->dma.chan_tx = dma_request_channel(mask, filter, sdata);
-               if (as->dma.chan_tx)
-                       as->dma.chan_rx =
-                               dma_request_channel(mask, filter, sdata);
+       as->dma.chan_tx = dma_request_slave_channel_compat(mask, filter,
+                                                          &as->dma,
+                                                          dev, "tx");
+       if (!as->dma.chan_tx) {
+               dev_err(dev,
+                       "DMA TX channel not available, SPI unable to use DMA\n");
+               err = -EBUSY;
+               goto error;
        }
-       if (!as->dma.chan_rx || !as->dma.chan_tx) {
-               dev_err(&as->pdev->dev,
-                       "DMA channel not available, SPI unable to use DMA\n");
+
+       as->dma.chan_rx = dma_request_slave_channel_compat(mask, filter,
+                                                          &as->dma,
+                                                          dev, "rx");
+
+       if (!as->dma.chan_rx) {
+               dev_err(dev,
+                       "DMA RX channel not available, SPI unable to use DMA\n");
                err = -EBUSY;
                goto error;
        }
@@ -1268,13 +1280,6 @@ static int atmel_spi_setup(struct spi_device *spi)
                return -EINVAL;
        }
 
-       if (bits < 8 || bits > 16) {
-               dev_dbg(&spi->dev,
-                               "setup: invalid bits_per_word %u (8 to 16)\n",
-                               bits);
-               return -EINVAL;
-       }
-
        /* see notes above re chipselect */
        if (!atmel_spi_is_v2(as)
                        && spi->chip_select == 0
@@ -1515,7 +1520,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
 
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
-
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
        master->dev.of_node = pdev->dev.of_node;
        master->bus_num = pdev->id;
        master->num_chipselect = master->dev.of_node ? 0 : 4;
index 44dd34b6ad09f796a8eb660c35dd87c4d350c4fc..e1965553ab799b7c77cdf8a5fe8e18b727bb7c05 100644 (file)
@@ -248,11 +248,6 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
                        hz = t->speed_hz;
        }
 
-       if (bpw < 4 || bpw > 24) {
-               dev_err(&spi->dev, "setupxfer: invalid bits_per_word=%d\n",
-                       bpw);
-               return -EINVAL;
-       }
        if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
                dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n",
                        hz);
@@ -296,12 +291,6 @@ static int au1550_spi_setup(struct spi_device *spi)
 {
        struct au1550_spi *hw = spi_master_get_devdata(spi->master);
 
-       if (spi->bits_per_word < 4 || spi->bits_per_word > 24) {
-               dev_err(&spi->dev, "setup: invalid bits_per_word=%d\n",
-                       spi->bits_per_word);
-               return -EINVAL;
-       }
-
        if (spi->max_speed_hz == 0)
                spi->max_speed_hz = hw->freq_max;
        if (spi->max_speed_hz > hw->freq_max
@@ -782,6 +771,7 @@ static int au1550_spi_probe(struct platform_device *pdev)
 
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 24);
 
        hw = spi_master_get_devdata(master);
 
@@ -987,8 +977,6 @@ static int au1550_spi_remove(struct platform_device *pdev)
                au1xxx_dbdma_chan_free(hw->dma_tx_ch);
        }
 
-       platform_set_drvdata(pdev, NULL);
-
        spi_master_put(hw->master);
        return 0;
 }
index 89c0b5033114b2d605b7f99cd1b84d6ae6678be6..a4185e492321b9261072d98226be0ddd5cd752c0 100644 (file)
@@ -331,10 +331,9 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
                goto out_master_put;
        }
 
-       bs->regs = devm_request_and_ioremap(&pdev->dev, res);
-       if (!bs->regs) {
-               dev_err(&pdev->dev, "could not request/map memory region\n");
-               err = -ENODEV;
+       bs->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(bs->regs)) {
+               err = PTR_ERR(bs->regs);
                goto out_master_put;
        }
 
index a4ec5f4ec8175ef16d4746c2f34a533ac3f5697a..9fd7a39b8029e2d630161a278879965f5abb9407 100644 (file)
@@ -124,17 +124,6 @@ static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
 /* the spi->mode bits understood by this driver: */
 #define MODEBITS (SPI_CPOL | SPI_CPHA)
 
-static int bcm63xx_spi_setup(struct spi_device *spi)
-{
-       if (spi->bits_per_word != 8) {
-               dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
-                       __func__, spi->bits_per_word);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
                                unsigned int num_transfers)
 {
@@ -277,13 +266,6 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master,
         * full-duplex transfers.
         */
        list_for_each_entry(t, &m->transfers, transfer_list) {
-               if (t->bits_per_word != 8) {
-                       dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
-                               __func__, t->bits_per_word);
-                       status = -EINVAL;
-                       goto exit;
-               }
-
                if (!first)
                        first = t;
 
@@ -430,11 +412,11 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
 
        master->bus_num = pdata->bus_num;
        master->num_chipselect = pdata->num_chipselect;
-       master->setup = bcm63xx_spi_setup;
        master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer;
        master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer;
        master->transfer_one_message = bcm63xx_spi_transfer_one;
        master->mode_bits = MODEBITS;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
        bs->msg_type_shift = pdata->msg_type_shift;
        bs->msg_ctl_width = pdata->msg_ctl_width;
        bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
@@ -469,7 +451,6 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
 out_clk_disable:
        clk_disable_unprepare(clk);
 out_err:
-       platform_set_drvdata(pdev, NULL);
        spi_master_put(master);
 out_clk:
        clk_put(clk);
@@ -491,8 +472,6 @@ static int bcm63xx_spi_remove(struct platform_device *pdev)
        clk_disable_unprepare(bs->clk);
        clk_put(bs->clk);
 
-       platform_set_drvdata(pdev, 0);
-
        spi_master_put(master);
 
        return 0;
index 39b0d1711b4e952fddcad68affd04ee103cdb47e..07ec597f9732cb3a7324d39f02747ad1979b601a 100644 (file)
@@ -417,7 +417,7 @@ bfin_sport_spi_pump_transfers(unsigned long data)
 
        /* Bits per word setup */
        bits_per_word = transfer->bits_per_word;
-       if (bits_per_word % 16 == 0)
+       if (bits_per_word == 16)
                drv_data->ops = &bfin_sport_transfer_ops_u16;
        else
                drv_data->ops = &bfin_sport_transfer_ops_u8;
@@ -600,13 +600,6 @@ bfin_sport_spi_setup(struct spi_device *spi)
                }
        }
 
-       if (spi->bits_per_word % 8) {
-               dev_err(&spi->dev, "%d bits_per_word is not supported\n",
-                               spi->bits_per_word);
-               ret = -EINVAL;
-               goto error;
-       }
-
        /* translate common spi framework into our register
         * following configure contents are same for tx and rx.
         */
@@ -778,6 +771,7 @@ static int bfin_sport_spi_probe(struct platform_device *pdev)
        drv_data->pin_req = platform_info->pin_req;
 
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+       master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
        master->bus_num = pdev->id;
        master->num_chipselect = platform_info->num_chipselect;
        master->cleanup = bfin_sport_spi_cleanup;
@@ -882,9 +876,6 @@ static int bfin_sport_spi_remove(struct platform_device *pdev)
 
        peripheral_free_list(drv_data->pin_req);
 
-       /* Prevent double remove */
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 317f564c899c3ba93e0ee558b094ea5e4c8d0743..59a73424419c8935c3428fea06247c08ced2d614 100644 (file)
@@ -643,21 +643,16 @@ static void bfin_spi_pump_transfers(unsigned long data)
 
        /* Bits per word setup */
        bits_per_word = transfer->bits_per_word;
-       if (bits_per_word % 16 == 0) {
+       if (bits_per_word == 16) {
                drv_data->n_bytes = bits_per_word/8;
                drv_data->len = (transfer->len) >> 1;
                cr_width = BIT_CTL_WORDSIZE;
                drv_data->ops = &bfin_bfin_spi_transfer_ops_u16;
-       } else if (bits_per_word % 8 == 0) {
+       } else if (bits_per_word == 8) {
                drv_data->n_bytes = bits_per_word/8;
                drv_data->len = transfer->len;
                cr_width = 0;
                drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
-       } else {
-               dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n");
-               message->status = -EINVAL;
-               bfin_spi_giveback(drv_data);
-               return;
        }
        cr = bfin_read(&drv_data->regs->ctl) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE);
        cr |= cr_width;
@@ -808,13 +803,13 @@ static void bfin_spi_pump_transfers(unsigned long data)
                        bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val);
                else {
                        int loop;
-                       if (bits_per_word % 16 == 0) {
+                       if (bits_per_word == 16) {
                                u16 *buf = (u16 *)drv_data->tx;
                                for (loop = 0; loop < bits_per_word / 16;
                                                loop++) {
                                        bfin_write(&drv_data->regs->tdbr, *buf++);
                                }
-                       } else if (bits_per_word % 8 == 0) {
+                       } else if (bits_per_word == 8) {
                                u8 *buf = (u8 *)drv_data->tx;
                                for (loop = 0; loop < bits_per_word / 8; loop++)
                                        bfin_write(&drv_data->regs->tdbr, *buf++);
@@ -1033,12 +1028,6 @@ static int bfin_spi_setup(struct spi_device *spi)
                chip->ctl_reg &= bfin_ctl_reg;
        }
 
-       if (spi->bits_per_word % 8) {
-               dev_err(&spi->dev, "%d bits_per_word is not supported\n",
-                               spi->bits_per_word);
-               goto error;
-       }
-
        /* translate common spi framework into our register */
        if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
                dev_err(&spi->dev, "unsupported spi modes detected\n");
@@ -1299,7 +1288,7 @@ static int bfin_spi_probe(struct platform_device *pdev)
 
        /* the spi->mode bits supported by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
-
+       master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
        master->bus_num = pdev->id;
        master->num_chipselect = platform_info->num_chipselect;
        master->cleanup = bfin_spi_cleanup;
@@ -1418,9 +1407,6 @@ static int bfin_spi_remove(struct platform_device *pdev)
 
        peripheral_free_list(drv_data->pin_req);
 
-       /* Prevent double remove */
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index a11cbf02691a88564ea8b8b33331453a7163b72a..17965fe225ccd4cf50aef85235466468b0de049a 100644 (file)
@@ -42,12 +42,6 @@ static int spi_clps711x_setup(struct spi_device *spi)
 {
        struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
 
-       if (spi->bits_per_word != 8) {
-               dev_err(&spi->dev, "Unsupported master bus width %i\n",
-                       spi->bits_per_word);
-               return -EINVAL;
-       }
-
        /* We are expect that SPI-device is not selected */
        gpio_direction_output(hw->chipselect[spi->chip_select],
                              !(spi->mode & SPI_CS_HIGH));
@@ -190,6 +184,7 @@ static int spi_clps711x_probe(struct platform_device *pdev)
 
        master->bus_num = pdev->id;
        master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
        master->num_chipselect = pdata->num_chipselect;
        master->setup = spi_clps711x_setup;
        master->transfer_one_message = spi_clps711x_transfer_one_message;
@@ -254,7 +249,6 @@ err_out:
                if (gpio_is_valid(hw->chipselect[i]))
                        gpio_free(hw->chipselect[i]);
 
-       platform_set_drvdata(pdev, NULL);
        spi_master_put(master);
        kfree(master);
 
@@ -274,7 +268,6 @@ static int spi_clps711x_remove(struct platform_device *pdev)
                        gpio_free(hw->chipselect[i]);
 
        devm_clk_put(&pdev->dev, hw->spi_clk);
-       platform_set_drvdata(pdev, NULL);
        spi_unregister_master(master);
        kfree(master);
 
index 7b5cc9e4e94d6a355962fca0afe05d3a3837339b..0631b9d4a5de7eb70d9e15fa3f701b9f8bb59c70 100644 (file)
@@ -312,10 +312,7 @@ static int mcfqspi_transfer_one_message(struct spi_master *master,
                bool cs_high = spi->mode & SPI_CS_HIGH;
                u16 qmr = MCFQSPI_QMR_MSTR;
 
-               if (t->bits_per_word)
-                       qmr |= t->bits_per_word << 10;
-               else
-                       qmr |= spi->bits_per_word << 10;
+               qmr |= t->bits_per_word << 10;
                if (spi->mode & SPI_CPHA)
                        qmr |= MCFQSPI_QMR_CPHA;
                if (spi->mode & SPI_CPOL)
@@ -377,11 +374,6 @@ static int mcfqspi_unprepare_transfer_hw(struct spi_master *master)
 
 static int mcfqspi_setup(struct spi_device *spi)
 {
-       if ((spi->bits_per_word < 8) || (spi->bits_per_word > 16)) {
-               dev_dbg(&spi->dev, "%d bits per word is not supported\n",
-                       spi->bits_per_word);
-               return -EINVAL;
-       }
        if (spi->chip_select >= spi->master->num_chipselect) {
                dev_dbg(&spi->dev, "%d chip select is out of range\n",
                        spi->chip_select);
@@ -408,6 +400,12 @@ static int mcfqspi_probe(struct platform_device *pdev)
        struct mcfqspi_platform_data *pdata;
        int status;
 
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_dbg(&pdev->dev, "platform data is missing\n");
+               return -ENOENT;
+       }
+
        master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
        if (master == NULL) {
                dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
@@ -458,11 +456,6 @@ static int mcfqspi_probe(struct platform_device *pdev)
        }
        clk_enable(mcfqspi->clk);
 
-       pdata = pdev->dev.platform_data;
-       if (!pdata) {
-               dev_dbg(&pdev->dev, "platform data is missing\n");
-               goto fail4;
-       }
        master->bus_num = pdata->bus_num;
        master->num_chipselect = pdata->num_chipselect;
 
@@ -477,6 +470,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
        mcfqspi->dev = &pdev->dev;
 
        master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
        master->setup = mcfqspi_setup;
        master->transfer_one_message = mcfqspi_transfer_one_message;
        master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw;
@@ -524,7 +518,6 @@ static int mcfqspi_remove(struct platform_device *pdev)
        /* disable the hardware (set the baud rate to 0) */
        mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
 
-       platform_set_drvdata(pdev, NULL);
        mcfqspi_cs_teardown(mcfqspi);
        clk_disable(mcfqspi->clk);
        clk_put(mcfqspi->clk);
index 50b13c9b1ab691fd5defcae44b98dc4bfccb5557..222d3e37fc283b95dc5932570c1dec874cec78e2 100644 (file)
@@ -299,16 +299,15 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
         * Assign function pointer to appropriate transfer method
         * 8bit, 16bit or 32bit transfer
         */
-       if (bits_per_word <= 8 && bits_per_word >= 2) {
+       if (bits_per_word <= 8) {
                dspi->get_rx = davinci_spi_rx_buf_u8;
                dspi->get_tx = davinci_spi_tx_buf_u8;
                dspi->bytes_per_word[spi->chip_select] = 1;
-       } else if (bits_per_word <= 16 && bits_per_word >= 2) {
+       } else {
                dspi->get_rx = davinci_spi_rx_buf_u16;
                dspi->get_tx = davinci_spi_tx_buf_u16;
                dspi->bytes_per_word[spi->chip_select] = 2;
-       } else
-               return -EINVAL;
+       }
 
        if (!hz)
                hz = spi->max_speed_hz;
@@ -865,7 +864,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
                goto err;
        }
 
-       dev_set_drvdata(&pdev->dev, master);
+       platform_set_drvdata(pdev, master);
 
        dspi = spi_master_get_devdata(master);
        if (dspi == NULL) {
@@ -933,6 +932,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
        master->dev.of_node = pdev->dev.of_node;
        master->bus_num = pdev->id;
        master->num_chipselect = pdata->num_chipselect;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
        master->setup = davinci_spi_setup;
 
        dspi->bitbang.chipselect = davinci_spi_chipselect;
@@ -1044,7 +1044,7 @@ static int davinci_spi_remove(struct platform_device *pdev)
        struct spi_master *master;
        struct resource *r;
 
-       master = dev_get_drvdata(&pdev->dev);
+       master = platform_get_drvdata(pdev);
        dspi = spi_master_get_devdata(master);
 
        spi_bitbang_stop(&dspi->bitbang);
index 4a6d5c9057a4428f61fb5937a01b40bec9b90ec0..4aa8be865cc06ae81d1145161086a89c9846723e 100644 (file)
@@ -111,8 +111,6 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
        struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
        struct resource *mem;
 
-       platform_set_drvdata(pdev, NULL);
-
        clk_disable(dwsmmio->clk);
        clk_put(dwsmmio->clk);
        dwsmmio->clk = NULL;
index c1abc06899e72d7e6fce929acacf4b0f85caeb35..79c958e49f6110a33385d99b3116245028c6c264 100644 (file)
@@ -457,19 +457,7 @@ static void pump_transfers(unsigned long data)
        }
        if (transfer->bits_per_word) {
                bits = transfer->bits_per_word;
-
-               switch (bits) {
-               case 8:
-               case 16:
-                       dws->n_bytes = dws->dma_width = bits >> 3;
-                       break;
-               default:
-                       printk(KERN_ERR "MRST SPI0: unsupported bits:"
-                               "%db\n", bits);
-                       message->status = -EIO;
-                       goto early_exit;
-               }
-
+               dws->n_bytes = dws->dma_width = bits >> 3;
                cr0 = (bits - 1)
                        | (chip->type << SPI_FRF_OFFSET)
                        | (spi->mode << SPI_MODE_OFFSET)
@@ -629,9 +617,6 @@ static int dw_spi_setup(struct spi_device *spi)
        struct dw_spi_chip *chip_info = NULL;
        struct chip_data *chip;
 
-       if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
-               return -EINVAL;
-
        /* Only alloc on first setup */
        chip = spi_get_ctldata(spi);
        if (!chip) {
@@ -660,16 +645,12 @@ static int dw_spi_setup(struct spi_device *spi)
                chip->enable_dma = chip_info->enable_dma;
        }
 
-       if (spi->bits_per_word <= 8) {
+       if (spi->bits_per_word == 8) {
                chip->n_bytes = 1;
                chip->dma_width = 1;
-       } else if (spi->bits_per_word <= 16) {
+       } else if (spi->bits_per_word == 16) {
                chip->n_bytes = 2;
                chip->dma_width = 2;
-       } else {
-               /* Never take >16b case for MRST SPIC */
-               dev_err(&spi->dev, "invalid wordsize\n");
-               return -EINVAL;
        }
        chip->bits_per_word = spi->bits_per_word;
 
@@ -824,6 +805,7 @@ int dw_spi_add_host(struct dw_spi *dws)
        }
 
        master->mode_bits = SPI_CPOL | SPI_CPHA;
+       master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
        master->bus_num = dws->bus_num;
        master->num_chipselect = dws->num_cs;
        master->cleanup = dw_spi_cleanup;
index d7bac60253c9c92cd2b542b9a17e8bd9d4088291..cad30b8a1d71cb7b573879ae21814c49758419a3 100644 (file)
@@ -296,12 +296,6 @@ static int ep93xx_spi_setup(struct spi_device *spi)
        struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
        struct ep93xx_spi_chip *chip;
 
-       if (spi->bits_per_word < 4 || spi->bits_per_word > 16) {
-               dev_err(&espi->pdev->dev, "invalid bits per word %d\n",
-                       spi->bits_per_word);
-               return -EINVAL;
-       }
-
        chip = spi_get_ctldata(spi);
        if (!chip) {
                dev_dbg(&espi->pdev->dev, "initial setup for %s\n",
@@ -365,10 +359,6 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 
        /* first validate each transfer */
        list_for_each_entry(t, &msg->transfers, transfer_list) {
-               if (t->bits_per_word) {
-                       if (t->bits_per_word < 4 || t->bits_per_word > 16)
-                               return -EINVAL;
-               }
                if (t->speed_hz && t->speed_hz < espi->min_rate)
                                return -EINVAL;
        }
@@ -1046,6 +1036,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
        master->bus_num = pdev->id;
        master->num_chipselect = info->num_chipselect;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
 
        platform_set_drvdata(pdev, master);
 
@@ -1104,6 +1095,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
        espi->wq = create_singlethread_workqueue("ep93xx_spid");
        if (!espi->wq) {
                dev_err(&pdev->dev, "unable to create workqueue\n");
+               error = -ENOMEM;
                goto fail_free_dma;
        }
        INIT_WORK(&espi->msg_work, ep93xx_spi_work);
@@ -1132,7 +1124,6 @@ fail_put_clock:
        clk_put(espi->clk);
 fail_release_master:
        spi_master_put(master);
-       platform_set_drvdata(pdev, NULL);
 
        return error;
 }
@@ -1167,7 +1158,6 @@ static int ep93xx_spi_remove(struct platform_device *pdev)
 
        ep93xx_spi_release_dma(espi);
        clk_put(espi->clk);
-       platform_set_drvdata(pdev, NULL);
 
        spi_unregister_master(master);
        return 0;
index 24610ca8955da2544e9a55cce30edf6081804f2b..6a74d7848d93febe8ccb2007fa5af63c46de4ea1 100644 (file)
@@ -144,10 +144,6 @@ static int fsl_espi_setup_transfer(struct spi_device *spi,
        if (!bits_per_word)
                bits_per_word = spi->bits_per_word;
 
-       /* Make sure its a bit width we support [4..16] */
-       if ((bits_per_word < 4) || (bits_per_word > 16))
-               return -EINVAL;
-
        if (!hz)
                hz = spi->max_speed_hz;
 
@@ -157,12 +153,10 @@ static int fsl_espi_setup_transfer(struct spi_device *spi,
        cs->get_tx = mpc8xxx_spi_tx_buf_u32;
        if (bits_per_word <= 8) {
                cs->rx_shift = 8 - bits_per_word;
-       } else if (bits_per_word <= 16) {
+       } else {
                cs->rx_shift = 16 - bits_per_word;
                if (spi->mode & SPI_LSB_FIRST)
                        cs->get_tx = fsl_espi_tx_buf_lsb;
-       } else {
-               return -EINVAL;
        }
 
        mpc8xxx_spi->rx_shift = cs->rx_shift;
@@ -609,6 +603,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
        if (ret)
                goto err_probe;
 
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
        master->setup = fsl_espi_setup;
 
        mpc8xxx_spi = spi_master_get_devdata(master);
index a91db0e57b235385e76df7968e7c1f43345e47d5..e947f2d1b2f5a0814f03e561bd389c4b70030127 100644 (file)
@@ -61,7 +61,7 @@ struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata)
        return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
 }
 
-void mpc8xxx_spi_work(struct work_struct *work)
+static void mpc8xxx_spi_work(struct work_struct *work)
 {
        struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
                                                       work);
index 14e202ee70363832f439b073fffd6ac4b36eaa3f..41e89c3e3edcdd7c1b60b90345afaf6933f5e6c2 100644 (file)
@@ -853,7 +853,7 @@ err:
 
 static int of_fsl_spi_remove(struct platform_device *ofdev)
 {
-       struct spi_master *master = dev_get_drvdata(&ofdev->dev);
+       struct spi_master *master = platform_get_drvdata(ofdev);
        struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
        int ret;
 
index 0021fc4c45bc2f4c9bb0e676bc6cab2fc3b5f02d..a54524cf42cc42689726547818fc55a33e3a1a94 100644 (file)
@@ -239,9 +239,6 @@ static int spi_gpio_setup(struct spi_device *spi)
        struct spi_gpio         *spi_gpio = spi_to_spi_gpio(spi);
        struct device_node      *np = spi->master->dev.of_node;
 
-       if (spi->bits_per_word > 32)
-               return -EINVAL;
-
        if (np) {
                /*
                 * In DT environments, the CS GPIOs have already been
@@ -446,6 +443,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
        if (pdata)
                spi_gpio->pdata = *pdata;
 
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
        master->flags = master_flags;
        master->bus_num = pdev->id;
        master->num_chipselect = SPI_N_CHIPSEL;
@@ -514,8 +512,6 @@ static int spi_gpio_remove(struct platform_device *pdev)
        status = spi_bitbang_stop(&spi_gpio->bitbang);
        spi_master_put(spi_gpio->bitbang.master);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
                gpio_free(SPI_MISO_GPIO);
        if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
index 0befeeb522f47ab633b1d54b76cf780902d2ae2b..7db4f43ee4d840c30514fe322cc871556071236c 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
-#include <linux/pinctrl/consumer.h>
 
 #include <linux/platform_data/spi-imx.h>
 
@@ -698,11 +697,10 @@ static int spi_imx_setupxfer(struct spi_device *spi,
        } else if (config.bpw <= 16) {
                spi_imx->rx = spi_imx_buf_rx_u16;
                spi_imx->tx = spi_imx_buf_tx_u16;
-       } else if (config.bpw <= 32) {
+       } else {
                spi_imx->rx = spi_imx_buf_rx_u32;
                spi_imx->tx = spi_imx_buf_tx_u32;
-       } else
-               BUG();
+       }
 
        spi_imx->devtype_data->config(spi_imx, &config);
 
@@ -760,7 +758,6 @@ static int spi_imx_probe(struct platform_device *pdev)
        struct spi_master *master;
        struct spi_imx_data *spi_imx;
        struct resource *res;
-       struct pinctrl *pinctrl;
        int i, ret, num_cs;
 
        if (!np && !mxc_platform_info) {
@@ -783,6 +780,7 @@ static int spi_imx_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, master);
 
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
        master->bus_num = pdev->id;
        master->num_chipselect = num_cs;
 
@@ -848,12 +846,6 @@ static int spi_imx_probe(struct platform_device *pdev)
                goto out_iounmap;
        }
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               ret = PTR_ERR(pinctrl);
-               goto out_free_irq;
-       }
-
        spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(spi_imx->clk_ipg)) {
                ret = PTR_ERR(spi_imx->clk_ipg);
@@ -902,7 +894,6 @@ out_gpio_free:
        }
        spi_master_put(master);
        kfree(master);
-       platform_set_drvdata(pdev, NULL);
        return ret;
 }
 
@@ -929,8 +920,6 @@ static int spi_imx_remove(struct platform_device *pdev)
 
        release_mem_region(res->start, resource_size(res));
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index dfddf336912de4d064ac8edf1f34fd20f5e68c00..29fce6af5145f13a7a0dadd212f1626937ac3885 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/interrupt.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
-#include <linux/workqueue.h>
 #include <linux/completion.h>
 #include <linux/io.h>
 #include <linux/delay.h>
 
 struct mpc512x_psc_spi {
        void (*cs_control)(struct spi_device *spi, bool on);
-       u32 sysclk;
 
        /* driver internal data */
        struct mpc52xx_psc __iomem *psc;
        struct mpc512x_psc_fifo __iomem *fifo;
        unsigned int irq;
        u8 bits_per_word;
-       u8 busy;
        u32 mclk;
-       u8 eofbyte;
 
-       struct workqueue_struct *workqueue;
-       struct work_struct work;
-
-       struct list_head queue;
-       spinlock_t lock;        /* Message queue lock */
-
-       struct completion done;
+       struct completion txisrdone;
 };
 
 /* controller state */
@@ -136,145 +126,223 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
                                         struct spi_transfer *t)
 {
        struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
-       struct mpc52xx_psc __iomem *psc = mps->psc;
        struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
-       size_t len = t->len;
+       size_t tx_len = t->len;
+       size_t rx_len = t->len;
        u8 *tx_buf = (u8 *)t->tx_buf;
        u8 *rx_buf = (u8 *)t->rx_buf;
 
        if (!tx_buf && !rx_buf && t->len)
                return -EINVAL;
 
-       /* Zero MR2 */
-       in_8(&psc->mode);
-       out_8(&psc->mode, 0x0);
-
-       /* enable transmiter/receiver */
-       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
-
-       while (len) {
-               int count;
-               int i;
+       while (rx_len || tx_len) {
+               size_t txcount;
                u8 data;
                size_t fifosz;
-               int rxcount;
+               size_t rxcount;
+               int rxtries;
 
                /*
-                * The number of bytes that can be sent at a time
-                * depends on the fifo size.
+                * send the TX bytes in as large a chunk as possible
+                * but neither exceed the TX nor the RX FIFOs
                 */
                fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz));
-               count = min(fifosz, len);
-
-               for (i = count; i > 0; i--) {
-                       data = tx_buf ? *tx_buf++ : 0;
-                       if (len == EOFBYTE && t->cs_change)
-                               setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF);
-                       out_8(&fifo->txdata_8, data);
-                       len--;
+               txcount = min(fifosz, tx_len);
+               fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->rxsz));
+               fifosz -= in_be32(&fifo->rxcnt) + 1;
+               txcount = min(fifosz, txcount);
+               if (txcount) {
+
+                       /* fill the TX FIFO */
+                       while (txcount-- > 0) {
+                               data = tx_buf ? *tx_buf++ : 0;
+                               if (tx_len == EOFBYTE && t->cs_change)
+                                       setbits32(&fifo->txcmd,
+                                                 MPC512x_PSC_FIFO_EOF);
+                               out_8(&fifo->txdata_8, data);
+                               tx_len--;
+                       }
+
+                       /* have the ISR trigger when the TX FIFO is empty */
+                       INIT_COMPLETION(mps->txisrdone);
+                       out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
+                       out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY);
+                       wait_for_completion(&mps->txisrdone);
                }
 
-               INIT_COMPLETION(mps->done);
+               /*
+                * consume as much RX data as the FIFO holds, while we
+                * iterate over the transfer's TX data length
+                *
+                * only insist in draining all the remaining RX bytes
+                * when the TX bytes were exhausted (that's at the very
+                * end of this transfer, not when still iterating over
+                * the transfer's chunks)
+                */
+               rxtries = 50;
+               do {
+
+                       /*
+                        * grab whatever was in the FIFO when we started
+                        * looking, don't bother fetching what was added to
+                        * the FIFO while we read from it -- we'll return
+                        * here eventually and prefer sending out remaining
+                        * TX data
+                        */
+                       fifosz = in_be32(&fifo->rxcnt);
+                       rxcount = min(fifosz, rx_len);
+                       while (rxcount-- > 0) {
+                               data = in_8(&fifo->rxdata_8);
+                               if (rx_buf)
+                                       *rx_buf++ = data;
+                               rx_len--;
+                       }
 
-               /* interrupt on tx fifo empty */
-               out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
-               out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY);
+                       /*
+                        * come back later if there still is TX data to send,
+                        * bail out of the RX drain loop if all of the TX data
+                        * was sent and all of the RX data was received (i.e.
+                        * when the transmission has completed)
+                        */
+                       if (tx_len)
+                               break;
+                       if (!rx_len)
+                               break;
 
-               wait_for_completion(&mps->done);
+                       /*
+                        * TX data transmission has completed while RX data
+                        * is still pending -- that's a transient situation
+                        * which depends on wire speed and specific
+                        * hardware implementation details (buffering) yet
+                        * should resolve very quickly
+                        *
+                        * just yield for a moment to not hog the CPU for
+                        * too long when running SPI at low speed
+                        *
+                        * the timeout range is rather arbitrary and tries
+                        * to balance throughput against system load; the
+                        * chosen values result in a minimal timeout of 50
+                        * times 10us and thus work at speeds as low as
+                        * some 20kbps, while the maximum timeout at the
+                        * transfer's end could be 5ms _if_ nothing else
+                        * ticks in the system _and_ RX data still wasn't
+                        * received, which only occurs in situations that
+                        * are exceptional; removing the unpredictability
+                        * of the timeout either decreases throughput
+                        * (longer timeouts), or puts more load on the
+                        * system (fixed short timeouts) or requires the
+                        * use of a timeout API instead of a counter and an
+                        * unknown inner delay
+                        */
+                       usleep_range(10, 100);
+
+               } while (--rxtries > 0);
+               if (!tx_len && rx_len && !rxtries) {
+                       /*
+                        * not enough RX bytes even after several retries
+                        * and the resulting rather long timeout?
+                        */
+                       rxcount = in_be32(&fifo->rxcnt);
+                       dev_warn(&spi->dev,
+                                "short xfer, missing %zd RX bytes, FIFO level %zd\n",
+                                rx_len, rxcount);
+               }
 
-               mdelay(1);
+               /*
+                * drain and drop RX data which "should not be there" in
+                * the first place, for undisturbed transmission this turns
+                * into a NOP (except for the FIFO level fetch)
+                */
+               if (!tx_len && !rx_len) {
+                       while (in_be32(&fifo->rxcnt))
+                               in_8(&fifo->rxdata_8);
+               }
 
-               /* rx fifo should have count bytes in it */
-               rxcount = in_be32(&fifo->rxcnt);
-               if (rxcount != count)
-                       mdelay(1);
+       }
+       return 0;
+}
 
-               rxcount = in_be32(&fifo->rxcnt);
-               if (rxcount != count) {
-                       dev_warn(&spi->dev, "expected %d bytes in rx fifo "
-                                "but got %d\n", count, rxcount);
+static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
+                                   struct spi_message *m)
+{
+       struct spi_device *spi;
+       unsigned cs_change;
+       int status;
+       struct spi_transfer *t;
+
+       spi = m->spi;
+       cs_change = 1;
+       status = 0;
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if (t->bits_per_word || t->speed_hz) {
+                       status = mpc512x_psc_spi_transfer_setup(spi, t);
+                       if (status < 0)
+                               break;
                }
 
-               rxcount = min(rxcount, count);
-               for (i = rxcount; i > 0; i--) {
-                       data = in_8(&fifo->rxdata_8);
-                       if (rx_buf)
-                               *rx_buf++ = data;
-               }
-               while (in_be32(&fifo->rxcnt)) {
-                       in_8(&fifo->rxdata_8);
-               }
+               if (cs_change)
+                       mpc512x_psc_spi_activate_cs(spi);
+               cs_change = t->cs_change;
+
+               status = mpc512x_psc_spi_transfer_rxtx(spi, t);
+               if (status)
+                       break;
+               m->actual_length += t->len;
+
+               if (t->delay_usecs)
+                       udelay(t->delay_usecs);
+
+               if (cs_change)
+                       mpc512x_psc_spi_deactivate_cs(spi);
        }
-       /* disable transmiter/receiver and fifo interrupt */
-       out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
-       out_be32(&fifo->tximr, 0);
-       return 0;
+
+       m->status = status;
+       m->complete(m->context);
+
+       if (status || !cs_change)
+               mpc512x_psc_spi_deactivate_cs(spi);
+
+       mpc512x_psc_spi_transfer_setup(spi, NULL);
+
+       spi_finalize_current_message(master);
+       return status;
 }
 
-static void mpc512x_psc_spi_work(struct work_struct *work)
+static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
 {
-       struct mpc512x_psc_spi *mps = container_of(work,
-                                                  struct mpc512x_psc_spi,
-                                                  work);
-
-       spin_lock_irq(&mps->lock);
-       mps->busy = 1;
-       while (!list_empty(&mps->queue)) {
-               struct spi_message *m;
-               struct spi_device *spi;
-               struct spi_transfer *t = NULL;
-               unsigned cs_change;
-               int status;
-
-               m = container_of(mps->queue.next, struct spi_message, queue);
-               list_del_init(&m->queue);
-               spin_unlock_irq(&mps->lock);
-
-               spi = m->spi;
-               cs_change = 1;
-               status = 0;
-               list_for_each_entry(t, &m->transfers, transfer_list) {
-                       if (t->bits_per_word || t->speed_hz) {
-                               status = mpc512x_psc_spi_transfer_setup(spi, t);
-                               if (status < 0)
-                                       break;
-                       }
+       struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
+       struct mpc52xx_psc __iomem *psc = mps->psc;
 
-                       if (cs_change)
-                               mpc512x_psc_spi_activate_cs(spi);
-                       cs_change = t->cs_change;
+       dev_dbg(&master->dev, "%s()\n", __func__);
 
-                       status = mpc512x_psc_spi_transfer_rxtx(spi, t);
-                       if (status)
-                               break;
-                       m->actual_length += t->len;
+       /* Zero MR2 */
+       in_8(&psc->mode);
+       out_8(&psc->mode, 0x0);
 
-                       if (t->delay_usecs)
-                               udelay(t->delay_usecs);
+       /* enable transmitter/receiver */
+       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
 
-                       if (cs_change)
-                               mpc512x_psc_spi_deactivate_cs(spi);
-               }
+       return 0;
+}
 
-               m->status = status;
-               m->complete(m->context);
+static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master)
+{
+       struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+       struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
 
-               if (status || !cs_change)
-                       mpc512x_psc_spi_deactivate_cs(spi);
+       dev_dbg(&master->dev, "%s()\n", __func__);
 
-               mpc512x_psc_spi_transfer_setup(spi, NULL);
+       /* disable transmitter/receiver and fifo interrupt */
+       out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+       out_be32(&fifo->tximr, 0);
 
-               spin_lock_irq(&mps->lock);
-       }
-       mps->busy = 0;
-       spin_unlock_irq(&mps->lock);
+       return 0;
 }
 
 static int mpc512x_psc_spi_setup(struct spi_device *spi)
 {
-       struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
        struct mpc512x_psc_spi_cs *cs = spi->controller_state;
-       unsigned long flags;
        int ret;
 
        if (spi->bits_per_word % 8)
@@ -303,28 +371,6 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi)
        cs->bits_per_word = spi->bits_per_word;
        cs->speed_hz = spi->max_speed_hz;
 
-       spin_lock_irqsave(&mps->lock, flags);
-       if (!mps->busy)
-               mpc512x_psc_spi_deactivate_cs(spi);
-       spin_unlock_irqrestore(&mps->lock, flags);
-
-       return 0;
-}
-
-static int mpc512x_psc_spi_transfer(struct spi_device *spi,
-                                   struct spi_message *m)
-{
-       struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
-       unsigned long flags;
-
-       m->actual_length = 0;
-       m->status = -EINPROGRESS;
-
-       spin_lock_irqsave(&mps->lock, flags);
-       list_add_tail(&m->queue, &mps->queue);
-       queue_work(mps->workqueue, &mps->work);
-       spin_unlock_irqrestore(&mps->lock, flags);
-
        return 0;
 }
 
@@ -407,12 +453,12 @@ static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
        struct mpc512x_psc_spi *mps = (struct mpc512x_psc_spi *)dev_id;
        struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
 
-       /* clear interrupt and wake up the work queue */
+       /* clear interrupt and wake up the rx/tx routine */
        if (in_be32(&fifo->txisr) &
            in_be32(&fifo->tximr) & MPC512x_PSC_FIFO_EMPTY) {
                out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
                out_be32(&fifo->tximr, 0);
-               complete(&mps->done);
+               complete(&mps->txisrdone);
                return IRQ_HANDLED;
        }
        return IRQ_NONE;
@@ -444,18 +490,18 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
 
        if (pdata == NULL) {
                mps->cs_control = mpc512x_spi_cs_control;
-               mps->sysclk = 0;
                master->bus_num = bus_num;
        } else {
                mps->cs_control = pdata->cs_control;
-               mps->sysclk = pdata->sysclk;
                master->bus_num = pdata->bus_num;
                master->num_chipselect = pdata->max_chipselect;
        }
 
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
        master->setup = mpc512x_psc_spi_setup;
-       master->transfer = mpc512x_psc_spi_transfer;
+       master->prepare_transfer_hardware = mpc512x_psc_spi_prep_xfer_hw;
+       master->transfer_one_message = mpc512x_psc_spi_msg_xfer;
+       master->unprepare_transfer_hardware = mpc512x_psc_spi_unprep_xfer_hw;
        master->cleanup = mpc512x_psc_spi_cleanup;
        master->dev.of_node = dev->of_node;
 
@@ -473,31 +519,18 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
                          "mpc512x-psc-spi", mps);
        if (ret)
                goto free_master;
+       init_completion(&mps->txisrdone);
 
        ret = mpc512x_psc_spi_port_config(master, mps);
        if (ret < 0)
                goto free_irq;
 
-       spin_lock_init(&mps->lock);
-       init_completion(&mps->done);
-       INIT_WORK(&mps->work, mpc512x_psc_spi_work);
-       INIT_LIST_HEAD(&mps->queue);
-
-       mps->workqueue =
-               create_singlethread_workqueue(dev_name(master->dev.parent));
-       if (mps->workqueue == NULL) {
-               ret = -EBUSY;
-               goto free_irq;
-       }
-
        ret = spi_register_master(master);
        if (ret < 0)
-               goto unreg_master;
+               goto free_irq;
 
        return ret;
 
-unreg_master:
-       destroy_workqueue(mps->workqueue);
 free_irq:
        free_irq(mps->irq, mps);
 free_master:
@@ -513,8 +546,6 @@ static int mpc512x_psc_spi_do_remove(struct device *dev)
        struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
        struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
 
-       flush_workqueue(mps->workqueue);
-       destroy_workqueue(mps->workqueue);
        spi_unregister_master(master);
        free_irq(mps->irq, mps);
        if (mps->psc)
index 291120b37dbb07fc90c74eb9f5c7d08af52e5bb9..fed0571d4decb0fb131890a3101dd5150c3c4aa7 100644 (file)
@@ -481,7 +481,7 @@ static int mpc52xx_psc_spi_of_probe(struct platform_device *op)
 
 static int mpc52xx_psc_spi_of_remove(struct platform_device *op)
 {
-       struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev));
+       struct spi_master *master = spi_master_get(platform_get_drvdata(op));
        struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
 
        flush_workqueue(mps->workqueue);
index 29f77056eedcba12b6d796f41799008e378bb2ba..7c675fe8310105d255f6f10afc7a2f1c5e576b32 100644 (file)
@@ -438,7 +438,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
        master->dev.of_node = op->dev.of_node;
 
-       dev_set_drvdata(&op->dev, master);
+       platform_set_drvdata(op, master);
 
        ms = spi_master_get_devdata(master);
        ms->master = master;
@@ -529,7 +529,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
 
 static int mpc52xx_spi_remove(struct platform_device *op)
 {
-       struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev));
+       struct spi_master *master = spi_master_get(platform_get_drvdata(op));
        struct mpc52xx_spi *ms = spi_master_get_devdata(master);
        int i;
 
index 84982768cd108beec37f67e303203c5c3ad5ecad..424d38e59421db2c621e1a14c1950f3777b7de75 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/stmp_device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/mxs-spi.h>
@@ -75,12 +74,6 @@ static int mxs_spi_setup_transfer(struct spi_device *dev,
        if (t && t->bits_per_word)
                bits_per_word = t->bits_per_word;
 
-       if (bits_per_word != 8) {
-               dev_err(&dev->dev, "%s, unsupported bits_per_word=%d\n",
-                                       __func__, bits_per_word);
-               return -EINVAL;
-       }
-
        hz = dev->max_speed_hz;
        if (t && t->speed_hz)
                hz = min(hz, t->speed_hz);
@@ -506,7 +499,6 @@ static int mxs_spi_probe(struct platform_device *pdev)
        struct mxs_spi *spi;
        struct mxs_ssp *ssp;
        struct resource *iores;
-       struct pinctrl *pinctrl;
        struct clk *clk;
        void __iomem *base;
        int devid, clk_freq;
@@ -528,10 +520,6 @@ static int mxs_spi_probe(struct platform_device *pdev)
        if (IS_ERR(base))
                return PTR_ERR(base);
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl))
-               return PTR_ERR(pinctrl);
-
        clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(clk))
                return PTR_ERR(clk);
@@ -548,6 +536,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
 
        master->transfer_one_message = mxs_spi_transfer_one;
        master->setup = mxs_spi_setup;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
        master->mode_bits = SPI_CPOL | SPI_CPHA;
        master->num_chipselect = 3;
        master->dev.of_node = np;
index b3f9ec83ef7361b98c05d1c42a9ee40949ab585b..2ad3d74ac0217061b1942eda99dc0bc4d758a74b 100644 (file)
@@ -174,17 +174,6 @@ static void nuc900_spi_gobusy(struct nuc900_spi *hw)
        spin_unlock_irqrestore(&hw->lock, flags);
 }
 
-static int nuc900_spi_setupxfer(struct spi_device *spi,
-                                struct spi_transfer *t)
-{
-       return 0;
-}
-
-static int nuc900_spi_setup(struct spi_device *spi)
-{
-       return 0;
-}
-
 static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count)
 {
        return hw->tx ? hw->tx[count] : 0;
@@ -377,10 +366,8 @@ static int nuc900_spi_probe(struct platform_device *pdev)
        master->num_chipselect     = hw->pdata->num_cs;
        master->bus_num            = hw->pdata->bus_num;
        hw->bitbang.master         = hw->master;
-       hw->bitbang.setup_transfer = nuc900_spi_setupxfer;
        hw->bitbang.chipselect     = nuc900_spi_chipsel;
        hw->bitbang.txrx_bufs      = nuc900_spi_txrx;
-       hw->bitbang.master->setup  = nuc900_spi_setup;
 
        hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (hw->res == NULL) {
@@ -459,8 +446,6 @@ static int nuc900_spi_remove(struct platform_device *dev)
 
        free_irq(hw->irq, hw);
 
-       platform_set_drvdata(dev, NULL);
-
        spi_bitbang_stop(&hw->bitbang);
 
        clk_disable(hw->clk);
index e60a776ed2d498f7f4574172b7638e37c0d75ef0..58deb79d046be444cbb0392e4f17583e8d99ee8d 100644 (file)
@@ -368,7 +368,6 @@ exit_gpio:
 exit_busy:
        err = -EBUSY;
 exit:
-       platform_set_drvdata(pdev, NULL);
        spi_master_put(master);
        return err;
 }
@@ -382,7 +381,6 @@ static int tiny_spi_remove(struct platform_device *pdev)
        spi_bitbang_stop(&hw->bitbang);
        for (i = 0; i < hw->gpio_cs_count; i++)
                gpio_free(hw->gpio_cs[i]);
-       platform_set_drvdata(pdev, NULL);
        spi_master_put(master);
        return 0;
 }
index 78d29a18dcc4e8de8f3b329fd899baed160c9060..ee25670f8cfd127341fff7ddc16562a7e512507d 100644 (file)
@@ -298,12 +298,6 @@ static int omap1_spi100k_setup(struct spi_device *spi)
        struct omap1_spi100k    *spi100k;
        struct omap1_spi100k_cs *cs = spi->controller_state;
 
-       if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
-                dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
-                       spi->bits_per_word);
-                return -EINVAL;
-       }
-
        spi100k = spi_master_get_devdata(spi->master);
 
        if (!cs) {
@@ -451,10 +445,7 @@ static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
                unsigned        len = t->len;
 
                if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
-                               || (len && !(rx_buf || tx_buf))
-                               || (t->bits_per_word &&
-                                       (  t->bits_per_word < 4
-                                       || t->bits_per_word > 32))) {
+                               || (len && !(rx_buf || tx_buf))) {
                        dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
                                        t->speed_hz,
                                        len,
@@ -509,8 +500,9 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
        master->cleanup = NULL;
        master->num_chipselect = 2;
        master->mode_bits = MODEBITS;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
 
-       dev_set_drvdata(&pdev->dev, master);
+       platform_set_drvdata(pdev, master);
 
        spi100k = spi_master_get_devdata(master);
        spi100k->master = master;
@@ -569,7 +561,7 @@ static int omap1_spi100k_remove(struct platform_device *pdev)
        unsigned long           flags;
        int                     status = 0;
 
-       master = dev_get_drvdata(&pdev->dev);
+       master = platform_get_drvdata(pdev);
        spi100k = spi_master_get_devdata(master);
 
        spin_lock_irqsave(&spi100k->lock, flags);
index 102b233b50c41833c875f683b1a9499dd54c0d9d..a6a8f09617508aeaf5a4ac3631d8914d26f38807 100644 (file)
@@ -495,7 +495,7 @@ static int uwire_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       dev_set_drvdata(&pdev->dev, uwire);
+       platform_set_drvdata(pdev, uwire);
 
        uwire->ck = clk_get(&pdev->dev, "fck");
        if (IS_ERR(uwire->ck)) {
@@ -538,7 +538,7 @@ static int uwire_probe(struct platform_device *pdev)
 
 static int uwire_remove(struct platform_device *pdev)
 {
-       struct uwire_spi        *uwire = dev_get_drvdata(&pdev->dev);
+       struct uwire_spi        *uwire = platform_get_drvdata(pdev);
        int                     status;
 
        // FIXME remove all child devices, somewhere ...
index 86d2158946bbf3de879cc459e53aa00005e6768f..5994039758debd91acd7fa1bd238cf3e85a8b790 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/pinctrl/consumer.h>
+#include <linux/gcd.h>
 
 #include <linux/spi/spi.h>
 
 #include <linux/platform_data/spi-omap2-mcspi.h>
 
 #define OMAP2_MCSPI_MAX_FREQ           48000000
+#define OMAP2_MCSPI_MAX_FIFODEPTH      64
+#define OMAP2_MCSPI_MAX_FIFOWCNT       0xFFFF
 #define SPI_AUTOSUSPEND_TIMEOUT                2000
 
 #define OMAP2_MCSPI_REVISION           0x00
@@ -54,6 +56,7 @@
 #define OMAP2_MCSPI_WAKEUPENABLE       0x20
 #define OMAP2_MCSPI_SYST               0x24
 #define OMAP2_MCSPI_MODULCTRL          0x28
+#define OMAP2_MCSPI_XFERLEVEL          0x7c
 
 /* per-channel banks, 0x14 bytes each, first is: */
 #define OMAP2_MCSPI_CHCONF0            0x2c
@@ -63,6 +66,7 @@
 #define OMAP2_MCSPI_RX0                        0x3c
 
 /* per-register bitmasks: */
+#define OMAP2_MCSPI_IRQSTATUS_EOW      BIT(17)
 
 #define OMAP2_MCSPI_MODULCTRL_SINGLE   BIT(0)
 #define OMAP2_MCSPI_MODULCTRL_MS       BIT(2)
 #define OMAP2_MCSPI_CHCONF_IS          BIT(18)
 #define OMAP2_MCSPI_CHCONF_TURBO       BIT(19)
 #define OMAP2_MCSPI_CHCONF_FORCE       BIT(20)
+#define OMAP2_MCSPI_CHCONF_FFET                BIT(27)
+#define OMAP2_MCSPI_CHCONF_FFER                BIT(28)
 
 #define OMAP2_MCSPI_CHSTAT_RXS         BIT(0)
 #define OMAP2_MCSPI_CHSTAT_TXS         BIT(1)
 #define OMAP2_MCSPI_CHSTAT_EOT         BIT(2)
+#define OMAP2_MCSPI_CHSTAT_TXFFE       BIT(3)
 
 #define OMAP2_MCSPI_CHCTRL_EN          BIT(0)
 
@@ -102,6 +109,9 @@ struct omap2_mcspi_dma {
 
        struct completion dma_tx_completion;
        struct completion dma_rx_completion;
+
+       char dma_rx_ch_name[14];
+       char dma_tx_ch_name[14];
 };
 
 /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
@@ -129,6 +139,7 @@ struct omap2_mcspi {
        struct omap2_mcspi_dma  *dma_channels;
        struct device           *dev;
        struct omap2_mcspi_regs ctx;
+       int                     fifo_depth;
        unsigned int            pin_dir:1;
 };
 
@@ -187,6 +198,16 @@ static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
        mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
 }
 
+static inline int mcspi_bytes_per_word(int word_len)
+{
+       if (word_len <= 8)
+               return 1;
+       else if (word_len <= 16)
+               return 2;
+       else /* word_len <= 32 */
+               return 4;
+}
+
 static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
                int is_read, int enable)
 {
@@ -248,6 +269,58 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master)
        ctx->modulctrl = l;
 }
 
+static void omap2_mcspi_set_fifo(const struct spi_device *spi,
+                               struct spi_transfer *t, int enable)
+{
+       struct spi_master *master = spi->master;
+       struct omap2_mcspi_cs *cs = spi->controller_state;
+       struct omap2_mcspi *mcspi;
+       unsigned int wcnt;
+       int fifo_depth, bytes_per_word;
+       u32 chconf, xferlevel;
+
+       mcspi = spi_master_get_devdata(master);
+
+       chconf = mcspi_cached_chconf0(spi);
+       if (enable) {
+               bytes_per_word = mcspi_bytes_per_word(cs->word_len);
+               if (t->len % bytes_per_word != 0)
+                       goto disable_fifo;
+
+               fifo_depth = gcd(t->len, OMAP2_MCSPI_MAX_FIFODEPTH);
+               if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0)
+                       goto disable_fifo;
+
+               wcnt = t->len / bytes_per_word;
+               if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)
+                       goto disable_fifo;
+
+               xferlevel = wcnt << 16;
+               if (t->rx_buf != NULL) {
+                       chconf |= OMAP2_MCSPI_CHCONF_FFER;
+                       xferlevel |= (fifo_depth - 1) << 8;
+               } else {
+                       chconf |= OMAP2_MCSPI_CHCONF_FFET;
+                       xferlevel |= fifo_depth - 1;
+               }
+
+               mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel);
+               mcspi_write_chconf0(spi, chconf);
+               mcspi->fifo_depth = fifo_depth;
+
+               return;
+       }
+
+disable_fifo:
+       if (t->rx_buf != NULL)
+               chconf &= ~OMAP2_MCSPI_CHCONF_FFER;
+       else
+               chconf &= ~OMAP2_MCSPI_CHCONF_FFET;
+
+       mcspi_write_chconf0(spi, chconf);
+       mcspi->fifo_depth = 0;
+}
+
 static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
 {
        struct spi_master       *spi_cntrl = mcspi->master;
@@ -364,7 +437,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 {
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *mcspi_dma;
-       unsigned int            count;
+       unsigned int            count, dma_count;
        u32                     l;
        int                     elements = 0;
        int                     word_len, element_count;
@@ -372,6 +445,11 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
        count = xfer->len;
+       dma_count = xfer->len;
+
+       if (mcspi->fifo_depth == 0)
+               dma_count -= es;
+
        word_len = cs->word_len;
        l = mcspi_cached_chconf0(spi);
 
@@ -385,16 +463,15 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
        if (mcspi_dma->dma_rx) {
                struct dma_async_tx_descriptor *tx;
                struct scatterlist sg;
-               size_t len = xfer->len - es;
 
                dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
 
-               if (l & OMAP2_MCSPI_CHCONF_TURBO)
-                       len -= es;
+               if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
+                       dma_count -= es;
 
                sg_init_table(&sg, 1);
                sg_dma_address(&sg) = xfer->rx_dma;
-               sg_dma_len(&sg) = len;
+               sg_dma_len(&sg) = dma_count;
 
                tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
                                DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
@@ -414,6 +491,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
        wait_for_completion(&mcspi_dma->dma_rx_completion);
        dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
                         DMA_FROM_DEVICE);
+
+       if (mcspi->fifo_depth > 0)
+               return count;
+
        omap2_mcspi_set_enable(spi, 0);
 
        elements = element_count - 1;
@@ -433,10 +514,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
                        else /* word_len <= 32 */
                                ((u32 *)xfer->rx_buf)[elements++] = w;
                } else {
+                       int bytes_per_word = mcspi_bytes_per_word(word_len);
                        dev_err(&spi->dev, "DMA RX penultimate word empty");
-                       count -= (word_len <= 8)  ? 2 :
-                               (word_len <= 16) ? 4 :
-                               /* word_len <= 32 */ 8;
+                       count -= (bytes_per_word << 1);
                        omap2_mcspi_set_enable(spi, 1);
                        return count;
                }
@@ -454,9 +534,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
                        ((u32 *)xfer->rx_buf)[elements] = w;
        } else {
                dev_err(&spi->dev, "DMA RX last word empty");
-               count -= (word_len <= 8)  ? 1 :
-                        (word_len <= 16) ? 2 :
-                      /* word_len <= 32 */ 4;
+               count -= mcspi_bytes_per_word(word_len);
        }
        omap2_mcspi_set_enable(spi, 1);
        return count;
@@ -475,7 +553,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        struct dma_slave_config cfg;
        enum dma_slave_buswidth width;
        unsigned es;
+       u32                     burst;
        void __iomem            *chstat_reg;
+       void __iomem            *irqstat_reg;
+       int                     wait_res;
 
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
@@ -493,19 +574,27 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
                es = 4;
        }
 
+       count = xfer->len;
+       burst = 1;
+
+       if (mcspi->fifo_depth > 0) {
+               if (count > mcspi->fifo_depth)
+                       burst = mcspi->fifo_depth / es;
+               else
+                       burst = count / es;
+       }
+
        memset(&cfg, 0, sizeof(cfg));
        cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
        cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
        cfg.src_addr_width = width;
        cfg.dst_addr_width = width;
-       cfg.src_maxburst = 1;
-       cfg.dst_maxburst = 1;
+       cfg.src_maxburst = burst;
+       cfg.dst_maxburst = burst;
 
        rx = xfer->rx_buf;
        tx = xfer->tx_buf;
 
-       count = xfer->len;
-
        if (tx != NULL)
                omap2_mcspi_tx_dma(spi, xfer, cfg);
 
@@ -513,18 +602,38 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
                count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
 
        if (tx != NULL) {
-               chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
                wait_for_completion(&mcspi_dma->dma_tx_completion);
                dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
                                 DMA_TO_DEVICE);
 
+               if (mcspi->fifo_depth > 0) {
+                       irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
+
+                       if (mcspi_wait_for_reg_bit(irqstat_reg,
+                                               OMAP2_MCSPI_IRQSTATUS_EOW) < 0)
+                               dev_err(&spi->dev, "EOW timed out\n");
+
+                       mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS,
+                                       OMAP2_MCSPI_IRQSTATUS_EOW);
+               }
+
                /* for TX_ONLY mode, be sure all words have shifted out */
                if (rx == NULL) {
-                       if (mcspi_wait_for_reg_bit(chstat_reg,
-                                               OMAP2_MCSPI_CHSTAT_TXS) < 0)
-                               dev_err(&spi->dev, "TXS timed out\n");
-                       else if (mcspi_wait_for_reg_bit(chstat_reg,
-                                               OMAP2_MCSPI_CHSTAT_EOT) < 0)
+                       chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
+                       if (mcspi->fifo_depth > 0) {
+                               wait_res = mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_TXFFE);
+                               if (wait_res < 0)
+                                       dev_err(&spi->dev, "TXFFE timed out\n");
+                       } else {
+                               wait_res = mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_TXS);
+                               if (wait_res < 0)
+                                       dev_err(&spi->dev, "TXS timed out\n");
+                       }
+                       if (wait_res >= 0 &&
+                               (mcspi_wait_for_reg_bit(chstat_reg,
+                                       OMAP2_MCSPI_CHSTAT_EOT) < 0))
                                dev_err(&spi->dev, "EOT timed out\n");
                }
        }
@@ -830,12 +939,20 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
        sig = mcspi_dma->dma_rx_sync_dev;
-       mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
+
+       mcspi_dma->dma_rx =
+               dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
+                                                &sig, &master->dev,
+                                                mcspi_dma->dma_rx_ch_name);
        if (!mcspi_dma->dma_rx)
                goto no_dma;
 
        sig = mcspi_dma->dma_tx_sync_dev;
-       mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
+       mcspi_dma->dma_tx =
+               dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
+                                                &sig, &master->dev,
+                                                mcspi_dma->dma_tx_ch_name);
+
        if (!mcspi_dma->dma_tx) {
                dma_release_channel(mcspi_dma->dma_rx);
                mcspi_dma->dma_rx = NULL;
@@ -857,12 +974,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
        struct omap2_mcspi_dma  *mcspi_dma;
        struct omap2_mcspi_cs   *cs = spi->controller_state;
 
-       if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
-               dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
-                       spi->bits_per_word);
-               return -EINVAL;
-       }
-
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
 
        if (!cs) {
@@ -951,7 +1062,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
        cs = spi->controller_state;
        cd = spi->controller_data;
 
-       omap2_mcspi_set_enable(spi, 1);
+       omap2_mcspi_set_enable(spi, 0);
        list_for_each_entry(t, &m->transfers, transfer_list) {
                if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
                        status = -EINVAL;
@@ -999,6 +1110,12 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
                if (t->len) {
                        unsigned        count;
 
+                       if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
+                           (m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
+                               omap2_mcspi_set_fifo(spi, t, 1);
+
+                       omap2_mcspi_set_enable(spi, 1);
+
                        /* RX_ONLY mode needs dummy data in TX reg */
                        if (t->tx_buf == NULL)
                                __raw_writel(0, cs->base
@@ -1025,6 +1142,11 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
                        omap2_mcspi_force_cs(spi, 0);
                        cs_active = 0;
                }
+
+               omap2_mcspi_set_enable(spi, 0);
+
+               if (mcspi->fifo_depth > 0)
+                       omap2_mcspi_set_fifo(spi, t, 0);
        }
        /* Restore defaults if they were overriden */
        if (par_override) {
@@ -1045,8 +1167,10 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
 
        omap2_mcspi_set_enable(spi, 0);
 
-       m->status = status;
+       if (mcspi->fifo_depth > 0 && t)
+               omap2_mcspi_set_fifo(spi, t, 0);
 
+       m->status = status;
 }
 
 static int omap2_mcspi_transfer_one_message(struct spi_master *master,
@@ -1072,10 +1196,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
                unsigned        len = t->len;
 
                if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
-                               || (len && !(rx_buf || tx_buf))
-                               || (t->bits_per_word &&
-                                       (  t->bits_per_word < 4
-                                          || t->bits_per_word > 32))) {
+                               || (len && !(rx_buf || tx_buf))) {
                        dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
                                        t->speed_hz,
                                        len,
@@ -1186,7 +1307,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        static int              bus_num = 1;
        struct device_node      *node = pdev->dev.of_node;
        const struct of_device_id *match;
-       struct pinctrl *pinctrl;
 
        master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
        if (master == NULL) {
@@ -1196,7 +1316,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
 
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
-
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
        master->setup = omap2_mcspi_setup;
        master->prepare_transfer_hardware = omap2_prepare_transfer;
        master->unprepare_transfer_hardware = omap2_unprepare_transfer;
@@ -1204,7 +1324,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        master->cleanup = omap2_mcspi_cleanup;
        master->dev.of_node = node;
 
-       dev_set_drvdata(&pdev->dev, master);
+       platform_set_drvdata(pdev, master);
 
        mcspi = spi_master_get_devdata(master);
        mcspi->master = master;
@@ -1256,39 +1376,47 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
                goto free_master;
 
        for (i = 0; i < master->num_chipselect; i++) {
-               char dma_ch_name[14];
+               char *dma_rx_ch_name = mcspi->dma_channels[i].dma_rx_ch_name;
+               char *dma_tx_ch_name = mcspi->dma_channels[i].dma_tx_ch_name;
                struct resource *dma_res;
 
-               sprintf(dma_ch_name, "rx%d", i);
-               dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
-                               dma_ch_name);
-               if (!dma_res) {
-                       dev_dbg(&pdev->dev, "cannot get DMA RX channel\n");
-                       status = -ENODEV;
-                       break;
-               }
+               sprintf(dma_rx_ch_name, "rx%d", i);
+               if (!pdev->dev.of_node) {
+                       dma_res =
+                               platform_get_resource_byname(pdev,
+                                                            IORESOURCE_DMA,
+                                                            dma_rx_ch_name);
+                       if (!dma_res) {
+                               dev_dbg(&pdev->dev,
+                                       "cannot get DMA RX channel\n");
+                               status = -ENODEV;
+                               break;
+                       }
 
-               mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;
-               sprintf(dma_ch_name, "tx%d", i);
-               dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
-                               dma_ch_name);
-               if (!dma_res) {
-                       dev_dbg(&pdev->dev, "cannot get DMA TX channel\n");
-                       status = -ENODEV;
-                       break;
+                       mcspi->dma_channels[i].dma_rx_sync_dev =
+                               dma_res->start;
                }
+               sprintf(dma_tx_ch_name, "tx%d", i);
+               if (!pdev->dev.of_node) {
+                       dma_res =
+                               platform_get_resource_byname(pdev,
+                                                            IORESOURCE_DMA,
+                                                            dma_tx_ch_name);
+                       if (!dma_res) {
+                               dev_dbg(&pdev->dev,
+                                       "cannot get DMA TX channel\n");
+                               status = -ENODEV;
+                               break;
+                       }
 
-               mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start;
+                       mcspi->dma_channels[i].dma_tx_sync_dev =
+                               dma_res->start;
+               }
        }
 
        if (status < 0)
                goto dma_chnl_free;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl))
-               dev_warn(&pdev->dev,
-                               "pins are not configured from the driver\n");
-
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
        pm_runtime_enable(&pdev->dev);
@@ -1318,7 +1446,7 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *dma_channels;
 
-       master = dev_get_drvdata(&pdev->dev);
+       master = platform_get_drvdata(pdev);
        mcspi = spi_master_get_devdata(master);
        dma_channels = mcspi->dma_channels;
 
index 66a5f82cf138d86b4fa84d5235e1086022ca6b08..5d90bebaa0fa3692da2591087f138281de5402c6 100644 (file)
@@ -428,7 +428,7 @@ static int orion_spi_probe(struct platform_device *pdev)
        master->transfer_one_message = orion_spi_transfer_one_message;
        master->num_chipselect = ORION_NUM_CHIPSELECTS;
 
-       dev_set_drvdata(&pdev->dev, master);
+       platform_set_drvdata(pdev, master);
 
        spi = spi_master_get_devdata(master);
        spi->master = master;
@@ -485,7 +485,7 @@ static int orion_spi_remove(struct platform_device *pdev)
        struct resource *r;
        struct orion_spi *spi;
 
-       master = dev_get_drvdata(&pdev->dev);
+       master = platform_get_drvdata(pdev);
        spi = spi_master_get_devdata(master);
 
        clk_disable_unprepare(spi->clk);
index 3b246543282f50a21a04397458097135c52693a3..abef061fb84af1537afde292373604be6d1e85b1 100644 (file)
@@ -368,11 +368,6 @@ struct pl022 {
        resource_size_t                 phybase;
        void __iomem                    *virtbase;
        struct clk                      *clk;
-       /* Two optional pin states - default & sleep */
-       struct pinctrl                  *pinctrl;
-       struct pinctrl_state            *pins_default;
-       struct pinctrl_state            *pins_idle;
-       struct pinctrl_state            *pins_sleep;
        struct spi_master               *master;
        struct pl022_ssp_controller     *master_info;
        /* Message per-transfer pump */
@@ -2134,32 +2129,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
        pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int),
                                          GFP_KERNEL);
 
-       pl022->pinctrl = devm_pinctrl_get(dev);
-       if (IS_ERR(pl022->pinctrl)) {
-               status = PTR_ERR(pl022->pinctrl);
-               goto err_no_pinctrl;
-       }
-
-       pl022->pins_default = pinctrl_lookup_state(pl022->pinctrl,
-                                                PINCTRL_STATE_DEFAULT);
-       /* enable pins to be muxed in and configured */
-       if (!IS_ERR(pl022->pins_default)) {
-               status = pinctrl_select_state(pl022->pinctrl,
-                               pl022->pins_default);
-               if (status)
-                       dev_err(dev, "could not set default pins\n");
-       } else
-               dev_err(dev, "could not get default pinstate\n");
-
-       pl022->pins_idle = pinctrl_lookup_state(pl022->pinctrl,
-                                             PINCTRL_STATE_IDLE);
-       if (IS_ERR(pl022->pins_idle))
-               dev_dbg(dev, "could not get idle pinstate\n");
-
-       pl022->pins_sleep = pinctrl_lookup_state(pl022->pinctrl,
-                                              PINCTRL_STATE_SLEEP);
-       if (IS_ERR(pl022->pins_sleep))
-               dev_dbg(dev, "could not get sleep pinstate\n");
+       pinctrl_pm_select_default_state(dev);
 
        /*
         * Bus Number Which has been Assigned to this SSP controller
@@ -2309,7 +2279,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
        amba_release_regions(adev);
  err_no_ioregion:
  err_no_gpio:
- err_no_pinctrl:
        spi_master_put(master);
        return status;
 }
@@ -2349,44 +2318,21 @@ pl022_remove(struct amba_device *adev)
  */
 static void pl022_suspend_resources(struct pl022 *pl022, bool runtime)
 {
-       int ret;
-       struct pinctrl_state *pins_state;
-
        clk_disable(pl022->clk);
 
-       pins_state = runtime ? pl022->pins_idle : pl022->pins_sleep;
-       /* Optionally let pins go into sleep states */
-       if (!IS_ERR(pins_state)) {
-               ret = pinctrl_select_state(pl022->pinctrl, pins_state);
-               if (ret)
-                       dev_err(&pl022->adev->dev, "could not set %s pins\n",
-                               runtime ? "idle" : "sleep");
-       }
+       if (runtime)
+               pinctrl_pm_select_idle_state(&pl022->adev->dev);
+       else
+               pinctrl_pm_select_sleep_state(&pl022->adev->dev);
 }
 
 static void pl022_resume_resources(struct pl022 *pl022, bool runtime)
 {
-       int ret;
-
-       /* Optionaly enable pins to be muxed in and configured */
        /* First go to the default state */
-       if (!IS_ERR(pl022->pins_default)) {
-               ret = pinctrl_select_state(pl022->pinctrl, pl022->pins_default);
-               if (ret)
-                       dev_err(&pl022->adev->dev,
-                               "could not set default pins\n");
-       }
-
-       if (!runtime) {
+       pinctrl_pm_select_default_state(&pl022->adev->dev);
+       if (!runtime)
                /* Then let's idle the pins until the next transfer happens */
-               if (!IS_ERR(pl022->pins_idle)) {
-                       ret = pinctrl_select_state(pl022->pinctrl,
-                                       pl022->pins_idle);
-               if (ret)
-                       dev_err(&pl022->adev->dev,
-                               "could not set idle pins\n");
-               }
-       }
+               pinctrl_pm_select_idle_state(&pl022->adev->dev);
 
        clk_enable(pl022->clk);
 }
index 357f183a4fb7e06d813197d423acceed84e654aa..0ee53c25ba58b5d772633e4736f5c2bbbaf72ab4 100644 (file)
@@ -190,12 +190,6 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
                        speed = min(t->speed_hz, spi->max_speed_hz);
        }
 
-       if (bits_per_word != 8) {
-               dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
-                               bits_per_word);
-               return -EINVAL;
-       }
-
        if (!speed || (speed > spi->max_speed_hz)) {
                dev_err(&spi->dev, "invalid speed_hz (%d)\n", speed);
                return -EINVAL;
@@ -229,12 +223,6 @@ static int spi_ppc4xx_setup(struct spi_device *spi)
 {
        struct spi_ppc4xx_cs *cs = spi->controller_state;
 
-       if (spi->bits_per_word != 8) {
-               dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
-                       spi->bits_per_word);
-               return -EINVAL;
-       }
-
        if (!spi->max_speed_hz) {
                dev_err(&spi->dev, "invalid max_speed_hz (must be non-zero)\n");
                return -EINVAL;
@@ -406,7 +394,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
        if (master == NULL)
                return -ENOMEM;
        master->dev.of_node = np;
-       dev_set_drvdata(dev, master);
+       platform_set_drvdata(op, master);
        hw = spi_master_get_devdata(master);
        hw->master = spi_master_get(master);
        hw->dev = dev;
@@ -465,6 +453,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
        bbp->use_dma = 0;
        bbp->master->setup = spi_ppc4xx_setup;
        bbp->master->cleanup = spi_ppc4xx_cleanup;
+       bbp->master->bits_per_word_mask = SPI_BPW_MASK(8);
 
        /* the spi->mode bits understood by this driver: */
        bbp->master->mode_bits =
@@ -553,7 +542,6 @@ request_mem_error:
 free_gpios:
        free_gpios(hw);
 free_master:
-       dev_set_drvdata(dev, NULL);
        spi_master_put(master);
 
        dev_err(dev, "initialization failed\n");
@@ -562,11 +550,10 @@ free_master:
 
 static int spi_ppc4xx_of_remove(struct platform_device *op)
 {
-       struct spi_master *master = dev_get_drvdata(&op->dev);
+       struct spi_master *master = platform_get_drvdata(op);
        struct ppc4xx_spi *hw = spi_master_get_devdata(master);
 
        spi_bitbang_stop(&hw->bitbang);
-       dev_set_drvdata(&op->dev, NULL);
        release_mem_region(hw->mapbase, hw->mapsize);
        free_irq(hw->irqnum, hw);
        iounmap(hw->regs);
index 6427600b5bbe66c5d66fbcf967a1b20a008162da..3c0b55125f1eb6b85989a549fc50c51f114b9b0d 100644 (file)
@@ -327,22 +327,23 @@ void pxa2xx_spi_dma_start(struct driver_data *drv_data)
 int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
 {
        struct pxa2xx_spi_master *pdata = drv_data->master_info;
+       struct device *dev = &drv_data->pdev->dev;
        dma_cap_mask_t mask;
 
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
-       drv_data->dummy = devm_kzalloc(&drv_data->pdev->dev, SZ_2K, GFP_KERNEL);
+       drv_data->dummy = devm_kzalloc(dev, SZ_2K, GFP_KERNEL);
        if (!drv_data->dummy)
                return -ENOMEM;
 
-       drv_data->tx_chan = dma_request_channel(mask, pxa2xx_spi_dma_filter,
-                                               pdata);
+       drv_data->tx_chan = dma_request_slave_channel_compat(mask,
+                               pxa2xx_spi_dma_filter, pdata, dev, "tx");
        if (!drv_data->tx_chan)
                return -ENODEV;
 
-       drv_data->rx_chan = dma_request_channel(mask, pxa2xx_spi_dma_filter,
-                                               pdata);
+       drv_data->rx_chan = dma_request_slave_channel_compat(mask,
+                               pxa2xx_spi_dma_filter, pdata, dev, "rx");
        if (!drv_data->rx_chan) {
                dma_release_channel(drv_data->tx_chan);
                drv_data->tx_chan = NULL;
index 48b396fced0acdde9fe6f28cb518a5b3024247c0..f440dcee852b582a2eb3369c5effd94c83fa3737 100644 (file)
@@ -881,21 +881,6 @@ static int setup(struct spi_device *spi)
                rx_thres = RX_THRESH_DFLT;
        }
 
-       if (!pxa25x_ssp_comp(drv_data)
-               && (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
-               dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
-                               "b/w not 4-32 for type non-PXA25x_SSP\n",
-                               drv_data->ssp_type, spi->bits_per_word);
-               return -EINVAL;
-       } else if (pxa25x_ssp_comp(drv_data)
-                       && (spi->bits_per_word < 4
-                               || spi->bits_per_word > 16)) {
-               dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
-                               "b/w not 4-16 for type PXA25x_SSP\n",
-                               drv_data->ssp_type, spi->bits_per_word);
-               return -EINVAL;
-       }
-
        /* Only alloc on first setup */
        chip = spi_get_ctldata(spi);
        if (!chip) {
@@ -1011,9 +996,6 @@ static int setup(struct spi_device *spi)
                chip->n_bytes = 4;
                chip->read = u32_reader;
                chip->write = u32_writer;
-       } else {
-               dev_err(&spi->dev, "invalid wordsize\n");
-               return -ENODEV;
        }
        chip->bits_per_word = spi->bits_per_word;
 
@@ -1040,32 +1022,10 @@ static void cleanup(struct spi_device *spi)
 }
 
 #ifdef CONFIG_ACPI
-static int pxa2xx_spi_acpi_add_dma(struct acpi_resource *res, void *data)
-{
-       struct pxa2xx_spi_master *pdata = data;
-
-       if (res->type == ACPI_RESOURCE_TYPE_FIXED_DMA) {
-               const struct acpi_resource_fixed_dma *dma;
-
-               dma = &res->data.fixed_dma;
-               if (pdata->tx_slave_id < 0) {
-                       pdata->tx_slave_id = dma->request_lines;
-                       pdata->tx_chan_id = dma->channels;
-               } else if (pdata->rx_slave_id < 0) {
-                       pdata->rx_slave_id = dma->request_lines;
-                       pdata->rx_chan_id = dma->channels;
-               }
-       }
-
-       /* Tell the ACPI core to skip this resource */
-       return 1;
-}
-
 static struct pxa2xx_spi_master *
 pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
 {
        struct pxa2xx_spi_master *pdata;
-       struct list_head resource_list;
        struct acpi_device *adev;
        struct ssp_device *ssp;
        struct resource *res;
@@ -1091,7 +1051,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
        ssp->phys_base = res->start;
        ssp->mmio_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(ssp->mmio_base))
-               return PTR_ERR(ssp->mmio_base);
+               return NULL;
 
        ssp->clk = devm_clk_get(&pdev->dev, NULL);
        ssp->irq = platform_get_irq(pdev, 0);
@@ -1103,15 +1063,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
                ssp->port_id = devid;
 
        pdata->num_chipselect = 1;
-       pdata->rx_slave_id = -1;
-       pdata->tx_slave_id = -1;
-
-       INIT_LIST_HEAD(&resource_list);
-       acpi_dev_get_resources(adev, &resource_list, pxa2xx_spi_acpi_add_dma,
-                              pdata);
-       acpi_dev_free_resource_list(&resource_list);
-
-       pdata->enable_dma = pdata->rx_slave_id >= 0 && pdata->tx_slave_id >= 0;
+       pdata->enable_dma = true;
 
        return pdata;
 }
@@ -1119,6 +1071,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
 static struct acpi_device_id pxa2xx_spi_acpi_match[] = {
        { "INT33C0", 0 },
        { "INT33C1", 0 },
+       { "80860F0E", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
@@ -1190,11 +1143,13 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        drv_data->ioaddr = ssp->mmio_base;
        drv_data->ssdr_physical = ssp->phys_base + SSDR;
        if (pxa25x_ssp_comp(drv_data)) {
+               master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
                drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
                drv_data->dma_cr1 = 0;
                drv_data->clear_sr = SSSR_ROR;
                drv_data->mask_sr = SSSR_RFS | SSSR_TFS | SSSR_ROR;
        } else {
+               master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
                drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
                drv_data->dma_cr1 = DEFAULT_DMA_CR1;
                drv_data->clear_sr = SSSR_ROR | SSSR_TINT;
@@ -1214,7 +1169,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        if (platform_info->enable_dma) {
                status = pxa2xx_spi_dma_setup(drv_data);
                if (status) {
-                       dev_warn(dev, "failed to setup DMA, using PIO\n");
+                       dev_dbg(dev, "no DMA channels available, using PIO\n");
                        platform_info->enable_dma = false;
                }
        }
@@ -1299,9 +1254,6 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
        /* Disconnect from the SPI framework */
        spi_unregister_master(drv_data->master);
 
-       /* Prevent double remove */
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 902f2fb902db8c94ee238b456480a18432c644ee..b44a6ac3cec9c682035ade85992a959c474c9559 100644 (file)
@@ -719,7 +719,7 @@ static void rspi_release_dma(struct rspi_data *rspi)
 
 static int rspi_remove(struct platform_device *pdev)
 {
-       struct rspi_data *rspi = dev_get_drvdata(&pdev->dev);
+       struct rspi_data *rspi = platform_get_drvdata(pdev);
 
        spi_unregister_master(rspi->master);
        rspi_release_dma(rspi);
@@ -759,7 +759,7 @@ static int rspi_probe(struct platform_device *pdev)
        }
 
        rspi = spi_master_get_devdata(master);
-       dev_set_drvdata(&pdev->dev, rspi);
+       platform_set_drvdata(pdev, rspi);
 
        rspi->master = master;
        rspi->addr = ioremap(res->start, resource_size(res));
index 02d64603fcc54988f33b1ad74e89a27fdf31a216..68910b3101525e88bf9fcf675f7755ef5d790a04 100644 (file)
@@ -667,8 +667,6 @@ static int s3c24xx_spi_remove(struct platform_device *dev)
 {
        struct s3c24xx_spi *hw = platform_get_drvdata(dev);
 
-       platform_set_drvdata(dev, NULL);
-
        spi_bitbang_stop(&hw->bitbang);
 
        clk_disable(hw->clk);
index 71cc3e6ef47ca770dd73c4d55f8153d42a8471aa..eb53df27e7ea81af4eefa2912da48565724d6aaa 100644 (file)
@@ -39,6 +39,7 @@
 #endif
 
 #define MAX_SPI_PORTS          3
+#define S3C64XX_SPI_QUIRK_POLL         (1 << 0)
 
 /* Registers and bit-fields */
 
 #define S3C64XX_SPI_TRAILCNT           S3C64XX_SPI_MAX_TRAILCNT
 
 #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+#define is_polling(x)  (x->port_conf->quirks & S3C64XX_SPI_QUIRK_POLL)
 
 #define RXBUSY    (1<<2)
 #define TXBUSY    (1<<3)
@@ -158,6 +160,7 @@ struct s3c64xx_spi_port_config {
        int     fifo_lvl_mask[MAX_SPI_PORTS];
        int     rx_lvl_offset;
        int     tx_st_done;
+       int     quirks;
        bool    high_speed;
        bool    clk_from_cmu;
 };
@@ -205,6 +208,7 @@ struct s3c64xx_spi_driver_data {
        struct s3c64xx_spi_port_config  *port_conf;
        unsigned int                    port_id;
        unsigned long                   gpios[4];
+       bool                            cs_gpio;
 };
 
 static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
@@ -344,8 +348,12 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
 {
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
 
-       /* Acquire DMA channels */
-       while (!acquire_dma(sdd))
+       /*
+        * If DMA resource was not available during
+        * probe, no need to continue with dma requests
+        * else Acquire DMA channels
+        */
+       while (!is_polling(sdd) && !acquire_dma(sdd))
                usleep_range(10000, 11000);
 
        pm_runtime_get_sync(&sdd->pdev->dev);
@@ -358,9 +366,12 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
 
        /* Free DMA channels */
-       sdd->ops->release((enum dma_ch)sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
-       sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
-
+       if (!is_polling(sdd)) {
+               sdd->ops->release((enum dma_ch)sdd->rx_dma.ch,
+                                       &s3c64xx_spi_dma_client);
+               sdd->ops->release((enum dma_ch)sdd->tx_dma.ch,
+                                       &s3c64xx_spi_dma_client);
+       }
        pm_runtime_put(&sdd->pdev->dev);
 
        return 0;
@@ -464,8 +475,10 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
 
        /* Free DMA channels */
-       dma_release_channel(sdd->rx_dma.ch);
-       dma_release_channel(sdd->tx_dma.ch);
+       if (!is_polling(sdd)) {
+               dma_release_channel(sdd->rx_dma.ch);
+               dma_release_channel(sdd->tx_dma.ch);
+       }
 
        pm_runtime_put(&sdd->pdev->dev);
        return 0;
@@ -558,14 +571,40 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
                if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
                        /* Deselect the last toggled device */
                        cs = sdd->tgl_spi->controller_data;
-                       gpio_set_value(cs->line,
-                               spi->mode & SPI_CS_HIGH ? 0 : 1);
+                       if (sdd->cs_gpio)
+                               gpio_set_value(cs->line,
+                                       spi->mode & SPI_CS_HIGH ? 0 : 1);
                }
                sdd->tgl_spi = NULL;
        }
 
        cs = spi->controller_data;
-       gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0);
+       if (sdd->cs_gpio)
+               gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0);
+
+       /* Start the signals */
+       writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+}
+
+static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
+                                       int timeout_ms)
+{
+       void __iomem *regs = sdd->regs;
+       unsigned long val = 1;
+       u32 status;
+
+       /* max fifo depth available */
+       u32 max_fifo = (FIFO_LVL_MASK(sdd) >> 1) + 1;
+
+       if (timeout_ms)
+               val = msecs_to_loops(timeout_ms);
+
+       do {
+               status = readl(regs + S3C64XX_SPI_STATUS);
+       } while (RX_FIFO_LVL(status, sdd) < max_fifo && --val);
+
+       /* return the actual received data length */
+       return RX_FIFO_LVL(status, sdd);
 }
 
 static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
@@ -590,20 +629,19 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
                } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
        }
 
-       if (!val)
-               return -EIO;
-
        if (dma_mode) {
                u32 status;
 
                /*
+                * If the previous xfer was completed within timeout, then
+                * proceed further else return -EIO.
                 * DmaTx returns after simply writing data in the FIFO,
                 * w/o waiting for real transmission on the bus to finish.
                 * DmaRx returns only after Dma read data from FIFO which
                 * needs bus transmission to finish, so we don't worry if
                 * Xfer involved Rx(with or without Tx).
                 */
-               if (xfer->rx_buf == NULL) {
+               if (val && !xfer->rx_buf) {
                        val = msecs_to_loops(10);
                        status = readl(regs + S3C64XX_SPI_STATUS);
                        while ((TX_FIFO_LVL(status, sdd)
@@ -613,30 +651,54 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
                                status = readl(regs + S3C64XX_SPI_STATUS);
                        }
 
-                       if (!val)
-                               return -EIO;
                }
+
+               /* If timed out while checking rx/tx status return error */
+               if (!val)
+                       return -EIO;
        } else {
+               int loops;
+               u32 cpy_len;
+               u8 *buf;
+
                /* If it was only Tx */
-               if (xfer->rx_buf == NULL) {
+               if (!xfer->rx_buf) {
                        sdd->state &= ~TXBUSY;
                        return 0;
                }
 
-               switch (sdd->cur_bpw) {
-               case 32:
-                       ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
-                               xfer->rx_buf, xfer->len / 4);
-                       break;
-               case 16:
-                       ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
-                               xfer->rx_buf, xfer->len / 2);
-                       break;
-               default:
-                       ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
-                               xfer->rx_buf, xfer->len);
-                       break;
-               }
+               /*
+                * If the receive length is bigger than the controller fifo
+                * size, calculate the loops and read the fifo as many times.
+                * loops = length / max fifo size (calculated by using the
+                * fifo mask).
+                * For any size less than the fifo size the below code is
+                * executed atleast once.
+                */
+               loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
+               buf = xfer->rx_buf;
+               do {
+                       /* wait for data to be received in the fifo */
+                       cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
+                                               (loops ? ms : 0));
+
+                       switch (sdd->cur_bpw) {
+                       case 32:
+                               ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
+                                       buf, cpy_len / 4);
+                               break;
+                       case 16:
+                               ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
+                                       buf, cpy_len / 2);
+                               break;
+                       default:
+                               ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
+                                       buf, cpy_len);
+                               break;
+                       }
+
+                       buf = buf + cpy_len;
+               } while (loops--);
                sdd->state &= ~RXBUSY;
        }
 
@@ -651,7 +713,11 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
        if (sdd->tgl_spi == spi)
                sdd->tgl_spi = NULL;
 
-       gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1);
+       if (sdd->cs_gpio)
+               gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1);
+
+       /* Quiese the signals */
+       writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
 }
 
 static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
@@ -733,7 +799,7 @@ static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
        struct device *dev = &sdd->pdev->dev;
        struct spi_transfer *xfer;
 
-       if (msg->is_dma_mapped)
+       if (is_polling(sdd) || msg->is_dma_mapped)
                return 0;
 
        /* First mark all xfer unmapped */
@@ -782,7 +848,7 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
        struct device *dev = &sdd->pdev->dev;
        struct spi_transfer *xfer;
 
-       if (msg->is_dma_mapped)
+       if (is_polling(sdd) || msg->is_dma_mapped)
                return;
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
@@ -861,8 +927,9 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
 
                /* Polling method for xfers not bigger than FIFO capacity */
                use_dma = 0;
-               if (sdd->rx_dma.ch && sdd->tx_dma.ch &&
-                   (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1)))
+               if (!is_polling(sdd) &&
+                       (sdd->rx_dma.ch && sdd->tx_dma.ch &&
+                       (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1))))
                        use_dma = 1;
 
                spin_lock_irqsave(&sdd->lock, flags);
@@ -876,17 +943,10 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
                /* Slave Select */
                enable_cs(sdd, spi);
 
-               /* Start the signals */
-               writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
-
                spin_unlock_irqrestore(&sdd->lock, flags);
 
                status = wait_for_xfer(sdd, xfer, use_dma);
 
-               /* Quiese the signals */
-               writel(S3C64XX_SPI_SLAVE_SIG_INACT,
-                      sdd->regs + S3C64XX_SPI_SLAVE_SEL);
-
                if (status) {
                        dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
                                xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
@@ -942,8 +1002,10 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
 {
        struct s3c64xx_spi_csinfo *cs;
        struct device_node *slave_np, *data_np = NULL;
+       struct s3c64xx_spi_driver_data *sdd;
        u32 fb_delay = 0;
 
+       sdd = spi_master_get_devdata(spi->master);
        slave_np = spi->dev.of_node;
        if (!slave_np) {
                dev_err(&spi->dev, "device node not found\n");
@@ -963,7 +1025,10 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
                return ERR_PTR(-ENOMEM);
        }
 
-       cs->line = of_get_named_gpio(data_np, "cs-gpio", 0);
+       /* The CS line is asserted/deasserted by the gpio pin */
+       if (sdd->cs_gpio)
+               cs->line = of_get_named_gpio(data_np, "cs-gpio", 0);
+
        if (!gpio_is_valid(cs->line)) {
                dev_err(&spi->dev, "chip select gpio is not specified or invalid\n");
                kfree(cs);
@@ -1003,7 +1068,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
                return -ENODEV;
        }
 
-       if (!spi_get_ctldata(spi)) {
+       /* Request gpio only if cs line is asserted by gpio pins */
+       if (sdd->cs_gpio) {
                err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH,
                                       dev_name(&spi->dev));
                if (err) {
@@ -1012,9 +1078,11 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
                                cs->line, err);
                        goto err_gpio_req;
                }
-               spi_set_ctldata(spi, cs);
        }
 
+       if (!spi_get_ctldata(spi))
+               spi_set_ctldata(spi, cs);
+
        sci = sdd->cntrlr_info;
 
        spin_lock_irqsave(&sdd->lock, flags);
@@ -1092,8 +1160,10 @@ err_gpio_req:
 static void s3c64xx_spi_cleanup(struct spi_device *spi)
 {
        struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi);
+       struct s3c64xx_spi_driver_data *sdd;
 
-       if (cs) {
+       sdd = spi_master_get_devdata(spi->master);
+       if (cs && sdd->cs_gpio) {
                gpio_free(cs->line);
                if (spi->dev.of_node)
                        kfree(cs);
@@ -1270,7 +1340,11 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        sdd->cntrlr_info = sci;
        sdd->pdev = pdev;
        sdd->sfr_start = mem_res->start;
+       sdd->cs_gpio = true;
        if (pdev->dev.of_node) {
+               if (!of_find_property(pdev->dev.of_node, "cs-gpio", NULL))
+                       sdd->cs_gpio = false;
+
                ret = of_alias_get_id(pdev->dev.of_node, "spi");
                if (ret < 0) {
                        dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
@@ -1287,19 +1361,19 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        if (!sdd->pdev->dev.of_node) {
                res = platform_get_resource(pdev, IORESOURCE_DMA,  0);
                if (!res) {
-                       dev_err(&pdev->dev, "Unable to get SPI tx dma "
-                                       "resource\n");
-                       return -ENXIO;
-               }
-               sdd->tx_dma.dmach = res->start;
+                       dev_warn(&pdev->dev, "Unable to get SPI tx dma "
+                                       "resource. Switching to poll mode\n");
+                       sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
+               } else
+                       sdd->tx_dma.dmach = res->start;
 
                res = platform_get_resource(pdev, IORESOURCE_DMA,  1);
                if (!res) {
-                       dev_err(&pdev->dev, "Unable to get SPI rx dma "
-                                       "resource\n");
-                       return -ENXIO;
-               }
-               sdd->rx_dma.dmach = res->start;
+                       dev_warn(&pdev->dev, "Unable to get SPI rx dma "
+                                       "resource. Switching to poll mode\n");
+                       sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
+               } else
+                       sdd->rx_dma.dmach = res->start;
        }
 
        sdd->tx_dma.direction = DMA_MEM_TO_DEV;
@@ -1314,7 +1388,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
        master->num_chipselect = sci->num_cs;
        master->dma_alignment = 8;
-       master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
+       master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+                                       SPI_BPW_MASK(8);
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 
@@ -1399,7 +1474,6 @@ err3:
 err2:
        clk_disable_unprepare(sdd->clk);
 err0:
-       platform_set_drvdata(pdev, NULL);
        spi_master_put(master);
 
        return ret;
@@ -1420,7 +1494,6 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
 
        clk_disable_unprepare(sdd->clk);
 
-       platform_set_drvdata(pdev, NULL);
        spi_master_put(master);
 
        return 0;
@@ -1535,6 +1608,15 @@ static struct s3c64xx_spi_port_config exynos4_spi_port_config = {
        .clk_from_cmu   = true,
 };
 
+static struct s3c64xx_spi_port_config exynos5440_spi_port_config = {
+       .fifo_lvl_mask  = { 0x1ff },
+       .rx_lvl_offset  = 15,
+       .tx_st_done     = 25,
+       .high_speed     = true,
+       .clk_from_cmu   = true,
+       .quirks         = S3C64XX_SPI_QUIRK_POLL,
+};
+
 static struct platform_device_id s3c64xx_spi_driver_ids[] = {
        {
                .name           = "s3c2443-spi",
@@ -1558,15 +1640,16 @@ static struct platform_device_id s3c64xx_spi_driver_ids[] = {
        { },
 };
 
-#ifdef CONFIG_OF
 static const struct of_device_id s3c64xx_spi_dt_match[] = {
        { .compatible = "samsung,exynos4210-spi",
                        .data = (void *)&exynos4_spi_port_config,
        },
+       { .compatible = "samsung,exynos5440-spi",
+                       .data = (void *)&exynos5440_spi_port_config,
+       },
        { },
 };
 MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
-#endif /* CONFIG_OF */
 
 static struct platform_driver s3c64xx_spi_driver = {
        .driver = {
index eab593eaaafa00f1c269dda9f60a70de72f1d98b..716edf999538ac78a3c38d85d39917e83785a6e8 100644 (file)
@@ -297,7 +297,7 @@ static int hspi_probe(struct platform_device *pdev)
        }
 
        hspi = spi_master_get_devdata(master);
-       dev_set_drvdata(&pdev->dev, hspi);
+       platform_set_drvdata(pdev, hspi);
 
        /* init hspi */
        hspi->master    = master;
@@ -341,7 +341,7 @@ static int hspi_probe(struct platform_device *pdev)
 
 static int hspi_remove(struct platform_device *pdev)
 {
-       struct hspi_priv *hspi = dev_get_drvdata(&pdev->dev);
+       struct hspi_priv *hspi = platform_get_drvdata(pdev);
 
        pm_runtime_disable(&pdev->dev);
 
index 3c3600a994bdfce9284b63e637fc10e7515e4548..c120a70094f20f131cf0ef5e7a3861e57f9eba39 100644 (file)
@@ -434,7 +434,7 @@ static irqreturn_t spi_sh_irq(int irq, void *_ss)
 
 static int spi_sh_remove(struct platform_device *pdev)
 {
-       struct spi_sh_data *ss = dev_get_drvdata(&pdev->dev);
+       struct spi_sh_data *ss = platform_get_drvdata(pdev);
 
        spi_unregister_master(ss->master);
        destroy_workqueue(ss->workqueue);
@@ -471,7 +471,7 @@ static int spi_sh_probe(struct platform_device *pdev)
        }
 
        ss = spi_master_get_devdata(master);
-       dev_set_drvdata(&pdev->dev, ss);
+       platform_set_drvdata(pdev, ss);
 
        switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
        case IORESOURCE_MEM_8BIT:
index 0808cd56bf8d458379aab54c68a595fbf4512969..fc20bcfd90c30dd7bf90faa9eb4cd8785822b38e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/of_gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
-#include <linux/pinctrl/consumer.h>
 
 #define DRIVER_NAME "sirfsoc_spi"
 
@@ -127,7 +126,6 @@ struct sirfsoc_spi {
        void __iomem *base;
        u32 ctrl_freq;  /* SPI controller clock speed */
        struct clk *clk;
-       struct pinctrl *p;
 
        /* rx & tx bufs from the spi_transfer */
        const void *tx;
@@ -142,9 +140,6 @@ struct sirfsoc_spi {
        unsigned int left_tx_cnt;
        unsigned int left_rx_cnt;
 
-       /* tasklet to push tx msg into FIFO */
-       struct tasklet_struct tasklet_tx;
-
        int chipselect[0];
 };
 
@@ -236,17 +231,6 @@ static void spi_sirfsoc_tx_word_u32(struct sirfsoc_spi *sspi)
        sspi->left_tx_cnt--;
 }
 
-static void spi_sirfsoc_tasklet_tx(unsigned long arg)
-{
-       struct sirfsoc_spi *sspi = (struct sirfsoc_spi *)arg;
-
-       /* Fill Tx FIFO while there are left words to be transmitted */
-       while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) &
-                       SIRFSOC_SPI_FIFO_FULL)) &&
-                       sspi->left_tx_cnt)
-               sspi->tx_word(sspi);
-}
-
 static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
 {
        struct sirfsoc_spi *sspi = dev_id;
@@ -261,25 +245,25 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
                writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
        }
 
-       if (spi_stat & SIRFSOC_SPI_FRM_END) {
+       if (spi_stat & (SIRFSOC_SPI_FRM_END
+                       | SIRFSOC_SPI_RXFIFO_THD_REACH))
                while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
                                & SIRFSOC_SPI_FIFO_EMPTY)) &&
                                sspi->left_rx_cnt)
                        sspi->rx_word(sspi);
 
-               /* Received all words */
-               if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) {
-                       complete(&sspi->done);
-                       writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
-               }
-       }
-
-       if (spi_stat & SIRFSOC_SPI_RXFIFO_THD_REACH ||
-               spi_stat & SIRFSOC_SPI_TXFIFO_THD_REACH ||
-               spi_stat & SIRFSOC_SPI_RX_FIFO_FULL ||
-               spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY)
-               tasklet_schedule(&sspi->tasklet_tx);
+       if (spi_stat & (SIRFSOC_SPI_FIFO_EMPTY
+                       | SIRFSOC_SPI_TXFIFO_THD_REACH))
+               while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
+                               & SIRFSOC_SPI_FIFO_FULL)) &&
+                               sspi->left_tx_cnt)
+                       sspi->tx_word(sspi);
 
+       /* Received all words */
+       if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) {
+               complete(&sspi->done);
+               writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
+       }
        return IRQ_HANDLED;
 }
 
@@ -426,9 +410,7 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                                        SIRFSOC_SPI_FIFO_WIDTH_DWORD;
                break;
        default:
-               dev_err(&spi->dev, "Bits per word %d not supported\n",
-                      bits_per_word);
-               return -EINVAL;
+               BUG();
        }
 
        if (!(spi->mode & SPI_CS_HIGH))
@@ -556,26 +538,20 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
        sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer;
        sspi->bitbang.master->setup = spi_sirfsoc_setup;
        master->bus_num = pdev->id;
+       master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(12) |
+                                       SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
        sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
 
-       sspi->p = pinctrl_get_select_default(&pdev->dev);
-       ret = IS_ERR(sspi->p);
-       if (ret)
-               goto free_master;
-
        sspi->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(sspi->clk)) {
                ret = -EINVAL;
-               goto free_pin;
+               goto free_master;
        }
        clk_prepare_enable(sspi->clk);
        sspi->ctrl_freq = clk_get_rate(sspi->clk);
 
        init_completion(&sspi->done);
 
-       tasklet_init(&sspi->tasklet_tx, spi_sirfsoc_tasklet_tx,
-                    (unsigned long)sspi);
-
        writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
        writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
        writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
@@ -594,8 +570,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
 free_clk:
        clk_disable_unprepare(sspi->clk);
        clk_put(sspi->clk);
-free_pin:
-       pinctrl_put(sspi->p);
 free_master:
        spi_master_put(master);
 err_cs:
@@ -618,7 +592,6 @@ static int  spi_sirfsoc_remove(struct platform_device *pdev)
        }
        clk_disable_unprepare(sspi->clk);
        clk_put(sspi->clk);
-       pinctrl_put(sspi->p);
        spi_master_put(master);
        return 0;
 }
index 598eb45e800860b1ee7b2c2dd48a515f0f7f8acf..e8f542ab89351963480a44112fb3ddbc673f1076 100644 (file)
@@ -1041,7 +1041,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "master allocation failed\n");
                return -ENOMEM;
        }
-       dev_set_drvdata(&pdev->dev, master);
+       platform_set_drvdata(pdev, master);
        tspi = spi_master_get_devdata(master);
 
        /* Parse DT */
@@ -1152,7 +1152,7 @@ exit_free_master:
 
 static int tegra_spi_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = dev_get_drvdata(&pdev->dev);
+       struct spi_master *master = platform_get_drvdata(pdev);
        struct tegra_spi_data   *tspi = spi_master_get_devdata(master);
 
        free_irq(tspi->irq, tspi);
index 09df8e22dba0a146c540248cea5374fa0fb13c92..c1d5d95e70ea33f13402b01e2736d7df95c7c8ba 100644 (file)
@@ -480,7 +480,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
        master->num_chipselect = MAX_CHIP_SELECT;
        master->bus_num = -1;
 
-       dev_set_drvdata(&pdev->dev, master);
+       platform_set_drvdata(pdev, master);
        tsd = spi_master_get_devdata(master);
        tsd->master = master;
        tsd->dev = &pdev->dev;
@@ -555,7 +555,7 @@ exit_free_master:
 
 static int tegra_sflash_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = dev_get_drvdata(&pdev->dev);
+       struct spi_master *master = platform_get_drvdata(pdev);
        struct tegra_sflash_data        *tsd = spi_master_get_devdata(master);
 
        free_irq(tsd->irq, tsd);
index 3faf88d003de79a853b87d1b1ad4457768351b81..80490cc11ce53e72794a1546103b90df42c07fc5 100644 (file)
@@ -1089,7 +1089,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
        master->num_chipselect = MAX_CHIP_SELECT;
        master->bus_num = -1;
 
-       dev_set_drvdata(&pdev->dev, master);
+       platform_set_drvdata(pdev, master);
        tspi = spi_master_get_devdata(master);
        tspi->master = master;
        tspi->dev = &pdev->dev;
@@ -1193,7 +1193,7 @@ exit_free_master:
 
 static int tegra_slink_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = dev_get_drvdata(&pdev->dev);
+       struct spi_master *master = platform_get_drvdata(pdev);
        struct tegra_slink_data *tspi = spi_master_get_devdata(master);
 
        free_irq(tspi->irq, tspi);
index 46992cab65f1c2a949716f02351d70e656adc219..10606fcc6efc81bca1fb63cd696cf393290253c1 100644 (file)
@@ -237,14 +237,6 @@ static void ti_ssp_spi_work(struct work_struct *work)
        spin_unlock(&hw->lock);
 }
 
-static int ti_ssp_spi_setup(struct spi_device *spi)
-{
-       if (spi->bits_per_word > 32)
-               return -EINVAL;
-
-       return 0;
-}
-
 static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
 {
        struct ti_ssp_spi       *hw;
@@ -269,12 +261,6 @@ static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
                        dev_err(&spi->dev, "invalid xfer, full duplex\n");
                        return -EINVAL;
                }
-
-               if (t->bits_per_word > 32) {
-                       dev_err(&spi->dev, "invalid xfer width %d\n",
-                               t->bits_per_word);
-                       return -EINVAL;
-               }
        }
 
        spin_lock(&hw->lock);
@@ -337,8 +323,8 @@ static int ti_ssp_spi_probe(struct platform_device *pdev)
        master->bus_num         = pdev->id;
        master->num_chipselect  = pdata->num_cs;
        master->mode_bits       = MODE_BITS;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
        master->flags           = SPI_MASTER_HALF_DUPLEX;
-       master->setup           = ti_ssp_spi_setup;
        master->transfer        = ti_ssp_spi_transfer;
 
        error = spi_register_master(master);
index 637d728fbeb5b3d2c573baf5c19c72e6dd542a3d..dd55707a6aa5fdd155ef286b5cfc6267215d531c 100644 (file)
@@ -367,7 +367,7 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id)
 
        if (reg_spsr_val & SPSR_ORF_BIT) {
                dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__);
-               if (data->current_msg->complete != 0) {
+               if (data->current_msg->complete) {
                        data->transfer_complete = true;
                        data->current_msg->status = -EIO;
                        data->current_msg->complete(data->current_msg->context);
@@ -472,11 +472,6 @@ static int pch_spi_setup(struct spi_device *pspi)
                dev_dbg(&pspi->dev, "%s 8 bits per word\n", __func__);
        }
 
-       if ((pspi->bits_per_word != 8) && (pspi->bits_per_word != 16)) {
-               dev_err(&pspi->dev, "%s Invalid bits per word\n", __func__);
-               return -EINVAL;
-       }
-
        /* Check baud rate setting */
        /* if baud rate of chip is greater than
           max we can support,return error */
@@ -537,17 +532,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
                /* if baud rate has been specified validate the same */
                if (transfer->speed_hz > PCH_MAX_BAUDRATE)
                        transfer->speed_hz = PCH_MAX_BAUDRATE;
-
-               /* if bits per word has been specified validate the same */
-               if (transfer->bits_per_word) {
-                       if ((transfer->bits_per_word != 8)
-                           && (transfer->bits_per_word != 16)) {
-                               retval = -EINVAL;
-                               dev_err(&pspi->dev,
-                                       "%s Invalid bits per word\n", __func__);
-                               goto err_return_spinlock;
-                       }
-               }
        }
        spin_unlock_irqrestore(&data->lock, flags);
 
@@ -659,7 +643,7 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
                list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
                        pmsg->status = -ENOMEM;
 
-                       if (pmsg->complete != 0)
+                       if (pmsg->complete)
                                pmsg->complete(pmsg->context);
 
                        /* delete from queue */
@@ -709,7 +693,7 @@ static void pch_spi_nomore_transfer(struct pch_spi_data *data)
         * [To the spi core..indicating end of transfer] */
        data->current_msg->status = 0;
 
-       if (data->current_msg->complete != 0) {
+       if (data->current_msg->complete) {
                dev_dbg(&data->master->dev,
                        "%s:Invoking callback of SPI core\n", __func__);
                data->current_msg->complete(data->current_msg->context);
@@ -1202,7 +1186,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
                list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
                        pmsg->status = -EIO;
 
-                       if (pmsg->complete != 0) {
+                       if (pmsg->complete) {
                                spin_unlock(&data->lock);
                                pmsg->complete(pmsg->context);
                                spin_lock(&data->lock);
@@ -1442,6 +1426,7 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
        master->setup = pch_spi_setup;
        master->transfer = pch_spi_transfer;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+       master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
 
        data->board_dat = board_dat;
        data->plat_dev = plat_dev;
index adb853047926fef7880e88543c1a4555e433b243..e9b7681ff6ac6c65f53812d7562f9d2babc3a090 100644 (file)
@@ -116,17 +116,12 @@ static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
 static int txx9spi_setup(struct spi_device *spi)
 {
        struct txx9spi *c = spi_master_get_devdata(spi->master);
-       u8 bits_per_word;
 
        if (!spi->max_speed_hz
                        || spi->max_speed_hz > c->max_speed_hz
                        || spi->max_speed_hz < c->min_speed_hz)
                return -EINVAL;
 
-       bits_per_word = spi->bits_per_word;
-       if (bits_per_word != 8 && bits_per_word != 16)
-               return -EINVAL;
-
        if (gpio_direction_output(spi->chip_select,
                        !(spi->mode & SPI_CS_HIGH))) {
                dev_err(&spi->dev, "Cannot setup GPIO for chipselect.\n");
@@ -319,8 +314,6 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
 
                if (!t->tx_buf && !t->rx_buf && t->len)
                        return -EINVAL;
-               if (bits_per_word != 8 && bits_per_word != 16)
-                       return -EINVAL;
                if (t->len & ((bits_per_word >> 3) - 1))
                        return -EINVAL;
                if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz)
@@ -411,6 +404,7 @@ static int txx9spi_probe(struct platform_device *dev)
        master->setup = txx9spi_setup;
        master->transfer = txx9spi_transfer;
        master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
+       master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
 
        ret = spi_register_master(master);
        if (ret)
@@ -425,7 +419,6 @@ exit:
                clk_disable(c->clk);
                clk_put(c->clk);
        }
-       platform_set_drvdata(dev, NULL);
        spi_master_put(master);
        return ret;
 }
@@ -436,7 +429,6 @@ static int txx9spi_remove(struct platform_device *dev)
        struct txx9spi *c = spi_master_get_devdata(master);
 
        spi_unregister_master(master);
-       platform_set_drvdata(dev, NULL);
        destroy_workqueue(c->workqueue);
        clk_disable(c->clk);
        clk_put(c->clk);
index 4d3ec8b9f4791cd2df02b0ec7a715af5e3ae7515..4258c712ad3c273d5f8ab571e9b3f829d0f256cf 100644 (file)
@@ -76,7 +76,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
 {
        unsigned int speed;
 
-       if ((t->bits_per_word && t->bits_per_word != 8) || t->len > 62)
+       if (t->len > 62)
                return -EINVAL;
 
        speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
@@ -209,14 +209,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
        return status;
 }
 
-static int spi_xcomm_setup(struct spi_device *spi)
-{
-       if (spi->bits_per_word != 8)
-               return -EINVAL;
-
-       return 0;
-}
-
 static int spi_xcomm_probe(struct i2c_client *i2c,
        const struct i2c_device_id *id)
 {
@@ -233,8 +225,8 @@ static int spi_xcomm_probe(struct i2c_client *i2c,
 
        master->num_chipselect = 16;
        master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_3WIRE;
+       master->bits_per_word_mask = SPI_BPW_MASK(8);
        master->flags = SPI_MASTER_HALF_DUPLEX;
-       master->setup = spi_xcomm_setup;
        master->transfer_one_message = spi_xcomm_transfer_one;
        master->dev.of_node = i2c->dev.of_node;
        i2c_set_clientdata(i2c, master);
index 34d18dcfa0db3c4da739129b1d1008f18ee06cfc..fb56fcfdf65e76b3110ea75bdbb6d9f61141cb93 100644 (file)
@@ -30,6 +30,7 @@
  */
 #define XSPI_CR_OFFSET         0x60    /* Control Register */
 
+#define XSPI_CR_LOOP           0x01
 #define XSPI_CR_ENABLE         0x02
 #define XSPI_CR_MASTER_MODE    0x04
 #define XSPI_CR_CPOL           0x08
@@ -232,21 +233,6 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
        return 0;
 }
 
-static int xilinx_spi_setup(struct spi_device *spi)
-{
-       /* always return 0, we can not check the number of bits.
-        * There are cases when SPI setup is called before any driver is
-        * there, in that case the SPI core defaults to 8 bits, which we
-        * do not support in some cases. But if we return an error, the
-        * SPI device would not be registered and no driver can get hold of it
-        * When the driver is there, it will call SPI setup again with the
-        * correct number of bits per transfer.
-        * If a driver setups with the wrong bit number, it will fail when
-        * it tries to do a transfer
-        */
-       return 0;
-}
-
 static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
 {
        u8 sr;
@@ -315,7 +301,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
                }
 
                /* See if there is more data to send */
-               if (!xspi->remaining_bytes > 0)
+               if (xspi->remaining_bytes <= 0)
                        break;
        }
 
@@ -355,11 +341,12 @@ static const struct of_device_id xilinx_spi_of_match[] = {
 MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
 
 struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
-       u32 irq, s16 bus_num, int num_cs, int little_endian, int bits_per_word)
+       u32 irq, s16 bus_num, int num_cs, int bits_per_word)
 {
        struct spi_master *master;
        struct xilinx_spi *xspi;
        int ret;
+       u32 tmp;
 
        master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
        if (!master)
@@ -373,7 +360,6 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
        xspi->bitbang.chipselect = xilinx_spi_chipselect;
        xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
        xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
-       xspi->bitbang.master->setup = xilinx_spi_setup;
        init_completion(&xspi->done);
 
        if (!request_mem_region(mem->start, resource_size(mem),
@@ -392,13 +378,25 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
 
        xspi->mem = *mem;
        xspi->irq = irq;
-       if (little_endian) {
-               xspi->read_fn = xspi_read32;
-               xspi->write_fn = xspi_write32;
-       } else {
+
+       /*
+        * Detect endianess on the IP via loop bit in CR. Detection
+        * must be done before reset is sent because incorrect reset
+        * value generates error interrupt.
+        * Setup little endian helper functions first and try to use them
+        * and check if bit was correctly setup or not.
+        */
+       xspi->read_fn = xspi_read32;
+       xspi->write_fn = xspi_write32;
+
+       xspi->write_fn(XSPI_CR_LOOP, xspi->regs + XSPI_CR_OFFSET);
+       tmp = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
+       tmp &= XSPI_CR_LOOP;
+       if (tmp != XSPI_CR_LOOP) {
                xspi->read_fn = xspi_read32_be;
                xspi->write_fn = xspi_write32_be;
        }
+
        xspi->bits_per_word = bits_per_word;
        if (xspi->bits_per_word == 8) {
                xspi->tx_fn = xspi_tx8;
@@ -462,14 +460,13 @@ static int xilinx_spi_probe(struct platform_device *dev)
 {
        struct xspi_platform_data *pdata;
        struct resource *r;
-       int irq, num_cs = 0, little_endian = 0, bits_per_word = 8;
+       int irq, num_cs = 0, bits_per_word = 8;
        struct spi_master *master;
        u8 i;
 
        pdata = dev->dev.platform_data;
        if (pdata) {
                num_cs = pdata->num_chipselect;
-               little_endian = pdata->little_endian;
                bits_per_word = pdata->bits_per_word;
        }
 
@@ -501,7 +498,7 @@ static int xilinx_spi_probe(struct platform_device *dev)
                return -ENXIO;
 
        master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs,
-                                little_endian, bits_per_word);
+                                bits_per_word);
        if (!master)
                return -ENODEV;
 
@@ -517,7 +514,6 @@ static int xilinx_spi_probe(struct platform_device *dev)
 static int xilinx_spi_remove(struct platform_device *dev)
 {
        xilinx_spi_deinit(platform_get_drvdata(dev));
-       platform_set_drvdata(dev, 0);
 
        return 0;
 }
index 32b7bb111eb6b53d9e96808f7bd5fd0982cffd9d..978dda2c523982f62c676573feb1955da0ca82da 100644 (file)
@@ -223,7 +223,7 @@ static const struct dev_pm_ops spi_pm = {
        SET_RUNTIME_PM_OPS(
                pm_generic_runtime_suspend,
                pm_generic_runtime_resume,
-               pm_generic_runtime_idle
+               NULL
        )
 };
 
@@ -601,7 +601,7 @@ static int spi_init_queue(struct spi_master *master)
 
        init_kthread_worker(&master->kworker);
        master->kworker_task = kthread_run(kthread_worker_fn,
-                                          &master->kworker,
+                                          &master->kworker, "%s",
                                           dev_name(&master->dev));
        if (IS_ERR(master->kworker_task)) {
                dev_err(&master->dev, "failed to create message pump task\n");
index c6dc1846943fbe06d21974a2c6adb453d6d6f388..119d486a5cf7fa76dad2fa49593b03e5f169b29a 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/cacheflush.h>
 #include <linux/fdtable.h>
 #include <linux/file.h>
+#include <linux/freezer.h>
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/miscdevice.h>
@@ -2140,13 +2141,13 @@ retry:
                        if (!binder_has_proc_work(proc, thread))
                                ret = -EAGAIN;
                } else
-                       ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));
+                       ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
        } else {
                if (non_block) {
                        if (!binder_has_thread_work(thread))
                                ret = -EAGAIN;
                } else
-                       ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));
+                       ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
        }
 
        binder_lock(__func__);
index 9bd874789ce5fc93906a78f62a68e542541bd288..080abf2faf972ab3b999ac58f923c03dbec7e9b8 100644 (file)
@@ -696,7 +696,7 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        ret = -EBADF;
                        break;
                }
-               if (!(in_egroup_p(file->f_dentry->d_inode->i_gid) ||
+               if (!(in_egroup_p(file_inode(file)->i_gid) ||
                                capable(CAP_SYSLOG))) {
                        ret = -EPERM;
                        break;
index ec9e2ae2de0da21f24451335c64fccc7a27b75be..ee3a57f22832ba9bd5ccba77139f8df476d34e3f 100644 (file)
@@ -78,7 +78,7 @@ int timed_output_dev_register(struct timed_output_dev *tdev)
 
        tdev->index = atomic_inc_return(&device_count);
        tdev->dev = device_create(timed_output_class, NULL,
-               MKDEV(0, tdev->index), NULL, tdev->name);
+               MKDEV(0, tdev->index), NULL, "%s", tdev->name);
        if (IS_ERR(tdev->dev))
                return PTR_ERR(tdev->dev);
 
index 0794aacc928ad649bc9f2fe7370ed7fb30c1aa1a..8647518259f6dd5ab3379babc218d5ef6cf24831 100644 (file)
@@ -2329,9 +2329,6 @@ static int comedi_close(struct inode *inode, struct file *file)
 
        mutex_unlock(&dev->mutex);
 
-       if (file->f_flags & FASYNC)
-               comedi_fasync(-1, file, 0);
-
        return 0;
 }
 
index 7d1b36d1e75fc57f8120c06c16754c20e5bddc40..8cee9c8bc38b1850b8bdcc3edad37e91a6996515 100644 (file)
@@ -273,7 +273,7 @@ void dgrp_create_node_class_sysfs_files(struct nd_struct *nd)
                sprintf(name, "node%ld", nd->nd_major);
 
        nd->nd_class_dev = device_create(dgrp_class, dgrp_class_nodes_dev,
-               MKDEV(0, nd->nd_major), NULL, name);
+               MKDEV(0, nd->nd_major), NULL, "%s", name);
 
        ret = sysfs_create_group(&nd->nd_class_dev->kobj,
                                 &dgrp_node_attribute_group);
index 34f3b6d02d2a4075b423d1adcca0c62b5f949c96..9a4296c2e3ab9fc120e893d35382fbab2af88cca 100644 (file)
@@ -1,7 +1,8 @@
 config SOLO6X10
        tristate "Softlogic 6x10 MPEG codec cards"
        depends on PCI && VIDEO_DEV && SND && I2C
-       depends on FONTS
+       select FONT_SUPPORT
+       select FONT_8x16
        select VIDEOBUF2_DMA_SG
        select VIDEOBUF2_DMA_CONTIG
        select SND_PCM
index b65bf5e177a84efc1aac4f63c2be7d0b58a52cd9..6e81ba0eaf1e5542346c7a04121333d4193aedc4 100644 (file)
@@ -238,7 +238,7 @@ struct net_device *r8712_init_netdev(void)
 
 static u32 start_drv_threads(struct _adapter *padapter)
 {
-       padapter->cmdThread = kthread_run(r8712_cmd_thread, padapter,
+       padapter->cmdThread = kthread_run(r8712_cmd_thread, padapter, "%s",
                              padapter->pnetdev->name);
        if (IS_ERR(padapter->cmdThread) < 0)
                return _FAIL;
index 9c020562c84637ca85d8d9e5ffe768c8b7809440..6d04eb48bfbce9362862d47e28b6d3d1a0b84be0 100644 (file)
@@ -421,12 +421,11 @@ static int omap3_bridge_startup(struct platform_device *pdev)
        drv_datap->tc_wordswapon = tc_wordswapon;
 
        if (base_img) {
-               drv_datap->base_img = kmalloc(strlen(base_img) + 1, GFP_KERNEL);
+               drv_datap->base_img = kstrdup(base_img, GFP_KERNEL);
                if (!drv_datap->base_img) {
                        err = -ENOMEM;
                        goto err2;
                }
-               strncpy(drv_datap->base_img, base_img, strlen(base_img) + 1);
        }
 
        dev_set_drvdata(bridge, drv_datap);
index ad41319d1d9b028eaeba3d0dcd08db5e745c0b78..28b35ad9c6cd361818d94c0cde6ee2aa987979c0 100644 (file)
@@ -150,10 +150,6 @@ struct pl011_dmatx_data {
 struct uart_amba_port {
        struct uart_port        port;
        struct clk              *clk;
-       /* Two optional pin states - default & sleep */
-       struct pinctrl          *pinctrl;
-       struct pinctrl_state    *pins_default;
-       struct pinctrl_state    *pins_sleep;
        const struct vendor_data *vendor;
        unsigned int            dmacr;          /* dma control reg */
        unsigned int            im;             /* interrupt mask */
@@ -1479,12 +1475,7 @@ static int pl011_hwinit(struct uart_port *port)
        int retval;
 
        /* Optionaly enable pins to be muxed in and configured */
-       if (!IS_ERR(uap->pins_default)) {
-               retval = pinctrl_select_state(uap->pinctrl, uap->pins_default);
-               if (retval)
-                       dev_err(port->dev,
-                               "could not set default pins\n");
-       }
+       pinctrl_pm_select_default_state(port->dev);
 
        /*
         * Try to enable the clock producer.
@@ -1610,7 +1601,6 @@ static void pl011_shutdown(struct uart_port *port)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
        unsigned int cr;
-       int retval;
 
        /*
         * disable all interrupts
@@ -1653,13 +1643,7 @@ static void pl011_shutdown(struct uart_port *port)
         */
        clk_disable_unprepare(uap->clk);
        /* Optionally let pins go into sleep states */
-       if (!IS_ERR(uap->pins_sleep)) {
-               retval = pinctrl_select_state(uap->pinctrl, uap->pins_sleep);
-               if (retval)
-                       dev_err(port->dev,
-                               "could not set pins to sleep state\n");
-       }
-
+       pinctrl_pm_select_sleep_state(port->dev);
 
        if (uap->port.dev->platform_data) {
                struct amba_pl011_data *plat;
@@ -2012,12 +1996,7 @@ static int __init pl011_console_setup(struct console *co, char *options)
                return -ENODEV;
 
        /* Allow pins to be muxed in and configured */
-       if (!IS_ERR(uap->pins_default)) {
-               ret = pinctrl_select_state(uap->pinctrl, uap->pins_default);
-               if (ret)
-                       dev_err(uap->port.dev,
-                               "could not set default pins\n");
-       }
+       pinctrl_pm_select_default_state(uap->port.dev);
 
        ret = clk_prepare(uap->clk);
        if (ret)
@@ -2131,21 +2110,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
                goto out;
        }
 
-       uap->pinctrl = devm_pinctrl_get(&dev->dev);
-       if (IS_ERR(uap->pinctrl)) {
-               ret = PTR_ERR(uap->pinctrl);
-               goto out;
-       }
-       uap->pins_default = pinctrl_lookup_state(uap->pinctrl,
-                                                PINCTRL_STATE_DEFAULT);
-       if (IS_ERR(uap->pins_default))
-               dev_err(&dev->dev, "could not get default pinstate\n");
-
-       uap->pins_sleep = pinctrl_lookup_state(uap->pinctrl,
-                                              PINCTRL_STATE_SLEEP);
-       if (IS_ERR(uap->pins_sleep))
-               dev_dbg(&dev->dev, "could not get sleep pinstate\n");
-
        uap->clk = devm_clk_get(&dev->dev, NULL);
        if (IS_ERR(uap->clk)) {
                ret = PTR_ERR(uap->clk);
index e266eca0ec7642d26dfeae72d70d0170b7308fc0..4a82267af83fcc95786a79df2b260b84a5dea931 100644 (file)
@@ -1252,13 +1252,8 @@ static int serial_hsu_resume(struct pci_dev *pdev)
 #ifdef CONFIG_PM_RUNTIME
 static int serial_hsu_runtime_idle(struct device *dev)
 {
-       int err;
-
-       err = pm_schedule_suspend(dev, 500);
-       if (err)
-               return -EBUSY;
-
-       return 0;
+       pm_schedule_suspend(dev, 500);
+       return -EBUSY;
 }
 
 static int serial_hsu_runtime_suspend(struct device *dev)
index d7799deacb21a66805d8e4308bcc199b64894fbf..14a2b5f11bcab9739ea6bc23c5bb4134f1b37f1c 100644 (file)
@@ -188,22 +188,7 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
        console_unlock();
        if (size < 0)
                return size;
-       switch (orig) {
-               default:
-                       return -EINVAL;
-               case 2:
-                       offset += size;
-                       break;
-               case 1:
-                       offset += file->f_pos;
-               case 0:
-                       break;
-       }
-       if (offset < 0 || offset > size) {
-               return -EINVAL;
-       }
-       file->f_pos = offset;
-       return file->f_pos;
+       return fixed_size_llseek(file, offset, orig, size);
 }
 
 
index b645c47501b42cc4765073fa6a5d2d2bfaf60396..3b96f18593b392b8680c4e3dd6e5f188c5001c65 100644 (file)
@@ -677,7 +677,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
        if (mi < 0)
                return -EINVAL;
 
-       requested_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       requested_pages = vma_pages(vma);
        actual_pages = ((idev->info->mem[mi].addr & ~PAGE_MASK)
                        + idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT;
        if (requested_pages > actual_pages)
index d3527dd8b90cc17e518ca5324ec517a265a8798b..5e0d33a7da58de75222807f17a915c373575ca8c 100644 (file)
@@ -1020,7 +1020,7 @@ static int usbatm_heavy_init(struct usbatm_data *instance)
 {
        struct task_struct *t;
 
-       t = kthread_create(usbatm_do_heavy_init, instance,
+       t = kthread_create(usbatm_do_heavy_init, instance, "%s",
                        instance->driver->driver_name);
        if (IS_ERR(t)) {
                usb_err(instance, "%s: failed to create kernel_thread (%ld)!\n",
@@ -1076,7 +1076,8 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
        /* public fields */
 
        instance->driver = driver;
-       snprintf(instance->driver_name, sizeof(instance->driver_name), driver->driver_name);
+       strlcpy(instance->driver_name, driver->driver_name,
+               sizeof(instance->driver_name));
 
        instance->usb_dev = usb_dev;
        instance->usb_intf = intf;
index 6eab440e1542e450f7733fb4cbbf35b1b1044313..7609ac4aed1cdc29493b3924c76b254cfdd09cae 100644 (file)
@@ -1765,7 +1765,8 @@ int usb_runtime_idle(struct device *dev)
         */
        if (autosuspend_check(udev) == 0)
                pm_runtime_autosuspend(dev);
-       return 0;
+       /* Tell the core not to suspend it, though. */
+       return -EBUSY;
 }
 
 int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
index 5fd3fee58f8b9ebc746e2e9372da5be94ee478b8..d6b0fadf53e9de9d3c8b074c50be95b301e176e4 100644 (file)
@@ -141,7 +141,6 @@ static const struct dev_pm_ops usb_port_pm_ops = {
 #ifdef CONFIG_PM_RUNTIME
        .runtime_suspend =      usb_port_runtime_suspend,
        .runtime_resume =       usb_port_runtime_resume,
-       .runtime_idle =         pm_generic_runtime_idle,
 #endif
 };
 
index 0d03a52004822417c4daba49b5afc814af0314d2..36bc28c884ad75afd2c5dbe4dcca4543236aa909 100644 (file)
@@ -2,6 +2,7 @@
 config USB_SISUSBVGA
        tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
        depends on (USB_MUSB_HDRC || USB_EHCI_HCD)
+       select FONT_SUPPORT if USB_SISUSBVGA_CON
         ---help---
          Say Y here if you intend to attach a USB2VGA dongle based on a
          Net2280 and a SiS315 chip.
index 5241f1d0ef7a3d3b3bb878a1729c6f93b98144c1..9209eafc75b1f004e407965c32c3a683abdf5ed2 100644 (file)
@@ -440,7 +440,7 @@ void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce)
        uwb_dev_init(uwb_dev);          /* This sets refcnt to one, we own it */
        uwb_dev->mac_addr = *bce->mac_addr;
        uwb_dev->dev_addr = bce->dev_addr;
-       dev_set_name(&uwb_dev->dev, macbuf);
+       dev_set_name(&uwb_dev->dev, "%s", macbuf);
        result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc);
        if (result < 0) {
                dev_err(dev, "new device %s: cannot instantiate device\n",
index a60d6afca97c99902a4ec32529a1cb3eb151fa3a..0393d827dd44bcfa6f472d78c11823892b944af3 100644 (file)
@@ -195,7 +195,6 @@ static int __init atmel_pwm_bl_probe(struct platform_device *pdev)
        return 0;
 
 err_free_bl_dev:
-       platform_set_drvdata(pdev, NULL);
        backlight_device_unregister(bldev);
 err_free_pwm:
        pwm_channel_free(&pwmbl->pwmc);
@@ -212,7 +211,6 @@ static int __exit atmel_pwm_bl_remove(struct platform_device *pdev)
        pwm_channel_disable(&pwmbl->pwmc);
        pwm_channel_free(&pwmbl->pwmc);
        backlight_device_unregister(pwmbl->bldev);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index c74e7aa467312097de2944452ad428ab8fe41b46..3fccb6d3c8c343ee1735811a0fc184270e869bbc 100644 (file)
@@ -208,7 +208,8 @@ static ssize_t backlight_show_actual_brightness(struct device *dev,
 
 static struct class *backlight_class;
 
-static int backlight_suspend(struct device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int backlight_suspend(struct device *dev)
 {
        struct backlight_device *bd = to_backlight_device(dev);
 
@@ -235,6 +236,10 @@ static int backlight_resume(struct device *dev)
 
        return 0;
 }
+#endif
+
+static SIMPLE_DEV_PM_OPS(backlight_class_dev_pm_ops, backlight_suspend,
+                        backlight_resume);
 
 static void bl_device_release(struct device *dev)
 {
@@ -304,7 +309,7 @@ struct backlight_device *backlight_device_register(const char *name,
        new_bd->dev.class = backlight_class;
        new_bd->dev.parent = parent;
        new_bd->dev.release = bl_device_release;
-       dev_set_name(&new_bd->dev, name);
+       dev_set_name(&new_bd->dev, "%s", name);
        dev_set_drvdata(&new_bd->dev, devdata);
 
        /* Set default properties */
@@ -370,6 +375,81 @@ void backlight_device_unregister(struct backlight_device *bd)
 }
 EXPORT_SYMBOL(backlight_device_unregister);
 
+static void devm_backlight_device_release(struct device *dev, void *res)
+{
+       struct backlight_device *backlight = *(struct backlight_device **)res;
+
+       backlight_device_unregister(backlight);
+}
+
+static int devm_backlight_device_match(struct device *dev, void *res,
+                                       void *data)
+{
+       struct backlight_device **r = res;
+
+       return *r == data;
+}
+
+/**
+ * devm_backlight_device_register - resource managed backlight_device_register()
+ * @dev: the device to register
+ * @name: the name of the device
+ * @parent: a pointer to the parent device
+ * @devdata: an optional pointer to be stored for private driver use
+ * @ops: the backlight operations structure
+ * @props: the backlight properties
+ *
+ * @return a struct backlight on success, or an ERR_PTR on error
+ *
+ * Managed backlight_device_register(). The backlight_device returned
+ * from this function are automatically freed on driver detach.
+ * See backlight_device_register() for more information.
+ */
+struct backlight_device *devm_backlight_device_register(struct device *dev,
+       const char *name, struct device *parent, void *devdata,
+       const struct backlight_ops *ops,
+       const struct backlight_properties *props)
+{
+       struct backlight_device **ptr, *backlight;
+
+       ptr = devres_alloc(devm_backlight_device_release, sizeof(*ptr),
+                       GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
+       backlight = backlight_device_register(name, parent, devdata, ops,
+                                               props);
+       if (!IS_ERR(backlight)) {
+               *ptr = backlight;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return backlight;
+}
+EXPORT_SYMBOL(devm_backlight_device_register);
+
+/**
+ * devm_backlight_device_unregister - resource managed backlight_device_unregister()
+ * @dev: the device to unregister
+ * @bd: the backlight device to unregister
+ *
+ * Deallocated a backlight allocated with devm_backlight_device_register().
+ * Normally this function will not need to be called and the resource management
+ * code will ensure that the resource is freed.
+ */
+void devm_backlight_device_unregister(struct device *dev,
+                               struct backlight_device *bd)
+{
+       int rc;
+
+       rc = devres_release(dev, devm_backlight_device_release,
+                               devm_backlight_device_match, bd);
+       WARN_ON(rc);
+}
+EXPORT_SYMBOL(devm_backlight_device_unregister);
+
 #ifdef CONFIG_OF
 static int of_parent_match(struct device *dev, const void *data)
 {
@@ -414,8 +494,7 @@ static int __init backlight_class_init(void)
        }
 
        backlight_class->dev_attrs = bl_device_attributes;
-       backlight_class->suspend = backlight_suspend;
-       backlight_class->resume = backlight_resume;
+       backlight_class->pm = &backlight_class_dev_pm_ops;
        return 0;
 }
 
index 33455821dd312acb61034ab0e3c829e6c05a5faa..018368ba4124f0b77f61a4c203b517d20f9b531d 100644 (file)
@@ -111,7 +111,6 @@ static int ep93xxbl_remove(struct platform_device *dev)
        struct backlight_device *bl = platform_get_drvdata(dev);
 
        backlight_device_unregister(bl);
-       platform_set_drvdata(dev, NULL);
        return 0;
 }
 
index 34fb6bd798c84bb82e79b7f651a380b0547955cd..41964a71a036c676c7ff256f190cb7186c245b6c 100644 (file)
@@ -219,7 +219,7 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent,
        new_ld->dev.class = lcd_class;
        new_ld->dev.parent = parent;
        new_ld->dev.release = lcd_device_release;
-       dev_set_name(&new_ld->dev, name);
+       dev_set_name(&new_ld->dev, "%s", name);
        dev_set_drvdata(&new_ld->dev, devdata);
 
        rc = device_register(&new_ld->dev);
@@ -260,6 +260,76 @@ void lcd_device_unregister(struct lcd_device *ld)
 }
 EXPORT_SYMBOL(lcd_device_unregister);
 
+static void devm_lcd_device_release(struct device *dev, void *res)
+{
+       struct lcd_device *lcd = *(struct lcd_device **)res;
+
+       lcd_device_unregister(lcd);
+}
+
+static int devm_lcd_device_match(struct device *dev, void *res, void *data)
+{
+       struct lcd_device **r = res;
+
+       return *r == data;
+}
+
+/**
+ * devm_lcd_device_register - resource managed lcd_device_register()
+ * @dev: the device to register
+ * @name: the name of the device
+ * @parent: a pointer to the parent device
+ * @devdata: an optional pointer to be stored for private driver use
+ * @ops: the lcd operations structure
+ *
+ * @return a struct lcd on success, or an ERR_PTR on error
+ *
+ * Managed lcd_device_register(). The lcd_device returned from this function
+ * are automatically freed on driver detach. See lcd_device_register()
+ * for more information.
+ */
+struct lcd_device *devm_lcd_device_register(struct device *dev,
+               const char *name, struct device *parent,
+               void *devdata, struct lcd_ops *ops)
+{
+       struct lcd_device **ptr, *lcd;
+
+       ptr = devres_alloc(devm_lcd_device_release, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return ERR_PTR(-ENOMEM);
+
+       lcd = lcd_device_register(name, parent, devdata, ops);
+       if (!IS_ERR(lcd)) {
+               *ptr = lcd;
+               devres_add(dev, ptr);
+       } else {
+               devres_free(ptr);
+       }
+
+       return lcd;
+}
+EXPORT_SYMBOL(devm_lcd_device_register);
+
+/**
+ * devm_lcd_device_unregister - resource managed lcd_device_unregister()
+ * @dev: the device to unregister
+ * @ld: the lcd device to unregister
+ *
+ * Deallocated a lcd allocated with devm_lcd_device_register(). Normally
+ * this function will not need to be called and the resource management
+ * code will ensure that the resource is freed.
+ */
+void devm_lcd_device_unregister(struct device *dev, struct lcd_device *ld)
+{
+       int rc;
+
+       rc = devres_release(dev, devm_lcd_device_release,
+                               devm_lcd_device_match, ld);
+       WARN_ON(rc);
+}
+EXPORT_SYMBOL(devm_lcd_device_unregister);
+
+
 static void __exit lcd_class_exit(void)
 {
        class_destroy(lcd_class);
index 4bb8b4f140cf3e2386790136af45843047bdbe16..980855ec9bb10c2c8421f59a48a65bd9a82af60f 100644 (file)
@@ -312,7 +312,6 @@ static int lp8788_backlight_remove(struct platform_device *pdev)
        backlight_update_status(bl_dev);
        sysfs_remove_group(&pdev->dev.kobj, &lp8788_attr_group);
        lp8788_backlight_unregister(bl);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index e87c7a3394f3adc2cf1782b11366e5539c3f1580..6ed76be18f1943e55fd7ad405c490a8749833358 100644 (file)
@@ -153,8 +153,6 @@ static int pcf50633_bl_remove(struct platform_device *pdev)
 
        backlight_device_unregister(pcf_bl->bl);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index bc922c47d046ef043c3e81e528aabbb9edb5233c..8c30603e0a86f6b2c6dfaa51d398621ad4529328 100644 (file)
@@ -6,7 +6,9 @@ menu "Console display driver support"
 
 config VGA_CONSOLE
        bool "VGA text console" if EXPERT || !X86
-       depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER)
+       depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && \
+               !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && !CRIS && \
+               (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER)
        default y
        help
          Saying Y here will allow you to use Linux in text mode through a
@@ -62,6 +64,7 @@ config MDA_CONSOLE
 config SGI_NEWPORT_CONSOLE
         tristate "SGI Newport Console support"
         depends on SGI_IP22 
+        select FONT_SUPPORT
         help
           Say Y here if you want the console on the Newport aka XL graphics
           card of your Indy.  Most people say Y here.
@@ -91,6 +94,7 @@ config FRAMEBUFFER_CONSOLE
        tristate "Framebuffer Console support"
        depends on FB
        select CRC32
+       select FONT_SUPPORT
        help
          Low-level framebuffer-based console driver.
 
@@ -123,120 +127,12 @@ config FRAMEBUFFER_CONSOLE_ROTATION
 config STI_CONSOLE
         bool "STI text console"
         depends on PARISC
+        select FONT_SUPPORT
         default y
         help
           The STI console is the builtin display/keyboard on HP-PARISC
           machines.  Say Y here to build support for it into your kernel.
           The alternative is to use your primary serial port as a console.
 
-config FONTS
-       bool "Select compiled-in fonts"
-       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
-       help
-         Say Y here if you would like to use fonts other than the default
-         your frame buffer console usually use.
-
-         Note that the answer to this question won't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about foreign fonts.
-
-         If unsure, say N (the default choices are safe).
-
-config FONT_8x8
-       bool "VGA 8x8 font" if FONTS
-       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
-       default y if !SPARC && !FONTS
-       help
-         This is the "high resolution" font for the VGA frame buffer (the one
-         provided by the text console 80x50 (and higher) modes).
-
-         Note that this is a poor quality font. The VGA 8x16 font is quite a
-         lot more readable.
-
-         Given the resolution provided by the frame buffer device, answer N
-         here is safe.
-
-config FONT_8x16
-       bool "VGA 8x16 font" if FONTS
-       depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE || STI_CONSOLE || USB_SISUSBVGA_CON
-       default y if !SPARC && !FONTS
-       help
-         This is the "high resolution" font for the VGA frame buffer (the one
-         provided by the VGA text console 80x25 mode.
-
-         If unsure, say Y.
-
-config FONT_6x11
-       bool "Mac console 6x11 font (not supported by all drivers)" if FONTS
-       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
-       default y if !SPARC && !FONTS && MAC
-       help
-         Small console font with Macintosh-style high-half glyphs.  Some Mac
-         framebuffer drivers don't support this one at all.
-
-config FONT_7x14
-       bool "console 7x14 font (not supported by all drivers)" if FONTS
-       depends on FRAMEBUFFER_CONSOLE
-       help
-         Console font with characters just a bit smaller than the default.
-         If the standard 8x16 font is a little too big for you, say Y.
-         Otherwise, say N.
-
-config FONT_PEARL_8x8
-       bool "Pearl (old m68k) console 8x8 font" if FONTS
-       depends on FRAMEBUFFER_CONSOLE
-       default y if !SPARC && !FONTS && AMIGA
-       help
-         Small console font with PC-style control-character and high-half
-         glyphs.
-
-config FONT_ACORN_8x8
-       bool "Acorn console 8x8 font" if FONTS
-       depends on FRAMEBUFFER_CONSOLE
-       default y if !SPARC && !FONTS && ARM && ARCH_ACORN
-       help
-         Small console font with PC-style control characters and high-half
-         glyphs.
-
-config FONT_MINI_4x6
-       bool "Mini 4x6 font"
-       depends on !SPARC && FONTS
-
-config FONT_SUN8x16
-       bool "Sparc console 8x16 font"
-       depends on FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC)
-       help
-         This is the high resolution console font for Sun machines. Say Y.
-
-config FONT_SUN12x22
-       bool "Sparc console 12x22 font (not supported by all drivers)"
-       depends on FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC)
-       help
-         This is the high resolution console font for Sun machines with very
-         big letters (like the letters used in the SPARC PROM). If the
-         standard font is unreadable for you, say Y, otherwise say N.
-
-config FONT_10x18
-       bool "console 10x18 font (not supported by all drivers)" if FONTS
-       depends on FRAMEBUFFER_CONSOLE
-       help
-         This is a high resolution console font for machines with very
-         big letters. It fits between the sun 12x22 and the normal 8x16 font.
-         If other fonts are too big or too small for you, say Y, otherwise say N.
-
-config FONT_AUTOSELECT
-       def_bool y
-       depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE || STI_CONSOLE || USB_SISUSBVGA_CON
-       depends on !FONT_8x8
-       depends on !FONT_6x11
-       depends on !FONT_7x14
-       depends on !FONT_PEARL_8x8
-       depends on !FONT_ACORN_8x8
-       depends on !FONT_MINI_4x6
-       depends on !FONT_SUN8x16
-       depends on !FONT_SUN12x22
-       depends on !FONT_10x18
-       select FONT_8x16
-
 endmenu
 
index 48da25c96cd3c2a160077e880f58fed3a52da0f8..43bfa485db9687411411e1fecdef4c29565c7ab6 100644 (file)
@@ -2,32 +2,12 @@
 # 5 Aug 1999, James Simmons, <mailto:jsimmons@users.sf.net>
 # Rewritten to use lists instead of if-statements.
 
-# Font handling
-font-objs := fonts.o
-
-font-objs-$(CONFIG_FONT_SUN8x16)   += font_sun8x16.o
-font-objs-$(CONFIG_FONT_SUN12x22)  += font_sun12x22.o
-font-objs-$(CONFIG_FONT_8x8)       += font_8x8.o
-font-objs-$(CONFIG_FONT_8x16)      += font_8x16.o
-font-objs-$(CONFIG_FONT_6x11)      += font_6x11.o
-font-objs-$(CONFIG_FONT_7x14)      += font_7x14.o
-font-objs-$(CONFIG_FONT_10x18)     += font_10x18.o
-font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
-font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
-font-objs-$(CONFIG_FONT_MINI_4x6)  += font_mini_4x6.o
-
-font-objs += $(font-objs-y)
-
-obj-$(CONFIG_FONTS) += font.o
-
-# Each configuration option enables a list of files.
-
 obj-$(CONFIG_DUMMY_CONSOLE)       += dummycon.o
-obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o font.o
-obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticore.o font.o
+obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o
+obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticore.o
 obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
 obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
-obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o softcursor.o
+obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o softcursor.o
 ifeq ($(CONFIG_FB_TILEBLITTING),y)
 obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += tileblit.o
 endif
@@ -36,8 +16,4 @@ obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \
                                          fbcon_ccw.o
 endif
 
-obj-$(CONFIG_FB_STI)              += sticore.o font.o
-
-ifeq ($(CONFIG_USB_SISUSBVGA_CON),y)
-obj-$(CONFIG_USB_SISUSBVGA)           += font.o
-endif
+obj-$(CONFIG_FB_STI)              += sticore.o
index d55b33757465bf971dad6af8e4698518b717b944..cd8a8027f8aeef2c9de03e9bd1ba9b7c4f040b35 100644 (file)
@@ -404,7 +404,7 @@ static void cursor_timer_handler(unsigned long dev_addr)
        struct fb_info *info = (struct fb_info *) dev_addr;
        struct fbcon_ops *ops = info->fbcon_par;
 
-       schedule_work(&info->queue);
+       queue_work(system_power_efficient_wq, &info->queue);
        mod_timer(&ops->cursor_timer, jiffies + HZ/5);
 }
 
index 0d6f2cda93696fa96322d77a15f122d81555311a..6285b97184510726cc3900b2092584aaae8fc930 100644 (file)
@@ -97,7 +97,7 @@ struct output_device *video_output_register(const char *name,
        new_dev->props = op;
        new_dev->dev.class = &video_output_class;
        new_dev->dev.parent = dev;
-       dev_set_name(&new_dev->dev, name);
+       dev_set_name(&new_dev->dev, "%s", name);
        dev_set_drvdata(&new_dev->dev, devdata);
        ret_code = device_register(&new_dev->dev);
        if (ret_code) {
index bd3ae324a1a261d5c735c552a915f9f5eeef86b1..0098810df69da6bb795b85a573ca28d7bd5a7609 100644 (file)
@@ -148,7 +148,7 @@ static void fill_balloon(struct virtio_balloon *vb, size_t num)
                }
                set_page_pfns(vb->pfns + vb->num_pfns, page);
                vb->num_pages += VIRTIO_BALLOON_PAGES_PER_PAGE;
-               totalram_pages--;
+               adjust_managed_page_count(page, -1);
        }
 
        /* Did we get any? */
@@ -163,8 +163,9 @@ static void release_pages_by_pfn(const u32 pfns[], unsigned int num)
 
        /* Find pfns pointing at start of each page, get pages and free them. */
        for (i = 0; i < num; i += VIRTIO_BALLOON_PAGES_PER_PAGE) {
-               balloon_page_free(balloon_pfn_to_page(pfns[i]));
-               totalram_pages++;
+               struct page *page = balloon_pfn_to_page(pfns[i]);
+               balloon_page_free(page);
+               adjust_managed_page_count(page, 1);
        }
 }
 
index 5217baf5528c0ef85dca9c4282cfb081f158a30c..c70207478e572f2f855bcbb06481b5f9135f4527 100644 (file)
@@ -295,37 +295,6 @@ add_head:
        return 0;
 }
 
-/**
- * virtqueue_add_buf - expose buffer to other end
- * @vq: the struct virtqueue we're talking about.
- * @sg: the description of the buffer(s).
- * @out_num: the number of sg readable by other side
- * @in_num: the number of sg which are writable (after readable ones)
- * @data: the token identifying the buffer.
- * @gfp: how to do memory allocations (if necessary).
- *
- * Caller must ensure we don't call this with other virtqueue operations
- * at the same time (except where noted).
- *
- * Returns zero or a negative error (ie. ENOSPC, ENOMEM).
- */
-int virtqueue_add_buf(struct virtqueue *_vq,
-                     struct scatterlist sg[],
-                     unsigned int out,
-                     unsigned int in,
-                     void *data,
-                     gfp_t gfp)
-{
-       struct scatterlist *sgs[2];
-
-       sgs[0] = sg;
-       sgs[1] = sg + out;
-
-       return virtqueue_add(_vq, sgs, sg_next_arr,
-                            out, in, out ? 1 : 0, in ? 1 : 0, data, gfp);
-}
-EXPORT_SYMBOL_GPL(virtqueue_add_buf);
-
 /**
  * virtqueue_add_sgs - expose buffers to other end
  * @vq: the struct virtqueue we're talking about.
@@ -473,7 +442,7 @@ EXPORT_SYMBOL_GPL(virtqueue_notify);
  * virtqueue_kick - update after add_buf
  * @vq: the struct virtqueue
  *
- * After one or more virtqueue_add_buf calls, invoke this to kick
+ * After one or more virtqueue_add_* calls, invoke this to kick
  * the other side.
  *
  * Caller must ensure we don't call this with other virtqueue
@@ -530,7 +499,7 @@ static inline bool more_used(const struct vring_virtqueue *vq)
  * operations at the same time (except where noted).
  *
  * Returns NULL if there are no used buffers, or the "data" token
- * handed to virtqueue_add_buf().
+ * handed to virtqueue_add_*().
  */
 void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
 {
@@ -685,7 +654,7 @@ EXPORT_SYMBOL_GPL(virtqueue_enable_cb_delayed);
  * virtqueue_detach_unused_buf - detach first unused buffer
  * @vq: the struct virtqueue we're talking about.
  *
- * Returns NULL or the "data" token handed to virtqueue_add_buf().
+ * Returns NULL or the "data" token handed to virtqueue_add_*().
  * This is not valid on an active queue; it is useful only for device
  * shutdown.
  */
index 91cc2cdf02c043481f5b9403d842b7b622fa1d25..cb8a8e5d957336db8d2934e8ed84f9756c3238f9 100644 (file)
@@ -302,7 +302,33 @@ error:
        return -EIO;
 }
 
+/*
+ * This is a special sequence we must do to ensure the P0 output is not stuck
+ * in test mode. This is described in rev 2 of the ds2408's datasheet
+ * (http://datasheets.maximintegrated.com/en/ds/DS2408.pdf) under
+ * "APPLICATION INFORMATION/Power-up timing".
+ */
+static int w1_f29_disable_test_mode(struct w1_slave *sl)
+{
+       int res;
+       u8 magic[10] = {0x96, };
+       u64 rn = le64_to_cpu(*((u64*)&sl->reg_num));
+
+       memcpy(&magic[1], &rn, 8);
+       magic[9] = 0x3C;
+
+       mutex_lock(&sl->master->bus_mutex);
 
+       res = w1_reset_bus(sl->master);
+       if (res)
+               goto out;
+       w1_write_block(sl->master, magic, ARRAY_SIZE(magic));
+
+       res = w1_reset_bus(sl->master);
+out:
+       mutex_unlock(&sl->master->bus_mutex);
+       return res;
+}
 
 static struct bin_attribute w1_f29_sysfs_bin_files[] = {
        {
@@ -363,6 +389,10 @@ static int w1_f29_add_slave(struct w1_slave *sl)
        int err = 0;
        int i;
 
+       err = w1_f29_disable_test_mode(sl);
+       if (err)
+               return err;
+
        for (i = 0; i < ARRAY_SIZE(w1_f29_sysfs_bin_files) && !err; ++i)
                err = sysfs_create_bin_file(
                        &sl->dev.kobj,
index 930fb68179012355952c20d759111a6755b3acbe..2a2ef97697b266af2b36428c35584b85955c04ef 100644 (file)
@@ -36,6 +36,8 @@
  * IN THE SOFTWARE.
  */
 
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -89,14 +91,6 @@ EXPORT_SYMBOL_GPL(balloon_stats);
 /* We increase/decrease in batches which fit in a page */
 static xen_pfn_t frame_list[PAGE_SIZE / sizeof(unsigned long)];
 
-#ifdef CONFIG_HIGHMEM
-#define inc_totalhigh_pages() (totalhigh_pages++)
-#define dec_totalhigh_pages() (totalhigh_pages--)
-#else
-#define inc_totalhigh_pages() do {} while (0)
-#define dec_totalhigh_pages() do {} while (0)
-#endif
-
 /* List of ballooned pages, threaded through the mem_map array. */
 static LIST_HEAD(ballooned_pages);
 
@@ -132,9 +126,7 @@ static void __balloon_append(struct page *page)
 static void balloon_append(struct page *page)
 {
        __balloon_append(page);
-       if (PageHighMem(page))
-               dec_totalhigh_pages();
-       totalram_pages--;
+       adjust_managed_page_count(page, -1);
 }
 
 /* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
@@ -151,13 +143,12 @@ static struct page *balloon_retrieve(bool prefer_highmem)
                page = list_entry(ballooned_pages.next, struct page, lru);
        list_del(&page->lru);
 
-       if (PageHighMem(page)) {
+       if (PageHighMem(page))
                balloon_stats.balloon_high--;
-               inc_totalhigh_pages();
-       } else
+       else
                balloon_stats.balloon_low--;
 
-       totalram_pages++;
+       adjust_managed_page_count(page, 1);
 
        return page;
 }
@@ -242,7 +233,7 @@ static enum bp_state reserve_additional_memory(long credit)
        rc = add_memory(nid, hotplug_start_paddr, balloon_hotplug << PAGE_SHIFT);
 
        if (rc) {
-               pr_info("xen_balloon: %s: add_memory() failed: %i\n", __func__, rc);
+               pr_info("%s: add_memory() failed: %i\n", __func__, rc);
                return BP_EAGAIN;
        }
 
@@ -372,9 +363,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages)
 #endif
 
                /* Relinquish the page back to the allocator. */
-               ClearPageReserved(page);
-               init_page_count(page);
-               __free_page(page);
+               __free_reserved_page(page);
        }
 
        balloon_stats.current_pages += rc;
@@ -591,7 +580,7 @@ static int __init balloon_init(void)
        if (!xen_domain())
                return -ENODEV;
 
-       pr_info("xen/balloon: Initialising balloon driver.\n");
+       pr_info("Initialising balloon driver\n");
 
        balloon_stats.current_pages = xen_pv_domain()
                ? min(xen_start_info->nr_pages - xen_released_pages, max_pfn)
index 084041d42c9adabfc40251546d361ad76d8987e5..cc6513a176b0b07ea25990a8470f3d8ee907f507 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/notifier.h>
 
 #include <xen/xen.h>
@@ -31,7 +33,7 @@ static int vcpu_online(unsigned int cpu)
        err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state);
        if (err != 1) {
                if (!xen_initial_domain())
-                       printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
+                       pr_err("Unable to read cpu state\n");
                return err;
        }
 
@@ -40,7 +42,7 @@ static int vcpu_online(unsigned int cpu)
        else if (strcmp(state, "offline") == 0)
                return 0;
 
-       printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n", state, cpu);
+       pr_err("unknown state(%s) on CPU%d\n", state, cpu);
        return -EINVAL;
 }
 static void vcpu_hotplug(unsigned int cpu)
index 6a6bbe4ede92c67afe4c88efd105839f14b3a240..a58ac435a9a4a03f39274f8b5a41ea659d44eee7 100644 (file)
@@ -21,6 +21,8 @@
  * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
  */
 
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/linkage.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -600,8 +602,7 @@ static unsigned int __startup_pirq(unsigned int irq)
        rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq);
        if (rc != 0) {
                if (!probing_irq(irq))
-                       printk(KERN_INFO "Failed to obtain physical IRQ %d\n",
-                              irq);
+                       pr_info("Failed to obtain physical IRQ %d\n", irq);
                return 0;
        }
        evtchn = bind_pirq.port;
@@ -693,8 +694,8 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
 
        irq = xen_irq_from_gsi(gsi);
        if (irq != -1) {
-               printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n",
-                      irq, gsi);
+               pr_info("%s: returning irq %d for gsi %u\n",
+                       __func__, irq, gsi);
                goto out;
        }
 
@@ -812,10 +813,10 @@ int xen_destroy_irq(int irq)
                 * (free_domain_pirqs).
                 */
                if ((rc == -ESRCH && info->u.pirq.domid != DOMID_SELF))
-                       printk(KERN_INFO "domain %d does not have %d anymore\n",
+                       pr_info("domain %d does not have %d anymore\n",
                                info->u.pirq.domid, info->u.pirq.pirq);
                else if (rc) {
-                       printk(KERN_WARNING "unmap irq failed %d\n", rc);
+                       pr_warn("unmap irq failed %d\n", rc);
                        goto out;
                }
        }
@@ -1621,8 +1622,8 @@ static void restore_pirqs(void)
 
                rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
                if (rc) {
-                       printk(KERN_WARNING "xen map irq failed gsi=%d irq=%d pirq=%d rc=%d\n",
-                                       gsi, irq, pirq, rc);
+                       pr_warn("xen map irq failed gsi=%d irq=%d pirq=%d rc=%d\n",
+                               gsi, irq, pirq, rc);
                        xen_free_irq(irq);
                        continue;
                }
@@ -1844,13 +1845,11 @@ void xen_callback_vector(void)
                callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR);
                rc = xen_set_callback_via(callback_via);
                if (rc) {
-                       printk(KERN_ERR "Request for Xen HVM callback vector"
-                                       " failed.\n");
+                       pr_err("Request for Xen HVM callback vector failed\n");
                        xen_have_vector_callback = 0;
                        return;
                }
-               printk(KERN_INFO "Xen HVM callback vector for event delivery is "
-                               "enabled\n");
+               pr_info("Xen HVM callback vector for event delivery is enabled\n");
                /* in the restore case the vector has already been allocated */
                if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
                        alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
index 45c8efaa6b3ea1035a1c560c403ad924f9d9e8ad..8feecf01d55c95c9241080cf36823f197b3b2d5c 100644 (file)
@@ -31,6 +31,8 @@
  * IN THE SOFTWARE.
  */
 
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -547,11 +549,11 @@ static int __init evtchn_init(void)
        /* Create '/dev/xen/evtchn'. */
        err = misc_register(&evtchn_miscdev);
        if (err != 0) {
-               printk(KERN_ERR "Could not register /dev/xen/evtchn\n");
+               pr_err("Could not register /dev/xen/evtchn\n");
                return err;
        }
 
-       printk(KERN_INFO "Event-channel device installed.\n");
+       pr_info("Event-channel device installed\n");
 
        return 0;
 }
index 4097987b330e6235d3ddf5df79119f15c7bf9b10..787d17945418b19c53d408d710e2558a6bb85ad8 100644 (file)
@@ -48,6 +48,8 @@
  * grant operation.
  */
 
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/atomic.h>
 #include <linux/module.h>
 #include <linux/miscdevice.h>
@@ -507,7 +509,7 @@ static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma)
        int rv, i;
 
        if (!(vma->vm_flags & VM_SHARED)) {
-               printk(KERN_ERR "%s: Mapping must be shared.\n", __func__);
+               pr_err("%s: Mapping must be shared\n", __func__);
                return -EINVAL;
        }
 
@@ -584,7 +586,7 @@ static int __init gntalloc_init(void)
 
        err = misc_register(&gntalloc_miscdev);
        if (err != 0) {
-               printk(KERN_ERR "Could not register misc gntalloc device\n");
+               pr_err("Could not register misc gntalloc device\n");
                return err;
        }
 
index 3c8803feba26cdcba8bd890225ac7995ef72810e..eab5427c75f5df829eb964b1c592758fb67aa64e 100644 (file)
@@ -19,6 +19,8 @@
 
 #undef DEBUG
 
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -760,7 +762,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
        if (use_ptemod && map->vma)
                goto unlock_out;
        if (use_ptemod && priv->mm != vma->vm_mm) {
-               printk(KERN_WARNING "Huh? Other mm?\n");
+               pr_warn("Huh? Other mm?\n");
                goto unlock_out;
        }
 
@@ -795,7 +797,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
                                          vma->vm_end - vma->vm_start,
                                          find_grant_ptes, map);
                if (err) {
-                       printk(KERN_WARNING "find_grant_ptes() failure.\n");
+                       pr_warn("find_grant_ptes() failure.\n");
                        goto out_put_map;
                }
        }
@@ -855,7 +857,7 @@ static int __init gntdev_init(void)
 
        err = misc_register(&gntdev_miscdev);
        if (err != 0) {
-               printk(KERN_ERR "Could not register gntdev device\n");
+               pr_err("Could not register gntdev device\n");
                return err;
        }
        return 0;
index 04c1b2d9b77514ca89ef1cf74d6263f5ebb93a29..04cdeb8e371944a12237da0191648e31f5a44c2f 100644 (file)
@@ -31,6 +31,8 @@
  * IN THE SOFTWARE.
  */
 
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -508,8 +510,7 @@ static void gnttab_handle_deferred(unsigned long unused)
                        entry = NULL;
                } else {
                        if (!--entry->warn_delay)
-                               pr_info("g.e. %#x still pending\n",
-                                       entry->ref);
+                               pr_info("g.e. %#x still pending\n", entry->ref);
                        if (!first)
                                first = entry;
                }
@@ -838,7 +839,7 @@ gnttab_retry_eagain_gop(unsigned int cmd, void *gop, int16_t *status,
        } while ((*status == GNTST_eagain) && (delay < MAX_DELAY));
 
        if (delay >= MAX_DELAY) {
-               printk(KERN_ERR "%s: %s eagain grant\n", func, current->comm);
+               pr_err("%s: %s eagain grant\n", func, current->comm);
                *status = GNTST_bad_page;
        }
 }
@@ -1048,8 +1049,8 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
                        xatp.gpfn = (xen_hvm_resume_frames >> PAGE_SHIFT) + i;
                        rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp);
                        if (rc != 0) {
-                               printk(KERN_WARNING
-                                               "grant table add_to_physmap failed, err=%d\n", rc);
+                               pr_warn("grant table add_to_physmap failed, err=%d\n",
+                                       rc);
                                break;
                        }
                } while (i-- > start_idx);
@@ -1131,8 +1132,7 @@ static void gnttab_request_version(void)
                grefs_per_grant_frame = PAGE_SIZE / sizeof(struct grant_entry_v1);
                gnttab_interface = &gnttab_v1_ops;
        }
-       printk(KERN_INFO "Grant tables using version %d layout.\n",
-               grant_table_version);
+       pr_info("Grant tables using version %d layout\n", grant_table_version);
 }
 
 static int gnttab_setup(void)
@@ -1150,8 +1150,7 @@ static int gnttab_setup(void)
                gnttab_shared.addr = xen_remap(xen_hvm_resume_frames,
                                                PAGE_SIZE * max_nr_gframes);
                if (gnttab_shared.addr == NULL) {
-                       printk(KERN_WARNING
-                                       "Failed to ioremap gnttab share frames!");
+                       pr_warn("Failed to ioremap gnttab share frames!\n");
                        return -ENOMEM;
                }
        }
index 412b96cc5305746c20d554b1a6d2c7e55ab09686..9385b4524547860e54a55a14d3727561be8d124e 100644 (file)
@@ -1,6 +1,9 @@
 /*
  * Handle extern requests for shutdown, reboot and sysrq
  */
+
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/slab.h>
@@ -43,6 +46,7 @@ struct suspend_info {
        void (*post)(int cancelled);
 };
 
+#ifdef CONFIG_HIBERNATE_CALLBACKS
 static void xen_hvm_post_suspend(int cancelled)
 {
        xen_arch_hvm_post_suspend(cancelled);
@@ -63,7 +67,6 @@ static void xen_post_suspend(int cancelled)
        xen_mm_unpin_all();
 }
 
-#ifdef CONFIG_HIBERNATE_CALLBACKS
 static int xen_suspend(void *data)
 {
        struct suspend_info *si = data;
@@ -73,8 +76,7 @@ static int xen_suspend(void *data)
 
        err = syscore_suspend();
        if (err) {
-               printk(KERN_ERR "xen_suspend: system core suspend failed: %d\n",
-                       err);
+               pr_err("%s: system core suspend failed: %d\n", __func__, err);
                return err;
        }
 
@@ -115,14 +117,14 @@ static void do_suspend(void)
           during suspend. */
        err = freeze_processes();
        if (err) {
-               printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
+               pr_err("%s: freeze failed %d\n", __func__, err);
                goto out;
        }
 #endif
 
        err = dpm_suspend_start(PMSG_FREEZE);
        if (err) {
-               printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
+               pr_err("%s: dpm_suspend_start %d\n", __func__, err);
                goto out_thaw;
        }
 
@@ -131,7 +133,7 @@ static void do_suspend(void)
 
        err = dpm_suspend_end(PMSG_FREEZE);
        if (err) {
-               printk(KERN_ERR "dpm_suspend_end failed: %d\n", err);
+               pr_err("dpm_suspend_end failed: %d\n", err);
                si.cancelled = 0;
                goto out_resume;
        }
@@ -153,7 +155,7 @@ static void do_suspend(void)
        dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
 
        if (err) {
-               printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
+               pr_err("failed to start xen_suspend: %d\n", err);
                si.cancelled = 1;
        }
 
@@ -245,7 +247,7 @@ static void shutdown_handler(struct xenbus_watch *watch,
        if (handler->cb) {
                handler->cb();
        } else {
-               printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
+               pr_info("Ignoring shutdown request: %s\n", str);
                shutting_down = SHUTDOWN_INVALID;
        }
 
@@ -265,8 +267,7 @@ static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
        if (err)
                return;
        if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
-               printk(KERN_ERR "Unable to read sysrq code in "
-                      "control/sysrq\n");
+               pr_err("Unable to read sysrq code in control/sysrq\n");
                xenbus_transaction_end(xbt, 1);
                return;
        }
@@ -299,14 +300,14 @@ static int setup_shutdown_watcher(void)
 
        err = register_xenbus_watch(&shutdown_watch);
        if (err) {
-               printk(KERN_ERR "Failed to set shutdown watcher\n");
+               pr_err("Failed to set shutdown watcher\n");
                return err;
        }
 
 #ifdef CONFIG_MAGIC_SYSRQ
        err = register_xenbus_watch(&sysrq_watch);
        if (err) {
-               printk(KERN_ERR "Failed to set sysrq watcher\n");
+               pr_err("Failed to set sysrq watcher\n");
                return err;
        }
 #endif
index 8feee08bcb438b9a1157405af4bc026a69a4bce6..6ab6a79c38a5a9efc930e5c958cd60bb8e5c20dc 100644 (file)
@@ -32,6 +32,8 @@
  * IN THE SOFTWARE.
  */
 
+#define pr_fmt(fmt) "xen_mcelog: " fmt
+
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -51,8 +53,6 @@
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
 
-#define XEN_MCELOG "xen_mcelog: "
-
 static struct mc_info g_mi;
 static struct mcinfo_logical_cpu *g_physinfo;
 static uint32_t ncpus;
@@ -227,7 +227,7 @@ static int convert_log(struct mc_info *mi)
        mic = NULL;
        x86_mcinfo_lookup(&mic, mi, MC_TYPE_GLOBAL);
        if (unlikely(!mic)) {
-               pr_warning(XEN_MCELOG "Failed to find global error info\n");
+               pr_warn("Failed to find global error info\n");
                return -ENODEV;
        }
 
@@ -241,8 +241,7 @@ static int convert_log(struct mc_info *mi)
                if (g_physinfo[i].mc_apicid == m.apicid)
                        break;
        if (unlikely(i == ncpus)) {
-               pr_warning(XEN_MCELOG "Failed to match cpu with apicid %d\n",
-                          m.apicid);
+               pr_warn("Failed to match cpu with apicid %d\n", m.apicid);
                return -ENODEV;
        }
 
@@ -254,7 +253,7 @@ static int convert_log(struct mc_info *mi)
        mic = NULL;
        x86_mcinfo_lookup(&mic, mi, MC_TYPE_BANK);
        if (unlikely(!mic)) {
-               pr_warning(XEN_MCELOG "Fail to find bank error info\n");
+               pr_warn("Fail to find bank error info\n");
                return -ENODEV;
        }
 
@@ -295,9 +294,8 @@ static int mc_queue_handle(uint32_t flags)
                mc_op.u.mc_fetch.flags = flags;
                ret = HYPERVISOR_mca(&mc_op);
                if (ret) {
-                       pr_err(XEN_MCELOG "Failed to fetch %s error log\n",
-                              (flags == XEN_MC_URGENT) ?
-                              "urgnet" : "nonurgent");
+                       pr_err("Failed to fetch %surgent error log\n",
+                              flags == XEN_MC_URGENT ? "" : "non");
                        break;
                }
 
@@ -307,15 +305,12 @@ static int mc_queue_handle(uint32_t flags)
                else {
                        ret = convert_log(&g_mi);
                        if (ret)
-                               pr_warning(XEN_MCELOG
-                                          "Failed to convert this error log, "
-                                          "continue acking it anyway\n");
+                               pr_warn("Failed to convert this error log, continue acking it anyway\n");
 
                        mc_op.u.mc_fetch.flags = flags | XEN_MC_ACK;
                        ret = HYPERVISOR_mca(&mc_op);
                        if (ret) {
-                               pr_err(XEN_MCELOG
-                                      "Failed to ack previous error log\n");
+                               pr_err("Failed to ack previous error log\n");
                                break;
                        }
                }
@@ -334,15 +329,12 @@ static void xen_mce_work_fn(struct work_struct *work)
        /* urgent mc_info */
        err = mc_queue_handle(XEN_MC_URGENT);
        if (err)
-               pr_err(XEN_MCELOG
-                      "Failed to handle urgent mc_info queue, "
-                      "continue handling nonurgent mc_info queue anyway.\n");
+               pr_err("Failed to handle urgent mc_info queue, continue handling nonurgent mc_info queue anyway\n");
 
        /* nonurgent mc_info */
        err = mc_queue_handle(XEN_MC_NONURGENT);
        if (err)
-               pr_err(XEN_MCELOG
-                      "Failed to handle nonurgent mc_info queue.\n");
+               pr_err("Failed to handle nonurgent mc_info queue\n");
 
        /* wake processes polling /dev/mcelog */
        wake_up_interruptible(&xen_mce_chrdev_wait);
@@ -370,7 +362,7 @@ static int bind_virq_for_mce(void)
        set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo);
        ret = HYPERVISOR_mca(&mc_op);
        if (ret) {
-               pr_err(XEN_MCELOG "Failed to get CPU numbers\n");
+               pr_err("Failed to get CPU numbers\n");
                return ret;
        }
 
@@ -383,7 +375,7 @@ static int bind_virq_for_mce(void)
        set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo);
        ret = HYPERVISOR_mca(&mc_op);
        if (ret) {
-               pr_err(XEN_MCELOG "Failed to get CPU info\n");
+               pr_err("Failed to get CPU info\n");
                kfree(g_physinfo);
                return ret;
        }
@@ -391,7 +383,7 @@ static int bind_virq_for_mce(void)
        ret  = bind_virq_to_irqhandler(VIRQ_MCA, 0,
                                       xen_mce_interrupt, 0, "mce", NULL);
        if (ret < 0) {
-               pr_err(XEN_MCELOG "Failed to bind virq\n");
+               pr_err("Failed to bind virq\n");
                kfree(g_physinfo);
                return ret;
        }
index 6536d5ab1697ba6d770a6d8b969d2340df832ec7..79e1dff7ed4f7f4c258d50e009f48e0bf0a5673c 100644 (file)
@@ -31,6 +31,8 @@
  * IN THE SOFTWARE.
  */
 
+#define pr_fmt(fmt) "xen_cpu: " fmt
+
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/cpu.h>
@@ -44,7 +46,6 @@
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 
-#define XEN_PCPU "xen_cpu: "
 
 /*
  * @cpu_id: Xen physical cpu logic number
@@ -242,8 +243,7 @@ static struct pcpu *create_and_register_pcpu(struct xenpf_pcpuinfo *info)
 
        err = register_pcpu(pcpu);
        if (err) {
-               pr_warning(XEN_PCPU "Failed to register pcpu%u\n",
-                          info->xen_cpuid);
+               pr_warn("Failed to register pcpu%u\n", info->xen_cpuid);
                return ERR_PTR(-ENOENT);
        }
 
@@ -378,19 +378,19 @@ static int __init xen_pcpu_init(void)
                                      xen_pcpu_interrupt, 0,
                                      "xen-pcpu", NULL);
        if (irq < 0) {
-               pr_warning(XEN_PCPU "Failed to bind pcpu virq\n");
+               pr_warn("Failed to bind pcpu virq\n");
                return irq;
        }
 
        ret = subsys_system_register(&xen_pcpu_subsys, NULL);
        if (ret) {
-               pr_warning(XEN_PCPU "Failed to register pcpu subsys\n");
+               pr_warn("Failed to register pcpu subsys\n");
                goto err1;
        }
 
        ret = xen_sync_pcpus();
        if (ret) {
-               pr_warning(XEN_PCPU "Failed to sync pcpu info\n");
+               pr_warn("Failed to sync pcpu info\n");
                goto err2;
        }
 
index 2cfc24d76fc54d97d9e8106c5fdf108379b7ba9f..f8e5dd701ecb63e1c9298e947bb57072cd76efd0 100644 (file)
@@ -6,6 +6,8 @@
  * Copyright (c) 2002-2004, K A Fraser, B Dragovic
  */
 
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -565,7 +567,7 @@ static int __init privcmd_init(void)
 
        err = misc_register(&privcmd_dev);
        if (err != 0) {
-               printk(KERN_ERR "Could not register Xen privcmd device\n");
+               pr_err("Could not register Xen privcmd device\n");
                return err;
        }
        return 0;
index 1d94316f0ea46616ceda930896af210d7ad68284..aadffcf7db9be0d49d3cd0b937503a3811d46be0 100644 (file)
@@ -33,6 +33,8 @@
  *
  */
 
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/bootmem.h>
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
@@ -202,8 +204,8 @@ retry:
                        order--;
                }
                if (order != get_order(bytes)) {
-                       pr_warn("Warning: only able to allocate %ld MB "
-                               "for software IO TLB\n", (PAGE_SIZE << order) >> 20);
+                       pr_warn("Warning: only able to allocate %ld MB for software IO TLB\n",
+                               (PAGE_SIZE << order) >> 20);
                        xen_io_tlb_nslabs = SLABS_PER_PAGE << order;
                        bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
                }
@@ -242,11 +244,11 @@ error:
        if (repeat--) {
                xen_io_tlb_nslabs = max(1024UL, /* Min is 2MB */
                                        (xen_io_tlb_nslabs >> 1));
-               printk(KERN_INFO "Xen-SWIOTLB: Lowering to %luMB\n",
-                     (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20);
+               pr_info("Lowering to %luMB\n",
+                       (xen_io_tlb_nslabs << IO_TLB_SHIFT) >> 20);
                goto retry;
        }
-       pr_err("%s (rc:%d)", xen_swiotlb_error(m_ret), rc);
+       pr_err("%s (rc:%d)\n", xen_swiotlb_error(m_ret), rc);
        if (early)
                panic("%s (rc:%d)", xen_swiotlb_error(m_ret), rc);
        else
index 0f0493c633717ae4814162f645406db15e16d54e..83b5c53bec6b6b0c06c7d9ec923df9676f17268b 100644 (file)
@@ -5,6 +5,8 @@
  * Author: Dan Magenheimer
  */
 
+#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -388,8 +390,8 @@ static int xen_tmem_init(void)
                                return PTR_ERR(old_ops);
                        s = " (WARNING: frontswap_ops overridden)";
                }
-               printk(KERN_INFO "frontswap enabled, RAM provided by "
-                                "Xen Transcendent Memory%s\n", s);
+               pr_info("frontswap enabled, RAM provided by Xen Transcendent Memory%s\n",
+                       s);
        }
 #endif
 #ifdef CONFIG_CLEANCACHE
@@ -400,8 +402,8 @@ static int xen_tmem_init(void)
                        cleancache_register_ops(&tmem_cleancache_ops);
                if (old_ops)
                        s = " (WARNING: cleancache_ops overridden)";
-               printk(KERN_INFO "cleancache enabled, RAM provided by "
-                                "Xen Transcendent Memory%s\n", s);
+               pr_info("cleancache enabled, RAM provided by Xen Transcendent Memory%s\n",
+                       s);
        }
 #endif
 #ifdef CONFIG_XEN_SELFBALLOONING
index 18c742bec91bfef6d98ae522f94e366e60c810a1..0caf4863be8cc6e007a69d588c509588c9496ae6 100644 (file)
@@ -15,6 +15,8 @@
  * details.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
index faef5b396051196a26c3c22d40d6e6d6d78adb57..9083f1e474f801c07c1531551fa971b5e0e21b38 100644 (file)
@@ -15,6 +15,8 @@
  * details.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
index c763479ed85ebcfc47eaa76014d3bcc765a2f68e..59708fdd068bdfed83976dab53a823115efeda29 100644 (file)
@@ -14,6 +14,8 @@
  * more details.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <acpi/acpi_bus.h>
index 8abd7d57903742c54538819fa70fdfa3d0c36f95..13bc6c31c060bfc9821eb23eb467873b720c6f13 100644 (file)
@@ -17,6 +17,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/cpumask.h>
 #include <linux/cpufreq.h>
 #include <linux/freezer.h>
@@ -34,8 +36,6 @@
 #include <xen/interface/platform.h>
 #include <asm/xen/hypercall.h>
 
-#define DRV_NAME "xen-acpi-processor: "
-
 static int no_hypercall;
 MODULE_PARM_DESC(off, "Inhibit the hypercall.");
 module_param_named(off, no_hypercall, int, 0400);
@@ -104,7 +104,7 @@ static int push_cxx_to_hypervisor(struct acpi_processor *_pr)
                set_xen_guest_handle(dst_cx->dp, NULL);
        }
        if (!ok) {
-               pr_debug(DRV_NAME "No _Cx for ACPI CPU %u\n", _pr->acpi_id);
+               pr_debug("No _Cx for ACPI CPU %u\n", _pr->acpi_id);
                kfree(dst_cx_states);
                return -EINVAL;
        }
@@ -133,7 +133,7 @@ static int push_cxx_to_hypervisor(struct acpi_processor *_pr)
                /* EINVAL means the ACPI ID is incorrect - meaning the ACPI
                 * table is referencing a non-existing CPU - which can happen
                 * with broken ACPI tables. */
-               pr_err(DRV_NAME "(CX): Hypervisor error (%d) for ACPI CPU%u\n",
+               pr_err("(CX): Hypervisor error (%d) for ACPI CPU%u\n",
                       ret, _pr->acpi_id);
 
        kfree(dst_cx_states);
@@ -239,7 +239,7 @@ static int push_pxx_to_hypervisor(struct acpi_processor *_pr)
                dst_perf->flags |= XEN_PX_PSD;
 
        if (dst_perf->flags != (XEN_PX_PSD | XEN_PX_PSS | XEN_PX_PCT | XEN_PX_PPC)) {
-               pr_warn(DRV_NAME "ACPI CPU%u missing some P-state data (%x), skipping.\n",
+               pr_warn("ACPI CPU%u missing some P-state data (%x), skipping\n",
                        _pr->acpi_id, dst_perf->flags);
                ret = -ENODEV;
                goto err_free;
@@ -265,8 +265,8 @@ static int push_pxx_to_hypervisor(struct acpi_processor *_pr)
                /* EINVAL means the ACPI ID is incorrect - meaning the ACPI
                 * table is referencing a non-existing CPU - which can happen
                 * with broken ACPI tables. */
-               pr_warn(DRV_NAME "(_PXX): Hypervisor error (%d) for ACPI CPU%u\n",
-                      ret, _pr->acpi_id);
+               pr_warn("(_PXX): Hypervisor error (%d) for ACPI CPU%u\n",
+                       ret, _pr->acpi_id);
 err_free:
        if (!IS_ERR_OR_NULL(dst_states))
                kfree(dst_states);
@@ -318,7 +318,7 @@ static unsigned int __init get_max_acpi_id(void)
                max_acpi_id = max(info->acpi_id, max_acpi_id);
        }
        max_acpi_id *= 2; /* Slack for CPU hotplug support. */
-       pr_debug(DRV_NAME "Max ACPI ID: %u\n", max_acpi_id);
+       pr_debug("Max ACPI ID: %u\n", max_acpi_id);
        return max_acpi_id;
 }
 /*
@@ -365,15 +365,14 @@ read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv)
        /* There are more ACPI Processor objects than in x2APIC or MADT.
         * This can happen with incorrect ACPI SSDT declerations. */
        if (acpi_id > nr_acpi_bits) {
-               pr_debug(DRV_NAME "We only have %u, trying to set %u\n",
+               pr_debug("We only have %u, trying to set %u\n",
                         nr_acpi_bits, acpi_id);
                return AE_OK;
        }
        /* OK, There is a ACPI Processor object */
        __set_bit(acpi_id, acpi_id_present);
 
-       pr_debug(DRV_NAME "ACPI CPU%u w/ PBLK:0x%lx\n", acpi_id,
-                (unsigned long)pblk);
+       pr_debug("ACPI CPU%u w/ PBLK:0x%lx\n", acpi_id, (unsigned long)pblk);
 
        status = acpi_evaluate_object(handle, "_CST", NULL, &buffer);
        if (ACPI_FAILURE(status)) {
@@ -476,7 +475,7 @@ static int xen_upload_processor_pm_data(void)
        unsigned int i;
        int rc = 0;
 
-       pr_info(DRV_NAME "Uploading Xen processor PM info\n");
+       pr_info("Uploading Xen processor PM info\n");
 
        for_each_possible_cpu(i) {
                struct acpi_processor *_pr;
@@ -523,7 +522,7 @@ static int __init xen_acpi_processor_init(void)
 
        acpi_perf_data = alloc_percpu(struct acpi_processor_performance);
        if (!acpi_perf_data) {
-               pr_debug(DRV_NAME "Memory allocation error for acpi_perf_data.\n");
+               pr_debug("Memory allocation error for acpi_perf_data\n");
                kfree(acpi_ids_done);
                return -ENOMEM;
        }
index 8f37e23f6d139ec1e46577eeaa6a599bba3b26eb..e555845d61faff522d51e00799606a9657234a9c 100644 (file)
@@ -30,6 +30,8 @@
  * IN THE SOFTWARE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/capability.h>
@@ -81,7 +83,7 @@ static int balloon_init_watcher(struct notifier_block *notifier,
 
        err = register_xenbus_watch(&target_watch);
        if (err)
-               printk(KERN_ERR "Failed to set balloon watcher\n");
+               pr_err("Failed to set balloon watcher\n");
 
        return NOTIFY_DONE;
 }
@@ -95,7 +97,7 @@ static int __init balloon_init(void)
        if (!xen_domain())
                return -ENODEV;
 
-       pr_info("xen-balloon: Initialising balloon driver.\n");
+       pr_info("Initialising balloon driver\n");
 
        register_balloon(&balloon_dev);
 
index 3daf862d739da94719c6378f924ca4c2cf3719c1..c5ee82587e8cc3b5feb5e594763da576765fd268 100644 (file)
@@ -4,6 +4,8 @@
  * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include "pciback.h"
@@ -75,10 +77,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
                               pci_name(dev));
                err = pci_set_mwi(dev);
                if (err) {
-                       printk(KERN_WARNING
-                              DRV_NAME ": %s: cannot enable "
-                              "memory-write-invalidate (%d)\n",
-                              pci_name(dev), err);
+                       pr_warn("%s: cannot enable memory-write-invalidate (%d)\n",
+                               pci_name(dev), err);
                        value &= ~PCI_COMMAND_INVALIDATE;
                }
        }
@@ -91,7 +91,7 @@ static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
        struct pci_bar_info *bar = data;
 
        if (unlikely(!bar)) {
-               printk(KERN_WARNING DRV_NAME ": driver data not found for %s\n",
+               pr_warn(DRV_NAME ": driver data not found for %s\n",
                       pci_name(dev));
                return XEN_PCI_ERR_op_failed;
        }
@@ -125,7 +125,7 @@ static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
        struct pci_bar_info *bar = data;
 
        if (unlikely(!bar)) {
-               printk(KERN_WARNING DRV_NAME ": driver data not found for %s\n",
+               pr_warn(DRV_NAME ": driver data not found for %s\n",
                       pci_name(dev));
                return XEN_PCI_ERR_op_failed;
        }
@@ -153,7 +153,7 @@ static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
        struct pci_bar_info *bar = data;
 
        if (unlikely(!bar)) {
-               printk(KERN_WARNING DRV_NAME ": driver data not found for %s\n",
+               pr_warn(DRV_NAME ": driver data not found for %s\n",
                       pci_name(dev));
                return XEN_PCI_ERR_op_failed;
        }
@@ -375,7 +375,7 @@ int xen_pcibk_config_header_add_fields(struct pci_dev *dev)
 
        default:
                err = -EINVAL;
-               printk(KERN_ERR DRV_NAME ": %s: Unsupported header type %d!\n",
+               pr_err("%s: Unsupported header type %d!\n",
                       pci_name(dev), dev->hdr_type);
                break;
        }
index 4e8ba38aa0c9cb0499ecdf27172baf44d55a65b5..62fcd485f0a76e37fe9d07bd62e6a3d367704cfa 100644 (file)
@@ -4,6 +4,9 @@
  * Ryan Wilson <hap9@epoch.ncsc.mil>
  * Chris Bookholt <hap10@epoch.ncsc.mil>
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/rwsem.h>
@@ -425,8 +428,6 @@ static int __init pcistub_init_devices_late(void)
        unsigned long flags;
        int err = 0;
 
-       pr_debug(DRV_NAME ": pcistub_init_devices_late\n");
-
        spin_lock_irqsave(&pcistub_devices_lock, flags);
 
        while (!list_empty(&seized_devices)) {
@@ -544,15 +545,11 @@ static void pcistub_remove(struct pci_dev *dev)
                        found_psdev->pdev);
 
                if (found_psdev->pdev) {
-                       printk(KERN_WARNING DRV_NAME ": ****** removing device "
-                              "%s while still in-use! ******\n",
+                       pr_warn("****** removing device %s while still in-use! ******\n",
                               pci_name(found_psdev->dev));
-                       printk(KERN_WARNING DRV_NAME ": ****** driver domain may"
-                              " still access this device's i/o resources!\n");
-                       printk(KERN_WARNING DRV_NAME ": ****** shutdown driver "
-                              "domain before binding device\n");
-                       printk(KERN_WARNING DRV_NAME ": ****** to other drivers "
-                              "or domains\n");
+                       pr_warn("****** driver domain may still access this device's i/o resources!\n");
+                       pr_warn("****** shutdown driver domain before binding device\n");
+                       pr_warn("****** to other drivers or domains\n");
 
                        xen_pcibk_release_pci_dev(found_psdev->pdev,
                                                found_psdev->dev);
@@ -1018,7 +1015,7 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func)
        pci_dev_id->bus = bus;
        pci_dev_id->devfn = devfn;
 
-       pr_debug(DRV_NAME ": wants to seize %04x:%02x:%02x.%d\n",
+       pr_debug("wants to seize %04x:%02x:%02x.%d\n",
                 domain, bus, slot, func);
 
        spin_lock_irqsave(&device_ids_lock, flags);
@@ -1048,8 +1045,8 @@ static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
 
                        err = 0;
 
-                       pr_debug(DRV_NAME ": removed %04x:%02x:%02x.%d from "
-                                "seize list\n", domain, bus, slot, func);
+                       pr_debug("removed %04x:%02x:%02x.%d from seize list\n",
+                                domain, bus, slot, func);
                }
        }
        spin_unlock_irqrestore(&device_ids_lock, flags);
@@ -1196,19 +1193,23 @@ static ssize_t pcistub_irq_handler_switch(struct device_driver *drv,
        struct pcistub_device *psdev;
        struct xen_pcibk_dev_data *dev_data;
        int domain, bus, slot, func;
-       int err = -ENOENT;
+       int err;
 
        err = str_to_slot(buf, &domain, &bus, &slot, &func);
        if (err)
                return err;
 
        psdev = pcistub_device_find(domain, bus, slot, func);
-       if (!psdev)
+       if (!psdev) {
+               err = -ENOENT;
                goto out;
+       }
 
        dev_data = pci_get_drvdata(psdev->dev);
-       if (!dev_data)
+       if (!dev_data) {
+               err = -ENOENT;
                goto out;
+       }
 
        dev_dbg(&psdev->dev->dev, "%s fake irq handler: %d->%d\n",
                dev_data->irq_name, dev_data->isr_on,
@@ -1470,7 +1471,7 @@ out:
        return err;
 
 parse_error:
-       printk(KERN_ERR DRV_NAME ": Error parsing pci_devs_to_hide at \"%s\"\n",
+       pr_err("Error parsing pci_devs_to_hide at \"%s\"\n",
               pci_devs_to_hide + pos);
        return -EINVAL;
 }
index b98cf0c35725a1714afbc498ee1ab49864eb1ff3..64eb0cd8b8af428ef87eb2db9e0314e5ed9336a9 100644 (file)
@@ -3,6 +3,9 @@
  *
  *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/wait.h>
 #include <linux/bitops.h>
@@ -144,7 +147,7 @@ int xen_pcibk_enable_msi(struct xen_pcibk_device *pdev,
        status = pci_enable_msi(dev);
 
        if (status) {
-               pr_warn_ratelimited(DRV_NAME ": %s: error enabling MSI for guest %u: err %d\n",
+               pr_warn_ratelimited("%s: error enabling MSI for guest %u: err %d\n",
                                    pci_name(dev), pdev->xdev->otherend_id,
                                    status);
                op->value = 0;
@@ -225,7 +228,7 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev,
                                                op->msix_entries[i].vector);
                }
        } else
-               pr_warn_ratelimited(DRV_NAME ": %s: error enabling MSI-X for guest %u: err %d!\n",
+               pr_warn_ratelimited("%s: error enabling MSI-X for guest %u: err %d!\n",
                                    pci_name(dev), pdev->xdev->otherend_id,
                                    result);
        kfree(entries);
@@ -372,7 +375,7 @@ static irqreturn_t xen_pcibk_guest_interrupt(int irq, void *dev_id)
                dev_data->handled++;
                if ((dev_data->handled % 1000) == 0) {
                        if (xen_test_irq_shared(irq)) {
-                               printk(KERN_INFO "%s IRQ line is not shared "
+                               pr_info("%s IRQ line is not shared "
                                        "with other domains. Turning ISR off\n",
                                         dev_data->irq_name);
                                dev_data->ack_intr = 0;
index 0f478ac483cd418e1a8a0b84fdb1b35651ce6404..3165ce361b0012e8fafdc4f1c6be8492b7afe739 100644 (file)
@@ -5,6 +5,8 @@
  *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
@@ -102,8 +104,7 @@ static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
                                       struct pci_dev_entry, list);
 
                        if (match_slot(dev, t->dev)) {
-                               pr_info(DRV_NAME ": vpci: %s: "
-                                       "assign to virtual slot %d func %d\n",
+                               pr_info("vpci: %s: assign to virtual slot %d func %d\n",
                                        pci_name(dev), slot,
                                        PCI_FUNC(dev->devfn));
                                list_add_tail(&dev_entry->list,
@@ -117,9 +118,8 @@ static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
        /* Assign to a new slot on the virtual PCI bus */
        for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
                if (list_empty(&vpci_dev->dev_list[slot])) {
-                       printk(KERN_INFO DRV_NAME
-                              ": vpci: %s: assign to virtual slot %d\n",
-                              pci_name(dev), slot);
+                       pr_info("vpci: %s: assign to virtual slot %d\n",
+                               pci_name(dev), slot);
                        list_add_tail(&dev_entry->list,
                                      &vpci_dev->dev_list[slot]);
                        func = dev->is_virtfn ? 0 : PCI_FUNC(dev->devfn);
index 64b11f99eacc87c758e50736a565d793d4c5c415..a9ed867afaba5408a3949ca7f4808aebf2b5bab9 100644 (file)
@@ -3,6 +3,9 @@
  *
  *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -723,14 +726,13 @@ int __init xen_pcibk_xenbus_register(void)
 {
        xen_pcibk_wq = create_workqueue("xen_pciback_workqueue");
        if (!xen_pcibk_wq) {
-               printk(KERN_ERR "%s: create"
-                       "xen_pciback_workqueue failed\n", __func__);
+               pr_err("%s: create xen_pciback_workqueue failed\n", __func__);
                return -EFAULT;
        }
        xen_pcibk_backend = &xen_pcibk_vpci_backend;
        if (passthrough)
                xen_pcibk_backend = &xen_pcibk_passthrough_backend;
-       pr_info(DRV_NAME ": backend is %s\n", xen_pcibk_backend->name);
+       pr_info("backend is %s\n", xen_pcibk_backend->name);
        return xenbus_register_backend(&xen_pcibk_driver);
 }
 
index f70984a892aa5c16a0e24deaee28acb2497dc9f6..02817a85f877c777c603079a08cb27b236ee8ee2 100644 (file)
@@ -64,6 +64,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/bootmem.h>
 #include <linux/swap.h>
@@ -510,22 +512,19 @@ int xen_selfballoon_init(bool use_selfballooning, bool use_frontswap_selfshrink)
                return -ENODEV;
 
        if (xen_initial_domain()) {
-               pr_info("xen/balloon: Xen selfballooning driver "
-                               "disabled for domain0.\n");
+               pr_info("Xen selfballooning driver disabled for domain0\n");
                return -ENODEV;
        }
 
        xen_selfballooning_enabled = tmem_enabled && use_selfballooning;
        if (xen_selfballooning_enabled) {
-               pr_info("xen/balloon: Initializing Xen "
-                                       "selfballooning driver.\n");
+               pr_info("Initializing Xen selfballooning driver\n");
                enable = true;
        }
 #ifdef CONFIG_FRONTSWAP
        frontswap_selfshrinking = tmem_enabled && use_frontswap_selfshrink;
        if (frontswap_selfshrinking) {
-               pr_info("xen/balloon: Initializing frontswap "
-                                       "selfshrinking driver.\n");
+               pr_info("Initializing frontswap selfshrinking driver\n");
                enable = true;
        }
 #endif
index c5aa55c5d371e495e1a5c4a39051225d5fc27dd7..fdb0f339d0a75b06bfe37ec46bc08d90e14a9759 100644 (file)
@@ -30,6 +30,8 @@
  * IN THE SOFTWARE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/wait.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
@@ -205,13 +207,12 @@ int xb_init_comms(void)
        struct xenstore_domain_interface *intf = xen_store_interface;
 
        if (intf->req_prod != intf->req_cons)
-               printk(KERN_ERR "XENBUS request ring is not quiescent "
-                      "(%08x:%08x)!\n", intf->req_cons, intf->req_prod);
+               pr_err("request ring is not quiescent (%08x:%08x)!\n",
+                      intf->req_cons, intf->req_prod);
 
        if (intf->rsp_prod != intf->rsp_cons) {
-               printk(KERN_WARNING "XENBUS response ring is not quiescent "
-                      "(%08x:%08x): fixing up\n",
-                      intf->rsp_cons, intf->rsp_prod);
+               pr_warn("response ring is not quiescent (%08x:%08x): fixing up\n",
+                       intf->rsp_cons, intf->rsp_prod);
                /* breaks kdump */
                if (!reset_devices)
                        intf->rsp_cons = intf->rsp_prod;
@@ -225,7 +226,7 @@ int xb_init_comms(void)
                err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting,
                                                0, "xenbus", &xb_waitq);
                if (err < 0) {
-                       printk(KERN_ERR "XENBUS request irq failed %i\n", err);
+                       pr_err("request irq failed %i\n", err);
                        return err;
                }
 
index a6f42fc01407e435c477862d380e8a1da55d6656..b17707ee07d4f3057c1ab529f91dcbfd15203ff9 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/mm.h>
@@ -127,7 +129,7 @@ static int __init xenbus_backend_init(void)
 
        err = misc_register(&xenbus_backend_dev);
        if (err)
-               printk(KERN_ERR "Could not register xenbus backend device\n");
+               pr_err("Could not register xenbus backend device\n");
        return err;
 }
 
index ac727028e658f75778fa916ca94e91c5d80e0737..85534ea6355588a79a2f589963edb7c146ebac83 100644 (file)
@@ -35,6 +35,8 @@
  *                              Turned xenfs into a loadable module.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/uio.h>
@@ -616,7 +618,7 @@ static int __init xenbus_init(void)
 
        err = misc_register(&xenbus_dev);
        if (err)
-               printk(KERN_ERR "Could not register xenbus frontend device\n");
+               pr_err("Could not register xenbus frontend device\n");
        return err;
 }
 
index 56cfaaa9d006ab1b86c47d6c1a9f1ab90268f399..38e92b770e91f224209dab2fc0e5543e8591bb65 100644 (file)
@@ -30,6 +30,8 @@
  * IN THE SOFTWARE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DPRINTK(fmt, args...)                          \
        pr_debug("xenbus_probe (%s:%d) " fmt ".\n",     \
                 __func__, __LINE__, ##args)
@@ -280,15 +282,15 @@ void xenbus_dev_shutdown(struct device *_dev)
 
        get_device(&dev->dev);
        if (dev->state != XenbusStateConnected) {
-               printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__,
-                      dev->nodename, xenbus_strstate(dev->state));
+               pr_info("%s: %s: %s != Connected, skipping\n",
+                       __func__, dev->nodename, xenbus_strstate(dev->state));
                goto out;
        }
        xenbus_switch_state(dev, XenbusStateClosing);
        timeout = wait_for_completion_timeout(&dev->down, timeout);
        if (!timeout)
-               printk(KERN_INFO "%s: %s timeout closing device\n",
-                      __func__, dev->nodename);
+               pr_info("%s: %s timeout closing device\n",
+                       __func__, dev->nodename);
  out:
        put_device(&dev->dev);
 }
@@ -447,7 +449,7 @@ int xenbus_probe_node(struct xen_bus_type *bus,
        if (err)
                goto fail;
 
-       dev_set_name(&xendev->dev, devname);
+       dev_set_name(&xendev->dev, "%s", devname);
 
        /* Register with generic device framework. */
        err = device_register(&xendev->dev);
@@ -579,8 +581,7 @@ int xenbus_dev_suspend(struct device *dev)
        if (drv->suspend)
                err = drv->suspend(xdev);
        if (err)
-               printk(KERN_WARNING
-                      "xenbus: suspend %s failed: %i\n", dev_name(dev), err);
+               pr_warn("suspend %s failed: %i\n", dev_name(dev), err);
        return 0;
 }
 EXPORT_SYMBOL_GPL(xenbus_dev_suspend);
@@ -599,9 +600,8 @@ int xenbus_dev_resume(struct device *dev)
        drv = to_xenbus_driver(dev->driver);
        err = talk_to_otherend(xdev);
        if (err) {
-               printk(KERN_WARNING
-                      "xenbus: resume (talk_to_otherend) %s failed: %i\n",
-                      dev_name(dev), err);
+               pr_warn("resume (talk_to_otherend) %s failed: %i\n",
+                       dev_name(dev), err);
                return err;
        }
 
@@ -610,18 +610,15 @@ int xenbus_dev_resume(struct device *dev)
        if (drv->resume) {
                err = drv->resume(xdev);
                if (err) {
-                       printk(KERN_WARNING
-                              "xenbus: resume %s failed: %i\n",
-                              dev_name(dev), err);
+                       pr_warn("resume %s failed: %i\n", dev_name(dev), err);
                        return err;
                }
        }
 
        err = watch_otherend(xdev);
        if (err) {
-               printk(KERN_WARNING
-                      "xenbus_probe: resume (watch_otherend) %s failed: "
-                      "%d.\n", dev_name(dev), err);
+               pr_warn("resume (watch_otherend) %s failed: %d.\n",
+                       dev_name(dev), err);
                return err;
        }
 
@@ -776,8 +773,7 @@ static int __init xenbus_init(void)
        /* Initialize the interface to xenstore. */
        err = xs_init();
        if (err) {
-               printk(KERN_WARNING
-                      "XENBUS: Error initializing xenstore comms: %i\n", err);
+               pr_warn("Error initializing xenstore comms: %i\n", err);
                goto out_error;
        }
 
index 257be37d90911d0721de9c134c0af93639519ad4..998bbbab816be6c59a4a71b8b183a2a39f053aff 100644 (file)
  * IN THE SOFTWARE.
  */
 
-#define DPRINTK(fmt, args...)                          \
-       pr_debug("xenbus_probe (%s:%d) " fmt ".\n",     \
-                __func__, __LINE__, ##args)
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define DPRINTK(fmt, ...)                              \
+       pr_debug("(%s:%d) " fmt "\n",                   \
+                __func__, __LINE__, ##__VA_ARGS__)
 
 #include <linux/kernel.h>
 #include <linux/err.h>
index a7e25073de19bc3b70e95b2a8697792f62312b63..6ed8a9df4472edc36b91b70ca3a0f463f237108d 100644 (file)
@@ -1,6 +1,8 @@
-#define DPRINTK(fmt, args...)                          \
-       pr_debug("xenbus_probe (%s:%d) " fmt ".\n",     \
-                __func__, __LINE__, ##args)
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define DPRINTK(fmt, ...)                              \
+       pr_debug("(%s:%d) " fmt "\n",                   \
+                __func__, __LINE__, ##__VA_ARGS__)
 
 #include <linux/kernel.h>
 #include <linux/err.h>
@@ -36,13 +38,13 @@ static int frontend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)
 {
        nodename = strchr(nodename, '/');
        if (!nodename || strlen(nodename + 1) >= XEN_BUS_ID_SIZE) {
-               printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
+               pr_warn("bad frontend %s\n", nodename);
                return -EINVAL;
        }
 
        strlcpy(bus_id, nodename + 1, XEN_BUS_ID_SIZE);
        if (!strchr(bus_id, '/')) {
-               printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
+               pr_warn("bus_id %s no slash\n", bus_id);
                return -EINVAL;
        }
        *strchr(bus_id, '/') = '-';
@@ -234,15 +236,13 @@ static int print_device_status(struct device *dev, void *data)
 
        if (!dev->driver) {
                /* Information only: is this too noisy? */
-               printk(KERN_INFO "XENBUS: Device with no driver: %s\n",
-                      xendev->nodename);
+               pr_info("Device with no driver: %s\n", xendev->nodename);
        } else if (xendev->state < XenbusStateConnected) {
                enum xenbus_state rstate = XenbusStateUnknown;
                if (xendev->otherend)
                        rstate = xenbus_read_driver_state(xendev->otherend);
-               printk(KERN_WARNING "XENBUS: Timeout connecting "
-                      "to device: %s (local state %d, remote state %d)\n",
-                      xendev->nodename, xendev->state, rstate);
+               pr_warn("Timeout connecting to device: %s (local state %d, remote state %d)\n",
+                       xendev->nodename, xendev->state, rstate);
        }
 
        return 0;
@@ -256,12 +256,13 @@ static bool wait_loop(unsigned long start, unsigned int max_delay,
 {
        if (time_after(jiffies, start + (*seconds_waited+5)*HZ)) {
                if (!*seconds_waited)
-                       printk(KERN_WARNING "XENBUS: Waiting for "
-                              "devices to initialise: ");
+                       pr_warn("Waiting for devices to initialise: ");
                *seconds_waited += 5;
-               printk("%us...", max_delay - *seconds_waited);
-               if (*seconds_waited == max_delay)
+               pr_cont("%us...", max_delay - *seconds_waited);
+               if (*seconds_waited == max_delay) {
+                       pr_cont("\n");
                        return true;
+               }
        }
 
        schedule_timeout_interruptible(HZ/10);
@@ -342,7 +343,7 @@ static void xenbus_reset_wait_for_backend(char *be, int expected)
        timeout = wait_event_interruptible_timeout(backend_state_wq,
                        backend_state == expected, 5 * HZ);
        if (timeout <= 0)
-               printk(KERN_INFO "XENBUS: backend %s timed out.\n", be);
+               pr_info("backend %s timed out\n", be);
 }
 
 /*
@@ -365,7 +366,7 @@ static void xenbus_reset_frontend(char *fe, char *be, int be_state)
        be_watch.callback = xenbus_reset_backend_state_changed;
        backend_state = XenbusStateUnknown;
 
-       printk(KERN_INFO "XENBUS: triggering reconnect on %s\n", be);
+       pr_info("triggering reconnect on %s\n", be);
        register_xenbus_watch(&be_watch);
 
        /* fall through to forward backend to state XenbusStateInitialising */
@@ -384,7 +385,7 @@ static void xenbus_reset_frontend(char *fe, char *be, int be_state)
        }
 
        unregister_xenbus_watch(&be_watch);
-       printk(KERN_INFO "XENBUS: reconnect done on %s\n", be);
+       pr_info("reconnect done on %s\n", be);
        kfree(be_watch.node);
 }
 
index 88e677b0de74042f017ef017bf08a1029311c3ce..b6d5fff43d16b90993b49ac2a91d14f64b791664 100644 (file)
@@ -31,6 +31,8 @@
  * IN THE SOFTWARE.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/unistd.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -129,9 +131,8 @@ static int get_error(const char *errorstring)
 
        for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) {
                if (i == ARRAY_SIZE(xsd_errors) - 1) {
-                       printk(KERN_WARNING
-                              "XENBUS xen store gave: unknown error %s",
-                              errorstring);
+                       pr_warn("xen store gave: unknown error %s\n",
+                               errorstring);
                        return EINVAL;
                }
        }
@@ -272,10 +273,8 @@ static void *xs_talkv(struct xenbus_transaction t,
        }
 
        if (msg.type != type) {
-               if (printk_ratelimit())
-                       printk(KERN_WARNING
-                              "XENBUS unexpected type [%d], expected [%d]\n",
-                              msg.type, type);
+               pr_warn_ratelimited("unexpected type [%d], expected [%d]\n",
+                                   msg.type, type);
                kfree(ret);
                return ERR_PTR(-EINVAL);
        }
@@ -655,7 +654,7 @@ static void xs_reset_watches(void)
 
        err = xs_error(xs_single(XBT_NIL, XS_RESET_WATCHES, "", NULL));
        if (err && err != -EEXIST)
-               printk(KERN_WARNING "xs_reset_watches failed: %d\n", err);
+               pr_warn("xs_reset_watches failed: %d\n", err);
 }
 
 /* Register callback to watch this node. */
@@ -705,9 +704,7 @@ void unregister_xenbus_watch(struct xenbus_watch *watch)
 
        err = xs_unwatch(watch->node, token);
        if (err)
-               printk(KERN_WARNING
-                      "XENBUS Failed to release watch %s: %i\n",
-                      watch->node, err);
+               pr_warn("Failed to release watch %s: %i\n", watch->node, err);
 
        up_read(&xs_state.watch_mutex);
 
@@ -901,8 +898,7 @@ static int xenbus_thread(void *unused)
        for (;;) {
                err = process_msg();
                if (err)
-                       printk(KERN_WARNING "XENBUS error %d while reading "
-                              "message\n", err);
+                       pr_warn("error %d while reading message\n", err);
                if (kthread_should_stop())
                        break;
        }
index b91f8ff50d05996148f6cbc589bcdae06d72efc3..4793fc594549742389fd8b420215b2cd76fd914d 100644 (file)
@@ -18,6 +18,8 @@
  * Authors: Hollis Blanchard <hollisb@us.ibm.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <asm/page.h>
index 71679875f056ccaf92eafba1b0a194cd7f177429..06092e0fe8cea4d3a5dfddac4df0e9bb531c5a60 100644 (file)
@@ -7,6 +7,8 @@
  *                              Turned xenfs into a loadable module.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/module.h>
@@ -82,7 +84,7 @@ static int __init xenfs_init(void)
        if (xen_domain())
                return register_filesystem(&xenfs_type);
 
-       printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n");
+       pr_info("not registering filesystem on non-xen platform\n");
        return 0;
 }
 
index 1c15ee7456b6cdce859189daaafd9dd7177f831e..ea1ce822a8e0437120184a8e559bd0495860c7b7 100644 (file)
 static loff_t
 proc_bus_zorro_lseek(struct file *file, loff_t off, int whence)
 {
-       loff_t new = -1;
-       struct inode *inode = file_inode(file);
-
-       mutex_lock(&inode->i_mutex);
-       switch (whence) {
-       case 0:
-               new = off;
-               break;
-       case 1:
-               new = file->f_pos + off;
-               break;
-       case 2:
-               new = sizeof(struct ConfigDev) + off;
-               break;
-       }
-       if (new < 0 || new > sizeof(struct ConfigDev))
-               new = -EINVAL;
-       else
-               file->f_pos = new;
-       mutex_unlock(&inode->i_mutex);
-       return new;
+       return fixed_size_llseek(file, off, whence, sizeof(struct ConfigDev));
 }
 
 static ssize_t
index ade28bb058e311dc3b2f120e2405884c4e090f7d..0d138c0de293ed3512046058b5ff96cac8c744ad 100644 (file)
@@ -191,8 +191,7 @@ const struct file_operations adfs_dir_operations = {
 };
 
 static int
-adfs_hash(const struct dentry *parent, const struct inode *inode,
-               struct qstr *qstr)
+adfs_hash(const struct dentry *parent, struct qstr *qstr)
 {
        const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen;
        const unsigned char *name;
@@ -228,8 +227,7 @@ adfs_hash(const struct dentry *parent, const struct inode *inode,
  * requirements of the underlying filesystem.
  */
 static int
-adfs_compare(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+adfs_compare(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        int i;
index ff65884a7839974ca472a64097ac996245c96346..c36cbb4537a26e0348a44f0ec7a65f64ac3204bf 100644 (file)
 typedef int (*toupper_t)(int);
 
 static int      affs_toupper(int ch);
-static int      affs_hash_dentry(const struct dentry *,
-               const struct inode *, struct qstr *);
-static int       affs_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int      affs_hash_dentry(const struct dentry *, struct qstr *);
+static int       affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 static int      affs_intl_toupper(int ch);
-static int      affs_intl_hash_dentry(const struct dentry *,
-               const struct inode *, struct qstr *);
-static int       affs_intl_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int      affs_intl_hash_dentry(const struct dentry *, struct qstr *);
+static int       affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 const struct dentry_operations affs_dentry_operations = {
@@ -86,14 +80,12 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper)
 }
 
 static int
-affs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
        return __affs_hash_dentry(qstr, affs_toupper);
 }
 static int
-affs_intl_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
        return __affs_hash_dentry(qstr, affs_intl_toupper);
 }
@@ -131,15 +123,13 @@ static inline int __affs_compare_dentry(unsigned int len,
 }
 
 static int
-affs_compare_dentry(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return __affs_compare_dentry(len, str, name, affs_toupper);
 }
 static int
-affs_intl_compare_dentry(const struct dentry *parent,const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return __affs_compare_dentry(len, str, name, affs_intl_toupper);
index 2497bf306c70e4593d552f6e427bfaa81a7d7ccc..a8cf2cff836c337fa64f22009c7cc15e4aa8b6bf 100644 (file)
@@ -252,7 +252,8 @@ static void afs_defer_unlock(struct afs_vnode *vnode, struct key *key)
  */
 static int afs_do_setlk(struct file *file, struct file_lock *fl)
 {
-       struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host);
+       struct inode *inode = file_inode(file);
+       struct afs_vnode *vnode = AFS_FS_I(inode);
        afs_lock_type_t type;
        struct key *key = file->private_data;
        int ret;
@@ -273,7 +274,7 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
 
        type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
 
        /* make sure we've got a callback on this file and that our view of the
         * data version is up to date */
@@ -420,7 +421,7 @@ given_lock:
        afs_vnode_fetch_status(vnode, NULL, key);
 
 error:
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        _leave(" = %d", ret);
        return ret;
 
index 2bbcacf74d0c64f8814cb68d8c4eff423dfe98d4..9b5ca113741948d95330d866e8e4e2cce113f3e5 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -39,6 +39,8 @@
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
 
+#include "internal.h"
+
 #define AIO_RING_MAGIC                 0xa10a10a1
 #define AIO_RING_COMPAT_FEATURES       1
 #define AIO_RING_INCOMPAT_FEATURES     0
@@ -623,7 +625,7 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
 
        /*
         * Add a completion event to the ring buffer. Must be done holding
-        * ctx->ctx_lock to prevent other code from messing with the tail
+        * ctx->completion_lock to prevent other code from messing with the tail
         * pointer since we might be called from irq context.
         */
        spin_lock_irqsave(&ctx->completion_lock, flags);
index 2091db8cdd783a2287ce9165a7223cfe59cf5a2b..bb43ce081d6ecef40b552d27f2b846a0d1a7606c 100644 (file)
@@ -325,31 +325,10 @@ static int blkdev_write_end(struct file *file, struct address_space *mapping,
 static loff_t block_llseek(struct file *file, loff_t offset, int whence)
 {
        struct inode *bd_inode = file->f_mapping->host;
-       loff_t size;
        loff_t retval;
 
        mutex_lock(&bd_inode->i_mutex);
-       size = i_size_read(bd_inode);
-
-       retval = -EINVAL;
-       switch (whence) {
-               case SEEK_END:
-                       offset += size;
-                       break;
-               case SEEK_CUR:
-                       offset += file->f_pos;
-               case SEEK_SET:
-                       break;
-               default:
-                       goto out;
-       }
-       if (offset >= 0 && offset <= size) {
-               if (offset != file->f_pos) {
-                       file->f_pos = offset;
-               }
-               retval = offset;
-       }
-out:
+       retval = fixed_size_llseek(file, offset, whence, i_size_read(bd_inode));
        mutex_unlock(&bd_inode->i_mutex);
        return retval;
 }
@@ -1583,6 +1562,7 @@ static const struct address_space_operations def_blk_aops = {
        .writepages     = generic_writepages,
        .releasepage    = blkdev_releasepage,
        .direct_IO      = blkdev_direct_IO,
+       .is_dirty_writeback = buffer_check_dirty_writeback,
 };
 
 const struct file_operations def_blk_fops = {
index 4205ba752d40ccbadfb0fa0b1f053b1022c553c0..89da56a58b635c9bf80197c0cf32e2dc3f698442 100644 (file)
@@ -2425,20 +2425,7 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence)
                }
        }
 
-       if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) {
-               offset = -EINVAL;
-               goto out;
-       }
-       if (offset > inode->i_sb->s_maxbytes) {
-               offset = -EINVAL;
-               goto out;
-       }
-
-       /* Special lock needed here? */
-       if (offset != file->f_pos) {
-               file->f_pos = offset;
-               file->f_version = 0;
-       }
+       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 out:
        mutex_unlock(&inode->i_mutex);
        return offset;
index 0f81d67cdc8da651890df1a89c01df9188667d97..cd7e96c73cb71df0589f1866346ab5ff2714eb96 100644 (file)
@@ -3881,7 +3881,7 @@ drop_write:
 
 static long btrfs_ioctl_quota_rescan(struct file *file, void __user *arg)
 {
-       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+       struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
        struct btrfs_ioctl_quota_rescan_args *qsa;
        int ret;
 
@@ -3914,7 +3914,7 @@ drop_write:
 
 static long btrfs_ioctl_quota_rescan_status(struct file *file, void __user *arg)
 {
-       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+       struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
        struct btrfs_ioctl_quota_rescan_args *qsa;
        int ret = 0;
 
@@ -4020,7 +4020,7 @@ out:
 
 static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg)
 {
-       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+       struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
        const char *label = root->fs_info->super_copy->label;
        size_t len = strnlen(label, BTRFS_LABEL_SIZE);
        int ret;
@@ -4039,7 +4039,7 @@ static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg)
 
 static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg)
 {
-       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
+       struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
        struct btrfs_super_block *super_block = root->fs_info->super_copy;
        struct btrfs_trans_handle *trans;
        char label[BTRFS_LABEL_SIZE];
index f93392e2df126fd5c17833b7105338fc6f65be5f..4d7433534f5cd77b7f9b240fba57ac7923df07e6 100644 (file)
@@ -82,6 +82,40 @@ void unlock_buffer(struct buffer_head *bh)
 }
 EXPORT_SYMBOL(unlock_buffer);
 
+/*
+ * Returns if the page has dirty or writeback buffers. If all the buffers
+ * are unlocked and clean then the PageDirty information is stale. If
+ * any of the pages are locked, it is assumed they are locked for IO.
+ */
+void buffer_check_dirty_writeback(struct page *page,
+                                    bool *dirty, bool *writeback)
+{
+       struct buffer_head *head, *bh;
+       *dirty = false;
+       *writeback = false;
+
+       BUG_ON(!PageLocked(page));
+
+       if (!page_has_buffers(page))
+               return;
+
+       if (PageWriteback(page))
+               *writeback = true;
+
+       head = page_buffers(page);
+       bh = head;
+       do {
+               if (buffer_locked(bh))
+                       *writeback = true;
+
+               if (buffer_dirty(bh))
+                       *dirty = true;
+
+               bh = bh->b_this_page;
+       } while (bh != head);
+}
+EXPORT_SYMBOL(buffer_check_dirty_writeback);
+
 /*
  * Block until a buffer comes unlocked.  This doesn't stop it
  * from becoming locked again - you have to lock it yourself
index 317f9ee9c99178d7afd774ff424bbd63fab2ff17..ebaff368120da71e8f4ff83405d22c74cf01f3d8 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mount.h>
 #include <linux/slab.h>
 #include <linux/file.h>
+#include <linux/swap.h>
 #include "internal.h"
 
 /*
@@ -227,8 +228,7 @@ static void cachefiles_read_copier(struct fscache_operation *_op)
  */
 static int cachefiles_read_backing_file_one(struct cachefiles_object *object,
                                            struct fscache_retrieval *op,
-                                           struct page *netpage,
-                                           struct pagevec *pagevec)
+                                           struct page *netpage)
 {
        struct cachefiles_one_read *monitor;
        struct address_space *bmapping;
@@ -237,8 +237,6 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object,
 
        _enter("");
 
-       pagevec_reinit(pagevec);
-
        _debug("read back %p{%lu,%d}",
               netpage, netpage->index, page_count(netpage));
 
@@ -283,9 +281,7 @@ installed_new_backing_page:
        backpage = newpage;
        newpage = NULL;
 
-       page_cache_get(backpage);
-       pagevec_add(pagevec, backpage);
-       __pagevec_lru_add_file(pagevec);
+       lru_cache_add_file(backpage);
 
 read_backing_page:
        ret = bmapping->a_ops->readpage(NULL, backpage);
@@ -452,8 +448,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
        if (block) {
                /* submit the apparently valid page to the backing fs to be
                 * read from disk */
-               ret = cachefiles_read_backing_file_one(object, op, page,
-                                                      &pagevec);
+               ret = cachefiles_read_backing_file_one(object, op, page);
        } else if (cachefiles_has_space(cache, 0, 1) == 0) {
                /* there's space in the cache we can use */
                fscache_mark_page_cached(op, page);
@@ -482,14 +477,11 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
 {
        struct cachefiles_one_read *monitor = NULL;
        struct address_space *bmapping = object->backer->d_inode->i_mapping;
-       struct pagevec lru_pvec;
        struct page *newpage = NULL, *netpage, *_n, *backpage = NULL;
        int ret = 0;
 
        _enter("");
 
-       pagevec_init(&lru_pvec, 0);
-
        list_for_each_entry_safe(netpage, _n, list, lru) {
                list_del(&netpage->lru);
 
@@ -534,9 +526,7 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
                backpage = newpage;
                newpage = NULL;
 
-               page_cache_get(backpage);
-               if (!pagevec_add(&lru_pvec, backpage))
-                       __pagevec_lru_add_file(&lru_pvec);
+               lru_cache_add_file(backpage);
 
        reread_backing_page:
                ret = bmapping->a_ops->readpage(NULL, backpage);
@@ -559,9 +549,7 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
                        goto nomem;
                }
 
-               page_cache_get(netpage);
-               if (!pagevec_add(&lru_pvec, netpage))
-                       __pagevec_lru_add_file(&lru_pvec);
+               lru_cache_add_file(netpage);
 
                /* install a monitor */
                page_cache_get(netpage);
@@ -643,9 +631,7 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
 
                fscache_mark_page_cached(op, netpage);
 
-               page_cache_get(netpage);
-               if (!pagevec_add(&lru_pvec, netpage))
-                       __pagevec_lru_add_file(&lru_pvec);
+               lru_cache_add_file(netpage);
 
                /* the netpage is unlocked and marked up to date here */
                fscache_end_io(op, netpage, 0);
@@ -661,8 +647,6 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
 
 out:
        /* tidy up */
-       pagevec_lru_add_file(&lru_pvec);
-
        if (newpage)
                page_cache_release(newpage);
        if (netpage)
index 656e169074305f12d34859ca07ee710c4c1a954d..16c989d3e23c762e52904419a81beae943332ea0 100644 (file)
@@ -866,16 +866,7 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int whence)
                break;
        }
 
-       if (offset < 0 || offset > inode->i_sb->s_maxbytes) {
-               offset = -EINVAL;
-               goto out;
-       }
-
-       /* Special lock needed here? */
-       if (offset != file->f_pos) {
-               file->f_pos = offset;
-               file->f_version = 0;
-       }
+       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out:
        mutex_unlock(&inode->i_mutex);
index ebbf680378e2ad3ad956babeb5b521e619830bcb..690f73f42425f1021727bad475fef24ae92b5f55 100644 (file)
@@ -192,7 +192,7 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
 
 /**
  * Encode the flock and fcntl locks for the given inode into the ceph_filelock
- * array. Must be called with lock_flocks() already held.
+ * array. Must be called with inode->i_lock already held.
  * If we encounter more of a specific lock type than expected, return -ENOSPC.
  */
 int ceph_encode_locks_to_buffer(struct inode *inode,
index 4d2920304be8e7e9075fd1f1b80b954cb26718f9..74fd2898b2ab43012ab1c3fbf25f619fbd7df3b2 100644 (file)
@@ -2481,20 +2481,20 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
                struct ceph_filelock *flocks;
 
 encode_again:
-               lock_flocks();
+               spin_lock(&inode->i_lock);
                ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                flocks = kmalloc((num_fcntl_locks+num_flock_locks) *
                                 sizeof(struct ceph_filelock), GFP_NOFS);
                if (!flocks) {
                        err = -ENOMEM;
                        goto out_free;
                }
-               lock_flocks();
+               spin_lock(&inode->i_lock);
                err = ceph_encode_locks_to_buffer(inode, flocks,
                                                  num_fcntl_locks,
                                                  num_flock_locks);
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                if (err) {
                        kfree(flocks);
                        if (err == -ENOSPC)
index 2906ee2764082786520718e4e4a490b9f3211ac6..603f18a65c121e5586f903baff101a8637bdb852 100644 (file)
@@ -10,6 +10,7 @@ config CIFS
        select CRYPTO_ECB
        select CRYPTO_DES
        select CRYPTO_SHA256
+       select CRYPTO_CMAC
        help
          This is the client VFS module for the Common Internet File System
          (CIFS) protocol which is the successor to the Server Message Block
index d59748346020f9302be6a5cf66730b9190f0af9d..f3ac4154cbb606707956d9fbbd2a64ec553a9ceb 100644 (file)
@@ -213,7 +213,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                                                   tcon->nativeFileSystem);
                                }
                                seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
-                                       "\nPathComponentMax: %d Status: 0x%d",
+                                       "\n\tPathComponentMax: %d Status: 0x%d",
                                        le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
                                        le32_to_cpu(tcon->fsAttrInfo.Attributes),
                                        le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
@@ -224,6 +224,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                                        seq_puts(m, " type: CDROM ");
                                else
                                        seq_printf(m, " type: %d ", dev_type);
+                               if (server->ops->dump_share_caps)
+                                       server->ops->dump_share_caps(m, tcon);
 
                                if (tcon->need_reconnect)
                                        seq_puts(m, "\tDISCONNECTED ");
@@ -595,9 +597,36 @@ static int cifs_security_flags_proc_open(struct inode *inode, struct file *file)
        return single_open(file, cifs_security_flags_proc_show, NULL);
 }
 
+/*
+ * Ensure that if someone sets a MUST flag, that we disable all other MAY
+ * flags except for the ones corresponding to the given MUST flag. If there are
+ * multiple MUST flags, then try to prefer more secure ones.
+ */
+static void
+cifs_security_flags_handle_must_flags(unsigned int *flags)
+{
+       unsigned int signflags = *flags & CIFSSEC_MUST_SIGN;
+
+       if ((*flags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
+               *flags = CIFSSEC_MUST_KRB5;
+       else if ((*flags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
+               *flags = CIFSSEC_MUST_NTLMSSP;
+       else if ((*flags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
+               *flags = CIFSSEC_MUST_NTLMV2;
+       else if ((*flags & CIFSSEC_MUST_NTLM) == CIFSSEC_MUST_NTLM)
+               *flags = CIFSSEC_MUST_NTLM;
+       else if ((*flags & CIFSSEC_MUST_LANMAN) == CIFSSEC_MUST_LANMAN)
+               *flags = CIFSSEC_MUST_LANMAN;
+       else if ((*flags & CIFSSEC_MUST_PLNTXT) == CIFSSEC_MUST_PLNTXT)
+               *flags = CIFSSEC_MUST_PLNTXT;
+
+       *flags |= signflags;
+}
+
 static ssize_t cifs_security_flags_proc_write(struct file *file,
                const char __user *buffer, size_t count, loff_t *ppos)
 {
+       int rc;
        unsigned int flags;
        char flags_string[12];
        char c;
@@ -620,26 +649,35 @@ static ssize_t cifs_security_flags_proc_write(struct file *file,
                        global_secflags = CIFSSEC_MAX;
                        return count;
                } else if (!isdigit(c)) {
-                       cifs_dbg(VFS, "invalid flag %c\n", c);
+                       cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
+                                       flags_string);
                        return -EINVAL;
                }
        }
-       /* else we have a number */
 
-       flags = simple_strtoul(flags_string, NULL, 0);
+       /* else we have a number */
+       rc = kstrtouint(flags_string, 0, &flags);
+       if (rc) {
+               cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
+                               flags_string);
+               return rc;
+       }
 
        cifs_dbg(FYI, "sec flags 0x%x\n", flags);
 
-       if (flags <= 0)  {
-               cifs_dbg(VFS, "invalid security flags %s\n", flags_string);
+       if (flags == 0)  {
+               cifs_dbg(VFS, "Invalid SecurityFlags: %s\n", flags_string);
                return -EINVAL;
        }
 
        if (flags & ~CIFSSEC_MASK) {
-               cifs_dbg(VFS, "attempt to set unsupported security flags 0x%x\n",
+               cifs_dbg(VFS, "Unsupported security flags: 0x%x\n",
                         flags & ~CIFSSEC_MASK);
                return -EINVAL;
        }
+
+       cifs_security_flags_handle_must_flags(&flags);
+
        /* flags look ok - update the global security flags for cifs module */
        global_secflags = flags;
        if (global_secflags & CIFSSEC_MUST_SIGN) {
index 4fb097468e214feb00b8602dd6dd658b20fafd88..fe8d6276410a5613230743f20312d4f283db2f4f 100644 (file)
@@ -327,14 +327,14 @@ UniToupper(register wchar_t uc)
 /*
  * UniStrupr:  Upper case a unicode string
  */
-static inline wchar_t *
-UniStrupr(register wchar_t *upin)
+static inline __le16 *
+UniStrupr(register __le16 *upin)
 {
-       register wchar_t *up;
+       register __le16 *up;
 
        up = upin;
        while (*up) {           /* For all characters */
-               *up = UniToupper(*up);
+               *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
                up++;
        }
        return upin;            /* Return input pointer */
index 71436d1fca13bede14a8a25ac6a9ae126e80dede..3d8bf941d1269ff3afa45baf1ed9f5aee8491431 100644 (file)
@@ -276,7 +276,6 @@ int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
                strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
 
        if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) {
-               memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
                memcpy(lnm_session_key, password_with_pad,
                        CIFS_ENCPWD_SIZE);
                return 0;
@@ -414,7 +413,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
        int rc = 0;
        int len;
        char nt_hash[CIFS_NTHASH_SIZE];
-       wchar_t *user;
+       __le16 *user;
        wchar_t *domain;
        wchar_t *server;
 
@@ -439,7 +438,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
                return rc;
        }
 
-       /* convert ses->user_name to unicode and uppercase */
+       /* convert ses->user_name to unicode */
        len = ses->user_name ? strlen(ses->user_name) : 0;
        user = kmalloc(2 + (len * 2), GFP_KERNEL);
        if (user == NULL) {
@@ -448,7 +447,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
        }
 
        if (len) {
-               len = cifs_strtoUTF16((__le16 *)user, ses->user_name, len, nls_cp);
+               len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
                UniStrupr(user);
        } else {
                memset(user, '\0', 2);
@@ -536,7 +535,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
                return rc;
        }
 
-       if (ses->server->secType == RawNTLMSSP)
+       if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
                memcpy(ses->auth_key.response + offset,
                        ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
        else
@@ -568,7 +567,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
        char ntlmv2_hash[16];
        unsigned char *tiblob = NULL; /* target info blob */
 
-       if (ses->server->secType == RawNTLMSSP) {
+       if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
                if (!ses->domainName) {
                        rc = find_domain_name(ses, nls_cp);
                        if (rc) {
@@ -706,6 +705,9 @@ calc_seckey(struct cifs_ses *ses)
 void
 cifs_crypto_shash_release(struct TCP_Server_Info *server)
 {
+       if (server->secmech.cmacaes)
+               crypto_free_shash(server->secmech.cmacaes);
+
        if (server->secmech.hmacsha256)
                crypto_free_shash(server->secmech.hmacsha256);
 
@@ -715,6 +717,8 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server)
        if (server->secmech.hmacmd5)
                crypto_free_shash(server->secmech.hmacmd5);
 
+       kfree(server->secmech.sdesccmacaes);
+
        kfree(server->secmech.sdeschmacsha256);
 
        kfree(server->secmech.sdeschmacmd5);
@@ -748,6 +752,13 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
                goto crypto_allocate_hmacsha256_fail;
        }
 
+       server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
+       if (IS_ERR(server->secmech.cmacaes)) {
+               cifs_dbg(VFS, "could not allocate crypto cmac-aes");
+               rc = PTR_ERR(server->secmech.cmacaes);
+               goto crypto_allocate_cmacaes_fail;
+       }
+
        size = sizeof(struct shash_desc) +
                        crypto_shash_descsize(server->secmech.hmacmd5);
        server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
@@ -778,8 +789,22 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
        server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
        server->secmech.sdeschmacsha256->shash.flags = 0x0;
 
+       size = sizeof(struct shash_desc) +
+                       crypto_shash_descsize(server->secmech.cmacaes);
+       server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
+       if (!server->secmech.sdesccmacaes) {
+               cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
+               rc = -ENOMEM;
+               goto crypto_allocate_cmacaes_sdesc_fail;
+       }
+       server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
+       server->secmech.sdesccmacaes->shash.flags = 0x0;
+
        return 0;
 
+crypto_allocate_cmacaes_sdesc_fail:
+       kfree(server->secmech.sdeschmacsha256);
+
 crypto_allocate_hmacsha256_sdesc_fail:
        kfree(server->secmech.sdescmd5);
 
@@ -787,6 +812,9 @@ crypto_allocate_md5_sdesc_fail:
        kfree(server->secmech.sdeschmacmd5);
 
 crypto_allocate_hmacmd5_sdesc_fail:
+       crypto_free_shash(server->secmech.cmacaes);
+
+crypto_allocate_cmacaes_fail:
        crypto_free_shash(server->secmech.hmacsha256);
 
 crypto_allocate_hmacsha256_fail:
index 540c1ccfcdb28a310614f24b873f81f4c4e652d3..4bdd547dbf6fb3d10a2b2b962b710b722d0b9685 100644 (file)
@@ -312,11 +312,14 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
 }
 
 static void
-cifs_show_security(struct seq_file *s, struct TCP_Server_Info *server)
+cifs_show_security(struct seq_file *s, struct cifs_ses *ses)
 {
+       if (ses->sectype == Unspecified)
+               return;
+
        seq_printf(s, ",sec=");
 
-       switch (server->secType) {
+       switch (ses->sectype) {
        case LANMAN:
                seq_printf(s, "lanman");
                break;
@@ -338,7 +341,7 @@ cifs_show_security(struct seq_file *s, struct TCP_Server_Info *server)
                break;
        }
 
-       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->sign)
                seq_printf(s, "i");
 }
 
@@ -369,7 +372,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
        srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr;
 
        seq_printf(s, ",vers=%s", tcon->ses->server->vals->version_string);
-       cifs_show_security(s, tcon->ses->server);
+       cifs_show_security(s, tcon->ses);
        cifs_show_cache_flavor(s, cifs_sb);
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
@@ -765,7 +768,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
 
 static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
 {
-       /* note that this is called by vfs setlease with lock_flocks held
+       /* note that this is called by vfs setlease with i_lock held
           to protect *lease from going away */
        struct inode *inode = file_inode(file);
        struct cifsFileInfo *cfile = file->private_data;
index d05b3028e3b96ef7c99eaa202d10bc22630489e7..ea723a5e8226231d64cd85eab065c7f91801a3a0 100644 (file)
@@ -132,5 +132,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "2.0"
+#define CIFS_VERSION   "2.01"
 #endif                         /* _CIFSFS_H */
index 4f07f6fbe4944c5e6f8bdf12c30b4eaed9397976..e66b08882548eb90597fcb6ea0f86139a710b204 100644 (file)
@@ -101,20 +101,14 @@ enum statusEnum {
 };
 
 enum securityEnum {
-       LANMAN = 0,                     /* Legacy LANMAN auth */
+       Unspecified = 0,        /* not specified */
+       LANMAN,                 /* Legacy LANMAN auth */
        NTLM,                   /* Legacy NTLM012 auth with NTLM hash */
        NTLMv2,                 /* Legacy NTLM auth with NTLMv2 hash */
        RawNTLMSSP,             /* NTLMSSP without SPNEGO, NTLMv2 hash */
-/*     NTLMSSP, */ /* can use rawNTLMSSP instead of NTLMSSP via SPNEGO */
        Kerberos,               /* Kerberos via SPNEGO */
 };
 
-enum protocolEnum {
-       TCP = 0,
-       SCTP
-       /* Netbios frames protocol not supported at this time */
-};
-
 struct session_key {
        unsigned int len;
        char *response;
@@ -131,9 +125,11 @@ struct cifs_secmech {
        struct crypto_shash *hmacmd5; /* hmac-md5 hash function */
        struct crypto_shash *md5; /* md5 hash function */
        struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
+       struct crypto_shash *cmacaes; /* block-cipher based MAC function */
        struct sdesc *sdeschmacmd5;  /* ctxt to generate ntlmv2 hash, CR1 */
        struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
        struct sdesc *sdeschmacsha256;  /* ctxt to generate smb2 signature */
+       struct sdesc *sdesccmacaes;  /* ctxt to generate smb3 signature */
 };
 
 /* per smb session structure/fields */
@@ -181,6 +177,7 @@ enum smb_version {
        Smb_20,
        Smb_21,
        Smb_30,
+       Smb_302,
 };
 
 struct mid_q_entry;
@@ -228,6 +225,7 @@ struct smb_version_operations {
        void (*dump_detail)(void *);
        void (*clear_stats)(struct cifs_tcon *);
        void (*print_stats)(struct seq_file *m, struct cifs_tcon *);
+       void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *);
        /* verify the message */
        int (*check_message)(char *, unsigned int);
        bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
@@ -367,6 +365,8 @@ struct smb_version_operations {
        void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
        /* generate new lease key */
        void (*new_lease_key)(struct cifs_fid *fid);
+       /* The next two functions will need to be changed to per smb session */
+       void (*generate_signingkey)(struct TCP_Server_Info *server);
        int (*calc_signature)(struct smb_rqst *rqst,
                                   struct TCP_Server_Info *server);
 };
@@ -387,6 +387,8 @@ struct smb_version_values {
        unsigned int    cap_nt_find;
        unsigned int    cap_large_files;
        unsigned int    oplock_read;
+       __u16           signing_enabled;
+       __u16           signing_required;
 };
 
 #define HEADER_SIZE(server) (server->vals->header_size)
@@ -407,7 +409,8 @@ struct smb_vol {
        kgid_t backupgid;
        umode_t file_mode;
        umode_t dir_mode;
-       unsigned secFlg;
+       enum securityEnum sectype; /* sectype requested via mnt opts */
+       bool sign; /* was signing requested via mnt opts? */
        bool retry:1;
        bool intr:1;
        bool setuids:1;
@@ -441,6 +444,7 @@ struct smb_vol {
        bool mfsymlinks:1; /* use Minshall+French Symlinks */
        bool multiuser:1;
        bool rwpidforward:1; /* pid forward for read/write operations */
+       bool nosharesock;
        unsigned int rsize;
        unsigned int wsize;
        bool sockopt_tcp_nodelay:1;
@@ -514,6 +518,7 @@ struct TCP_Server_Info {
        struct task_struct *tsk;
        char server_GUID[16];
        __u16 sec_mode;
+       bool sign; /* is signing enabled on this connection? */
        bool session_estab; /* mark when very first sess is established */
 #ifdef CONFIG_CIFS_SMB2
        int echo_credits;  /* echo reserved slots */
@@ -521,7 +526,6 @@ struct TCP_Server_Info {
        bool echoes:1; /* enable echoes */
 #endif
        u16 dialect; /* dialect index that server chose */
-       enum securityEnum secType;
        bool oplocks:1; /* enable oplocks */
        unsigned int maxReq;    /* Clients should submit no more */
        /* than maxReq distinct unanswered SMBs to the server when using  */
@@ -540,12 +544,17 @@ struct TCP_Server_Info {
        int timeAdj;  /* Adjust for difference in server time zone in sec */
        __u64 CurrentMid;         /* multiplex id - rotating counter */
        char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
+       char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
        /* 16th byte of RFC1001 workstation name is always null */
        char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
        __u32 sequence_number; /* for signing, protected by srv_mutex */
        struct session_key session_key;
        unsigned long lstrp; /* when we got last response from this server */
        struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
+#define        CIFS_NEGFLAVOR_LANMAN   0       /* wct == 13, LANMAN */
+#define        CIFS_NEGFLAVOR_UNENCAP  1       /* wct == 17, but no ext_sec */
+#define        CIFS_NEGFLAVOR_EXTENDED 2       /* wct == 17, ext_sec bit set */
+       char    negflavor;      /* NEGOTIATE response flavor */
        /* extended security flavors that server supports */
        bool    sec_ntlmssp;            /* supports NTLMSSP */
        bool    sec_kerberosu2u;        /* supports U2U Kerberos */
@@ -697,7 +706,6 @@ struct cifs_ses {
        enum statusEnum status;
        unsigned overrideSecFlg;  /* if non-zero override global sec flags */
        __u16 ipc_tid;          /* special tid for connection to IPC share */
-       __u16 flags;
        __u16 vcnum;
        char *serverOS;         /* name of operating system underlying server */
        char *serverNOS;        /* name of network operating system of server */
@@ -714,21 +722,14 @@ struct cifs_ses {
        char *password;
        struct session_key auth_key;
        struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */
+       enum securityEnum sectype; /* what security flavor was specified? */
+       bool sign;              /* is signing required? */
        bool need_reconnect:1; /* connection reset, uid now invalid */
 #ifdef CONFIG_CIFS_SMB2
        __u16 session_flags;
 #endif /* CONFIG_CIFS_SMB2 */
 };
 
-/* no more than one of the following three session flags may be set */
-#define CIFS_SES_NT4 1
-#define CIFS_SES_OS2 2
-#define CIFS_SES_W9X 4
-/* following flag is set for old servers such as OS2 (and Win95?)
-   which do not negotiate NTLM or POSIX dialects, but instead
-   negotiate one of the older LANMAN dialects */
-#define CIFS_SES_LANMAN 8
-
 static inline bool
 cap_unix(struct cifs_ses *ses)
 {
@@ -816,7 +817,7 @@ struct cifs_tcon {
 #ifdef CONFIG_CIFS_SMB2
        bool print:1;           /* set if connection to printer share */
        bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
-       __u32 capabilities;
+       __le32 capabilities;
        __u32 share_flags;
        __u32 maximal_access;
        __u32 vol_serial_number;
@@ -1348,7 +1349,7 @@ require use of the stronger protocol */
 #define   CIFSSEC_MUST_SEAL    0x40040 /* not supported yet */
 #define   CIFSSEC_MUST_NTLMSSP 0x80080 /* raw ntlmssp with ntlmv2 */
 
-#define   CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLMSSP)
+#define   CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_NTLMSSP)
 #define   CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2)
 #define   CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)
 /*
@@ -1494,4 +1495,7 @@ extern struct smb_version_values smb21_values;
 #define SMB30_VERSION_STRING   "3.0"
 extern struct smb_version_operations smb30_operations;
 extern struct smb_version_values smb30_values;
+#define SMB302_VERSION_STRING  "3.02"
+/*extern struct smb_version_operations smb302_operations;*/ /* not needed yet */
+extern struct smb_version_values smb302_values;
 #endif /* _CIFS_GLOB_H */
index e996ff6b26d1886f63a6c162a09a996e80edf32a..11ca24a8e054ef11472ba634472e6e8622008305 100644 (file)
  */
 #define CIFS_SESS_KEY_SIZE (16)
 
+/*
+ * Size of the smb3 signing key
+ */
+#define SMB3_SIGN_KEY_SIZE (16)
+
 #define CIFS_CLIENT_CHALLENGE_SIZE (8)
 #define CIFS_SERVER_CHALLENGE_SIZE (8)
 #define CIFS_HMAC_MD5_HASH_SIZE (16)
@@ -531,7 +536,7 @@ typedef struct lanman_neg_rsp {
 #define READ_RAW_ENABLE 1
 #define WRITE_RAW_ENABLE 2
 #define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE)
-
+#define SMB1_CLIENT_GUID_SIZE (16)
 typedef struct negotiate_rsp {
        struct smb_hdr hdr;     /* wct = 17 */
        __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */
@@ -553,7 +558,7 @@ typedef struct negotiate_rsp {
                /* followed by 16 bytes of server GUID */
                /* then security blob if cap_extended_security negotiated */
                struct {
-                       unsigned char GUID[16];
+                       unsigned char GUID[SMB1_CLIENT_GUID_SIZE];
                        unsigned char SecurityBlob[1];
                } __attribute__((packed)) extended_response;
        } __attribute__((packed)) u;
@@ -1315,6 +1320,14 @@ typedef struct smb_com_ntransact_rsp {
        /* parms and data follow */
 } __attribute__((packed)) NTRANSACT_RSP;
 
+/* See MS-SMB 2.2.7.2.1.1 */
+struct srv_copychunk {
+       __le64 SourceOffset;
+       __le64 DestinationOffset;
+       __le32 CopyLength;
+       __u32  Reserved;
+} __packed;
+
 typedef struct smb_com_transaction_ioctl_req {
        struct smb_hdr hdr;     /* wct = 23 */
        __u8 MaxSetupCount;
index dda188a94332bfbf569121680d3207360e1acc3a..c8ff018fae6887640c277269c649feae49545ce2 100644 (file)
@@ -118,6 +118,8 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
 extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
                                struct cifs_ses *ses,
                                void **request_buf);
+extern enum securityEnum select_sectype(struct TCP_Server_Info *server,
+                               enum securityEnum requested);
 extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
                          const struct nls_table *nls_cp);
 extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
@@ -212,6 +214,7 @@ extern int cifs_negotiate_protocol(const unsigned int xid,
                                   struct cifs_ses *ses);
 extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
                              struct nls_table *nls_info);
+extern int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required);
 extern int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses);
 
 extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
@@ -433,6 +436,7 @@ extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
 extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
 extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
 extern int calc_seckey(struct cifs_ses *);
+extern void generate_smb3signingkey(struct TCP_Server_Info *);
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 extern int calc_lanman_hash(const char *password, const char *cryptkey,
index a58dc77cc4430d57d8c8226c3120f3a12519fb00..a89c4cb4e6cf64e8cbd92fe6f7ceb6b7e941eca3 100644 (file)
@@ -367,6 +367,185 @@ vt2_err:
        return -EINVAL;
 }
 
+static int
+decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
+{
+       int     rc = 0;
+       u16     count;
+       char    *guid = pSMBr->u.extended_response.GUID;
+       struct TCP_Server_Info *server = ses->server;
+
+       count = get_bcc(&pSMBr->hdr);
+       if (count < SMB1_CLIENT_GUID_SIZE)
+               return -EIO;
+
+       spin_lock(&cifs_tcp_ses_lock);
+       if (server->srv_count > 1) {
+               spin_unlock(&cifs_tcp_ses_lock);
+               if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
+                       cifs_dbg(FYI, "server UID changed\n");
+                       memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
+               }
+       } else {
+               spin_unlock(&cifs_tcp_ses_lock);
+               memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
+       }
+
+       if (count == SMB1_CLIENT_GUID_SIZE) {
+               server->sec_ntlmssp = true;
+       } else {
+               count -= SMB1_CLIENT_GUID_SIZE;
+               rc = decode_negTokenInit(
+                       pSMBr->u.extended_response.SecurityBlob, count, server);
+               if (rc != 1)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+int
+cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
+{
+       bool srv_sign_required = server->sec_mode & server->vals->signing_required;
+       bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
+       bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
+
+       /*
+        * Is signing required by mnt options? If not then check
+        * global_secflags to see if it is there.
+        */
+       if (!mnt_sign_required)
+               mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
+                                               CIFSSEC_MUST_SIGN);
+
+       /*
+        * If signing is required then it's automatically enabled too,
+        * otherwise, check to see if the secflags allow it.
+        */
+       mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
+                               (global_secflags & CIFSSEC_MAY_SIGN);
+
+       /* If server requires signing, does client allow it? */
+       if (srv_sign_required) {
+               if (!mnt_sign_enabled) {
+                       cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
+                       return -ENOTSUPP;
+               }
+               server->sign = true;
+       }
+
+       /* If client requires signing, does server allow it? */
+       if (mnt_sign_required) {
+               if (!srv_sign_enabled) {
+                       cifs_dbg(VFS, "Server does not support signing!");
+                       return -ENOTSUPP;
+               }
+               server->sign = true;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+static int
+decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
+{
+       __s16 tmp;
+       struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
+
+       if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
+               return -EOPNOTSUPP;
+
+       server->sec_mode = le16_to_cpu(rsp->SecurityMode);
+       server->maxReq = min_t(unsigned int,
+                              le16_to_cpu(rsp->MaxMpxCount),
+                              cifs_max_pending);
+       set_credits(server, server->maxReq);
+       server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
+       server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
+       /* even though we do not use raw we might as well set this
+       accurately, in case we ever find a need for it */
+       if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
+               server->max_rw = 0xFF00;
+               server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
+       } else {
+               server->max_rw = 0;/* do not need to use raw anyway */
+               server->capabilities = CAP_MPX_MODE;
+       }
+       tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
+       if (tmp == -1) {
+               /* OS/2 often does not set timezone therefore
+                * we must use server time to calc time zone.
+                * Could deviate slightly from the right zone.
+                * Smallest defined timezone difference is 15 minutes
+                * (i.e. Nepal).  Rounding up/down is done to match
+                * this requirement.
+                */
+               int val, seconds, remain, result;
+               struct timespec ts, utc;
+               utc = CURRENT_TIME;
+               ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
+                                   rsp->SrvTime.Time, 0);
+               cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
+                        (int)ts.tv_sec, (int)utc.tv_sec,
+                        (int)(utc.tv_sec - ts.tv_sec));
+               val = (int)(utc.tv_sec - ts.tv_sec);
+               seconds = abs(val);
+               result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
+               remain = seconds % MIN_TZ_ADJ;
+               if (remain >= (MIN_TZ_ADJ / 2))
+                       result += MIN_TZ_ADJ;
+               if (val < 0)
+                       result = -result;
+               server->timeAdj = result;
+       } else {
+               server->timeAdj = (int)tmp;
+               server->timeAdj *= 60; /* also in seconds */
+       }
+       cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
+
+
+       /* BB get server time for time conversions and add
+       code to use it and timezone since this is not UTC */
+
+       if (rsp->EncryptionKeyLength ==
+                       cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
+               memcpy(server->cryptkey, rsp->EncryptionKey,
+                       CIFS_CRYPTO_KEY_SIZE);
+       } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
+               return -EIO; /* need cryptkey unless plain text */
+       }
+
+       cifs_dbg(FYI, "LANMAN negotiated\n");
+       return 0;
+}
+#else
+static inline int
+decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
+{
+       cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
+       return -EOPNOTSUPP;
+}
+#endif
+
+static bool
+should_set_ext_sec_flag(enum securityEnum sectype)
+{
+       switch (sectype) {
+       case RawNTLMSSP:
+       case Kerberos:
+               return true;
+       case Unspecified:
+               if (global_secflags &
+                   (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
+                       return true;
+               /* Fallthrough */
+       default:
+               return false;
+       }
+}
+
 int
 CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
 {
@@ -375,41 +554,24 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
        int rc = 0;
        int bytes_returned;
        int i;
-       struct TCP_Server_Info *server;
+       struct TCP_Server_Info *server = ses->server;
        u16 count;
-       unsigned int secFlags;
 
-       if (ses->server)
-               server = ses->server;
-       else {
-               rc = -EIO;
-               return rc;
+       if (!server) {
+               WARN(1, "%s: server is NULL!\n", __func__);
+               return -EIO;
        }
+
        rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
                      (void **) &pSMB, (void **) &pSMBr);
        if (rc)
                return rc;
 
-       /* if any of auth flags (ie not sign or seal) are overriden use them */
-       if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
-               secFlags = ses->overrideSecFlg;  /* BB FIXME fix sign flags? */
-       else /* if override flags set only sign/seal OR them with global auth */
-               secFlags = global_secflags | ses->overrideSecFlg;
-
-       cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);
-
        pSMB->hdr.Mid = get_next_mid(server);
        pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
 
-       if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
-               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
-               cifs_dbg(FYI, "Kerberos only mechanism, enable extended security\n");
-               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
-               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
-               cifs_dbg(FYI, "NTLMSSP only mechanism, enable extended security\n");
+       if (should_set_ext_sec_flag(ses->sectype)) {
+               cifs_dbg(FYI, "Requesting extended security.");
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
        }
 
@@ -436,127 +598,21 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
                could not negotiate a common dialect */
                rc = -EOPNOTSUPP;
                goto neg_err_exit;
-#ifdef CONFIG_CIFS_WEAK_PW_HASH
-       } else if ((pSMBr->hdr.WordCount == 13)
-                       && ((server->dialect == LANMAN_PROT)
-                               || (server->dialect == LANMAN2_PROT))) {
-               __s16 tmp;
-               struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
-
-               if ((secFlags & CIFSSEC_MAY_LANMAN) ||
-                       (secFlags & CIFSSEC_MAY_PLNTXT))
-                       server->secType = LANMAN;
-               else {
-                       cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
-                       rc = -EOPNOTSUPP;
-                       goto neg_err_exit;
-               }
-               server->sec_mode = le16_to_cpu(rsp->SecurityMode);
-               server->maxReq = min_t(unsigned int,
-                                      le16_to_cpu(rsp->MaxMpxCount),
-                                      cifs_max_pending);
-               set_credits(server, server->maxReq);
-               server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
-               server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
-               /* even though we do not use raw we might as well set this
-               accurately, in case we ever find a need for it */
-               if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
-                       server->max_rw = 0xFF00;
-                       server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
-               } else {
-                       server->max_rw = 0;/* do not need to use raw anyway */
-                       server->capabilities = CAP_MPX_MODE;
-               }
-               tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
-               if (tmp == -1) {
-                       /* OS/2 often does not set timezone therefore
-                        * we must use server time to calc time zone.
-                        * Could deviate slightly from the right zone.
-                        * Smallest defined timezone difference is 15 minutes
-                        * (i.e. Nepal).  Rounding up/down is done to match
-                        * this requirement.
-                        */
-                       int val, seconds, remain, result;
-                       struct timespec ts, utc;
-                       utc = CURRENT_TIME;
-                       ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
-                                           rsp->SrvTime.Time, 0);
-                       cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
-                                (int)ts.tv_sec, (int)utc.tv_sec,
-                                (int)(utc.tv_sec - ts.tv_sec));
-                       val = (int)(utc.tv_sec - ts.tv_sec);
-                       seconds = abs(val);
-                       result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
-                       remain = seconds % MIN_TZ_ADJ;
-                       if (remain >= (MIN_TZ_ADJ / 2))
-                               result += MIN_TZ_ADJ;
-                       if (val < 0)
-                               result = -result;
-                       server->timeAdj = result;
-               } else {
-                       server->timeAdj = (int)tmp;
-                       server->timeAdj *= 60; /* also in seconds */
-               }
-               cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
-
-
-               /* BB get server time for time conversions and add
-               code to use it and timezone since this is not UTC */
-
-               if (rsp->EncryptionKeyLength ==
-                               cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
-                       memcpy(ses->server->cryptkey, rsp->EncryptionKey,
-                               CIFS_CRYPTO_KEY_SIZE);
-               } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
-                       rc = -EIO; /* need cryptkey unless plain text */
-                       goto neg_err_exit;
-               }
-
-               cifs_dbg(FYI, "LANMAN negotiated\n");
-               /* we will not end up setting signing flags - as no signing
-               was in LANMAN and server did not return the flags on */
-               goto signing_check;
-#else /* weak security disabled */
        } else if (pSMBr->hdr.WordCount == 13) {
-               cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
-               rc = -EOPNOTSUPP;
-#endif /* WEAK_PW_HASH */
-               goto neg_err_exit;
+               server->negflavor = CIFS_NEGFLAVOR_LANMAN;
+               rc = decode_lanman_negprot_rsp(server, pSMBr);
+               goto signing_check;
        } else if (pSMBr->hdr.WordCount != 17) {
                /* unknown wct */
                rc = -EOPNOTSUPP;
                goto neg_err_exit;
        }
-       /* else wct == 17 NTLM */
+       /* else wct == 17, NTLM or better */
+
        server->sec_mode = pSMBr->SecurityMode;
        if ((server->sec_mode & SECMODE_USER) == 0)
                cifs_dbg(FYI, "share mode security\n");
 
-       if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
-#ifdef CONFIG_CIFS_WEAK_PW_HASH
-               if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
-#endif /* CIFS_WEAK_PW_HASH */
-                       cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
-
-       if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
-               server->secType = NTLMv2;
-       else if (secFlags & CIFSSEC_MAY_NTLM)
-               server->secType = NTLM;
-       else if (secFlags & CIFSSEC_MAY_NTLMV2)
-               server->secType = NTLMv2;
-       else if (secFlags & CIFSSEC_MAY_KRB5)
-               server->secType = Kerberos;
-       else if (secFlags & CIFSSEC_MAY_NTLMSSP)
-               server->secType = RawNTLMSSP;
-       else if (secFlags & CIFSSEC_MAY_LANMAN)
-               server->secType = LANMAN;
-       else {
-               rc = -EOPNOTSUPP;
-               cifs_dbg(VFS, "Invalid security type\n");
-               goto neg_err_exit;
-       }
-       /* else ... any others ...? */
-
        /* one byte, so no need to convert this or EncryptionKeyLen from
           little endian */
        server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
@@ -569,90 +625,26 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
        server->capabilities = le32_to_cpu(pSMBr->Capabilities);
        server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
        server->timeAdj *= 60;
+
        if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+               server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
                memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
                       CIFS_CRYPTO_KEY_SIZE);
        } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
                        server->capabilities & CAP_EXTENDED_SECURITY) &&
                                (pSMBr->EncryptionKeyLength == 0)) {
-               /* decode security blob */
-               count = get_bcc(&pSMBr->hdr);
-               if (count < 16) {
-                       rc = -EIO;
-                       goto neg_err_exit;
-               }
-               spin_lock(&cifs_tcp_ses_lock);
-               if (server->srv_count > 1) {
-                       spin_unlock(&cifs_tcp_ses_lock);
-                       if (memcmp(server->server_GUID,
-                                  pSMBr->u.extended_response.
-                                  GUID, 16) != 0) {
-                               cifs_dbg(FYI, "server UID changed\n");
-                               memcpy(server->server_GUID,
-                                       pSMBr->u.extended_response.GUID,
-                                       16);
-                       }
-               } else {
-                       spin_unlock(&cifs_tcp_ses_lock);
-                       memcpy(server->server_GUID,
-                              pSMBr->u.extended_response.GUID, 16);
-               }
-
-               if (count == 16) {
-                       server->secType = RawNTLMSSP;
-               } else {
-                       rc = decode_negTokenInit(pSMBr->u.extended_response.
-                                                SecurityBlob, count - 16,
-                                                server);
-                       if (rc == 1)
-                               rc = 0;
-                       else
-                               rc = -EINVAL;
-                       if (server->secType == Kerberos) {
-                               if (!server->sec_kerberos &&
-                                               !server->sec_mskerberos)
-                                       rc = -EOPNOTSUPP;
-                       } else if (server->secType == RawNTLMSSP) {
-                               if (!server->sec_ntlmssp)
-                                       rc = -EOPNOTSUPP;
-                       } else
-                                       rc = -EOPNOTSUPP;
-               }
+               server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
+               rc = decode_ext_sec_blob(ses, pSMBr);
        } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
                rc = -EIO; /* no crypt key only if plain text pwd */
-               goto neg_err_exit;
-       } else
-               server->capabilities &= ~CAP_EXTENDED_SECURITY;
-
-#ifdef CONFIG_CIFS_WEAK_PW_HASH
-signing_check:
-#endif
-       if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
-               /* MUST_SIGN already includes the MAY_SIGN FLAG
-                  so if this is zero it means that signing is disabled */
-               cifs_dbg(FYI, "Signing disabled\n");
-               if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
-                       cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
-                       rc = -EOPNOTSUPP;
-               }
-               server->sec_mode &=
-                       ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-       } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
-               /* signing required */
-               cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags);
-               if ((server->sec_mode &
-                       (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
-                       cifs_dbg(VFS, "signing required but server lacks support\n");
-                       rc = -EOPNOTSUPP;
-               } else
-                       server->sec_mode |= SECMODE_SIGN_REQUIRED;
        } else {
-               /* signing optional ie CIFSSEC_MAY_SIGN */
-               if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
-                       server->sec_mode &=
-                               ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+               server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
+               server->capabilities &= ~CAP_EXTENDED_SECURITY;
        }
 
+signing_check:
+       if (!rc)
+               rc = cifs_enable_signing(server, ses->sign);
 neg_err_exit:
        cifs_buf_release(pSMB);
 
@@ -777,9 +769,8 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
 
        pSMB->hdr.Mid = get_next_mid(ses->server);
 
-       if (ses->server->sec_mode &
-                  (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-                       pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+       if (ses->server->sign)
+               pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        pSMB->hdr.Uid = ses->Suid;
 
@@ -1540,8 +1531,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
        switch (mid->mid_state) {
        case MID_RESPONSE_RECEIVED:
                /* result already set, check signature */
-               if (server->sec_mode &
-                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+               if (server->sign) {
                        int rc = 0;
 
                        rc = cifs_verify_signature(&rqst, server,
@@ -3940,6 +3930,7 @@ QFileInfoRetry:
        pSMB->Pad = 0;
        pSMB->Fid = netfid;
        inc_rfc1001_len(pSMB, byte_count);
+       pSMB->t2.ByteCount = cpu_to_le16(byte_count);
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -4108,6 +4099,7 @@ UnixQFileInfoRetry:
        pSMB->Pad = 0;
        pSMB->Fid = netfid;
        inc_rfc1001_len(pSMB, byte_count);
+       pSMB->t2.ByteCount = cpu_to_le16(byte_count);
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -4794,11 +4786,8 @@ getDFSRetry:
                strncpy(pSMB->RequestFileName, search_name, name_len);
        }
 
-       if (ses->server) {
-               if (ses->server->sec_mode &
-                  (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-                       pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-       }
+       if (ses->server && ses->server->sign)
+               pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        pSMB->hdr.Uid = ses->Suid;
 
index e3bc39bb9d12b224d7cda96e2e55b9babed68c0b..afcb8a1a33b7dcb273eba95331248a781b42e27a 100644 (file)
@@ -85,7 +85,7 @@ enum {
        Opt_acl, Opt_noacl, Opt_locallease,
        Opt_sign, Opt_seal, Opt_noac,
        Opt_fsc, Opt_mfsymlinks,
-       Opt_multiuser, Opt_sloppy,
+       Opt_multiuser, Opt_sloppy, Opt_nosharesock,
 
        /* Mount options which take numeric value */
        Opt_backupuid, Opt_backupgid, Opt_uid,
@@ -165,6 +165,7 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_mfsymlinks, "mfsymlinks" },
        { Opt_multiuser, "multiuser" },
        { Opt_sloppy, "sloppy" },
+       { Opt_nosharesock, "nosharesock" },
 
        { Opt_backupuid, "backupuid=%s" },
        { Opt_backupgid, "backupgid=%s" },
@@ -275,6 +276,7 @@ static const match_table_t cifs_smb_version_tokens = {
        { Smb_20, SMB20_VERSION_STRING},
        { Smb_21, SMB21_VERSION_STRING },
        { Smb_30, SMB30_VERSION_STRING },
+       { Smb_302, SMB302_VERSION_STRING },
 };
 
 static int ip_connect(struct TCP_Server_Info *server);
@@ -1024,44 +1026,48 @@ static int cifs_parse_security_flavors(char *value,
 
        substring_t args[MAX_OPT_ARGS];
 
+       /*
+        * With mount options, the last one should win. Reset any existing
+        * settings back to default.
+        */
+       vol->sectype = Unspecified;
+       vol->sign = false;
+
        switch (match_token(value, cifs_secflavor_tokens, args)) {
-       case Opt_sec_krb5:
-               vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_SIGN;
-               break;
-       case Opt_sec_krb5i:
-               vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MUST_SIGN;
-               break;
        case Opt_sec_krb5p:
-               /* vol->secFlg |= CIFSSEC_MUST_SEAL | CIFSSEC_MAY_KRB5; */
-               cifs_dbg(VFS, "Krb5 cifs privacy not supported\n");
-               break;
-       case Opt_sec_ntlmssp:
-               vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
+               cifs_dbg(VFS, "sec=krb5p is not supported!\n");
+               return 1;
+       case Opt_sec_krb5i:
+               vol->sign = true;
+               /* Fallthrough */
+       case Opt_sec_krb5:
+               vol->sectype = Kerberos;
                break;
        case Opt_sec_ntlmsspi:
-               vol->secFlg |= CIFSSEC_MAY_NTLMSSP | CIFSSEC_MUST_SIGN;
-               break;
-       case Opt_ntlm:
-               /* ntlm is default so can be turned off too */
-               vol->secFlg |= CIFSSEC_MAY_NTLM;
+               vol->sign = true;
+               /* Fallthrough */
+       case Opt_sec_ntlmssp:
+               vol->sectype = RawNTLMSSP;
                break;
        case Opt_sec_ntlmi:
-               vol->secFlg |= CIFSSEC_MAY_NTLM | CIFSSEC_MUST_SIGN;
-               break;
-       case Opt_sec_ntlmv2:
-               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+               vol->sign = true;
+               /* Fallthrough */
+       case Opt_ntlm:
+               vol->sectype = NTLM;
                break;
        case Opt_sec_ntlmv2i:
-               vol->secFlg |= CIFSSEC_MAY_NTLMV2 | CIFSSEC_MUST_SIGN;
+               vol->sign = true;
+               /* Fallthrough */
+       case Opt_sec_ntlmv2:
+               vol->sectype = NTLMv2;
                break;
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
        case Opt_sec_lanman:
-               vol->secFlg |= CIFSSEC_MAY_LANMAN;
+               vol->sectype = LANMAN;
                break;
 #endif
        case Opt_sec_none:
                vol->nullauth = 1;
-               vol->secFlg |= CIFSSEC_MAY_NTLM;
                break;
        default:
                cifs_dbg(VFS, "bad security option: %s\n", value);
@@ -1119,6 +1125,10 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
                vol->ops = &smb30_operations;
                vol->vals = &smb30_values;
                break;
+       case Smb_302:
+               vol->ops = &smb30_operations; /* currently identical with 3.0 */
+               vol->vals = &smb302_values;
+               break;
 #endif
        default:
                cifs_dbg(VFS, "Unknown vers= option specified: %s\n", value);
@@ -1424,7 +1434,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        vol->local_lease = 1;
                        break;
                case Opt_sign:
-                       vol->secFlg |= CIFSSEC_MUST_SIGN;
+                       vol->sign = true;
                        break;
                case Opt_seal:
                        /* we do not do the following in secFlags because seal
@@ -1455,6 +1465,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                case Opt_sloppy:
                        sloppy = true;
                        break;
+               case Opt_nosharesock:
+                       vol->nosharesock = true;
+                       break;
 
                /* Numeric Values */
                case Opt_backupuid:
@@ -1978,47 +1991,21 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
 static bool
 match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
 {
-       unsigned int secFlags;
-
-       if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
-               secFlags = vol->secFlg;
-       else
-               secFlags = global_secflags | vol->secFlg;
-
-       switch (server->secType) {
-       case LANMAN:
-               if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT)))
-                       return false;
-               break;
-       case NTLMv2:
-               if (!(secFlags & CIFSSEC_MAY_NTLMV2))
-                       return false;
-               break;
-       case NTLM:
-               if (!(secFlags & CIFSSEC_MAY_NTLM))
-                       return false;
-               break;
-       case Kerberos:
-               if (!(secFlags & CIFSSEC_MAY_KRB5))
-                       return false;
-               break;
-       case RawNTLMSSP:
-               if (!(secFlags & CIFSSEC_MAY_NTLMSSP))
-                       return false;
-               break;
-       default:
-               /* shouldn't happen */
+       /*
+        * The select_sectype function should either return the vol->sectype
+        * that was specified, or "Unspecified" if that sectype was not
+        * compatible with the given NEGOTIATE request.
+        */
+       if (select_sectype(server, vol->sectype) == Unspecified)
                return false;
-       }
 
-       /* now check if signing mode is acceptable */
-       if ((secFlags & CIFSSEC_MAY_SIGN) == 0 &&
-           (server->sec_mode & SECMODE_SIGN_REQUIRED))
-                       return false;
-       else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) &&
-                (server->sec_mode &
-                 (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0)
-                       return false;
+       /*
+        * Now check if signing mode is acceptable. No need to check
+        * global_secflags at this point since if MUST_SIGN is set then
+        * the server->sign had better be too.
+        */
+       if (vol->sign && !server->sign)
+               return false;
 
        return true;
 }
@@ -2027,6 +2014,9 @@ static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
 {
        struct sockaddr *addr = (struct sockaddr *)&vol->dstaddr;
 
+       if (vol->nosharesock)
+               return 0;
+
        if ((server->vals != vol->vals) || (server->ops != vol->ops))
                return 0;
 
@@ -2216,7 +2206,11 @@ out_err:
 
 static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
 {
-       switch (ses->server->secType) {
+       if (vol->sectype != Unspecified &&
+           vol->sectype != ses->sectype)
+               return 0;
+
+       switch (ses->sectype) {
        case Kerberos:
                if (!uid_eq(vol->cred_uid, ses->cred_uid))
                        return 0;
@@ -2493,7 +2487,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
        ses->cred_uid = volume_info->cred_uid;
        ses->linux_uid = volume_info->linux_uid;
 
-       ses->overrideSecFlg = volume_info->secFlg;
+       ses->sectype = volume_info->sectype;
+       ses->sign = volume_info->sign;
 
        mutex_lock(&ses->session_mutex);
        rc = cifs_negotiate_protocol(xid, ses);
@@ -3656,7 +3651,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
                   NTLMv2 password here) */
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
                if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
-                   (ses->server->secType == LANMAN))
+                   (ses->sectype == LANMAN))
                        calc_lanman_hash(tcon->password, ses->server->cryptkey,
                                         ses->server->sec_mode &
                                            SECMODE_PW_ENCRYPT ? true : false,
@@ -3674,8 +3669,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
                }
        }
 
-       if (ses->server->sec_mode &
-                       (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->server->sign)
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        if (ses->capabilities & CAP_STATUS32) {
@@ -3738,7 +3732,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
                }
                bcc_ptr += length + 1;
                bytes_left -= (length + 1);
-               strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
+               strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
 
                /* mostly informational -- no need to fail on error here */
                kfree(tcon->nativeFileSystem);
@@ -3827,7 +3821,6 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
        int rc = -ENOSYS;
        struct TCP_Server_Info *server = ses->server;
 
-       ses->flags = 0;
        ses->capabilities = server->capabilities;
        if (linuxExtEnabled == 0)
                ses->capabilities &= (~server->vals->cap_unix);
@@ -3848,6 +3841,8 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
                        server->sequence_number = 0x2;
                        server->session_estab = true;
                        ses->auth_key.response = NULL;
+                       if (server->ops->generate_signingkey)
+                               server->ops->generate_signingkey(server);
                }
                mutex_unlock(&server->srv_mutex);
 
@@ -3870,23 +3865,11 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
 static int
 cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses)
 {
-       switch (ses->server->secType) {
-       case Kerberos:
-               vol->secFlg = CIFSSEC_MUST_KRB5;
+       vol->sectype = ses->sectype;
+
+       /* krb5 is special, since we don't need username or pw */
+       if (vol->sectype == Kerberos)
                return 0;
-       case NTLMv2:
-               vol->secFlg = CIFSSEC_MUST_NTLMV2;
-               break;
-       case NTLM:
-               vol->secFlg = CIFSSEC_MUST_NTLM;
-               break;
-       case RawNTLMSSP:
-               vol->secFlg = CIFSSEC_MUST_NTLMSSP;
-               break;
-       case LANMAN:
-               vol->secFlg = CIFSSEC_MUST_LANMAN;
-               break;
-       }
 
        return cifs_set_cifscreds(vol, ses);
 }
@@ -3912,6 +3895,8 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
        vol_info->nocase = master_tcon->nocase;
        vol_info->local_lease = master_tcon->local_lease;
        vol_info->no_linux_ext = !master_tcon->unix_ext;
+       vol_info->sectype = master_tcon->ses->sectype;
+       vol_info->sign = master_tcon->ses->sign;
 
        rc = cifs_set_vol_auth(vol_info, master_tcon->ses);
        if (rc) {
index 5699b5036ed805189d367796d9a673730e773b8b..5175aebf6737953983c3da59671657660ec5641f 100644 (file)
@@ -822,8 +822,7 @@ const struct dentry_operations cifs_dentry_ops = {
 /* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
 };
 
-static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *q)
+static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
 {
        struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
        unsigned long hash;
@@ -838,12 +837,10 @@ static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
        return 0;
 }
 
-static int cifs_ci_compare(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int cifs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
-       struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls;
+       struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls;
 
        if ((name->len == len) &&
            (nls_strnicmp(codepage, name->name, str, len) == 0))
index 4d8ba8d491e5d0be27bfbf8506175f7ffd8ce476..91d8629e69a24137e48422cb2620361b4e8e47c2 100644 (file)
@@ -999,7 +999,7 @@ try_again:
                rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next);
                if (!rc)
                        goto try_again;
-               locks_delete_block(flock);
+               posix_unblock_lock(flock);
        }
        return rc;
 }
@@ -1092,6 +1092,7 @@ struct lock_to_push {
 static int
 cifs_push_posix_locks(struct cifsFileInfo *cfile)
 {
+       struct inode *inode = cfile->dentry->d_inode;
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
        struct file_lock *flock, **before;
        unsigned int count = 0, i = 0;
@@ -1102,12 +1103,12 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
 
        xid = get_xid();
 
-       lock_flocks();
-       cifs_for_each_lock(cfile->dentry->d_inode, before) {
+       spin_lock(&inode->i_lock);
+       cifs_for_each_lock(inode, before) {
                if ((*before)->fl_flags & FL_POSIX)
                        count++;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 
        INIT_LIST_HEAD(&locks_to_send);
 
@@ -1126,8 +1127,8 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
        }
 
        el = locks_to_send.next;
-       lock_flocks();
-       cifs_for_each_lock(cfile->dentry->d_inode, before) {
+       spin_lock(&inode->i_lock);
+       cifs_for_each_lock(inode, before) {
                flock = *before;
                if ((flock->fl_flags & FL_POSIX) == 0)
                        continue;
@@ -1152,7 +1153,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
                lck->offset = flock->fl_start;
                el = el->next;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 
        list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
                int stored_rc;
index 1bec014779fd8e92a679643fd1a554de68fbd96a..f7d4b2285efea06fee58d52b94e72a332412cb1a 100644 (file)
@@ -267,8 +267,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                if (treeCon->nocase)
                        buffer->Flags  |= SMBFLG_CASELESS;
                if ((treeCon->ses) && (treeCon->ses->server))
-                       if (treeCon->ses->server->sec_mode &
-                         (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+                       if (treeCon->ses->server->sign)
                                buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
        }
 
index f1213799de1a2603b1f8f1c8d42f8b0fb2cb5a64..ab877846939499c18cb454c83ed26c43dc60040c 100644 (file)
@@ -126,6 +126,22 @@ out:
        dput(dentry);
 }
 
+/*
+ * Is it possible that this directory might turn out to be a DFS referral
+ * once we go to try and use it?
+ */
+static bool
+cifs_dfs_is_possible(struct cifs_sb_info *cifs_sb)
+{
+#ifdef CONFIG_CIFS_DFS_UPCALL
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+
+       if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
+               return true;
+#endif
+       return false;
+}
+
 static void
 cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
 {
@@ -135,6 +151,19 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
        if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
                fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
                fattr->cf_dtype = DT_DIR;
+               /*
+                * Windows CIFS servers generally make DFS referrals look
+                * like directories in FIND_* responses with the reparse
+                * attribute flag also set (since DFS junctions are
+                * reparse points). We must revalidate at least these
+                * directory inodes before trying to use them (if
+                * they are DFS we will get PATH_NOT_COVERED back
+                * when queried directly and can then try to connect
+                * to the DFS target)
+                */
+               if (cifs_dfs_is_possible(cifs_sb) &&
+                   (fattr->cf_cifsattrs & ATTR_REPARSE))
+                       fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
        } else {
                fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
                fattr->cf_dtype = DT_REG;
index f230571a7ab30d1c7d809eafbfdf9cb5724c2dd3..79358e341fd2ea63cff42e6d608c58f65b5f9804 100644 (file)
@@ -138,8 +138,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
        capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
                        CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
 
-       if (ses->server->sec_mode &
-           (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->server->sign)
                pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        if (ses->capabilities & CAP_UNICODE) {
@@ -310,11 +309,10 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses,
        return;
 }
 
-static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
-                              struct cifs_ses *ses,
-                              const struct nls_table *nls_cp)
+static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
+                               struct cifs_ses *ses,
+                               const struct nls_table *nls_cp)
 {
-       int rc = 0;
        int len;
        char *bcc_ptr = *pbcc_area;
 
@@ -322,24 +320,22 @@ static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
 
        len = strnlen(bcc_ptr, bleft);
        if (len >= bleft)
-               return rc;
+               return;
 
        kfree(ses->serverOS);
 
        ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
        if (ses->serverOS)
                strncpy(ses->serverOS, bcc_ptr, len);
-       if (strncmp(ses->serverOS, "OS/2", 4) == 0) {
+       if (strncmp(ses->serverOS, "OS/2", 4) == 0)
                cifs_dbg(FYI, "OS/2 server\n");
-                       ses->flags |= CIFS_SES_OS2;
-       }
 
        bcc_ptr += len + 1;
        bleft -= len + 1;
 
        len = strnlen(bcc_ptr, bleft);
        if (len >= bleft)
-               return rc;
+               return;
 
        kfree(ses->serverNOS);
 
@@ -352,7 +348,7 @@ static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
 
        len = strnlen(bcc_ptr, bleft);
        if (len > bleft)
-               return rc;
+               return;
 
        /* No domain field in LANMAN case. Domain is
           returned by old servers in the SMB negprot response */
@@ -360,8 +356,6 @@ static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
           but thus do return domain here we could add parsing
           for it later, but it is not very important */
        cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
-
-       return rc;
 }
 
 int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
@@ -432,8 +426,7 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
        flags = NTLMSSP_NEGOTIATE_56 |  NTLMSSP_REQUEST_TARGET |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
                NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
-       if (ses->server->sec_mode &
-                       (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+       if (ses->server->sign) {
                flags |= NTLMSSP_NEGOTIATE_SIGN;
                if (!ses->server->session_estab)
                        flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
@@ -471,8 +464,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
                NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
                NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
-       if (ses->server->sec_mode &
-          (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+       if (ses->server->sign) {
                flags |= NTLMSSP_NEGOTIATE_SIGN;
                if (!ses->server->session_estab)
                        flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
@@ -558,6 +550,56 @@ setup_ntlmv2_ret:
        return rc;
 }
 
+enum securityEnum
+select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
+{
+       switch (server->negflavor) {
+       case CIFS_NEGFLAVOR_EXTENDED:
+               switch (requested) {
+               case Kerberos:
+               case RawNTLMSSP:
+                       return requested;
+               case Unspecified:
+                       if (server->sec_ntlmssp &&
+                           (global_secflags & CIFSSEC_MAY_NTLMSSP))
+                               return RawNTLMSSP;
+                       if ((server->sec_kerberos || server->sec_mskerberos) &&
+                           (global_secflags & CIFSSEC_MAY_KRB5))
+                               return Kerberos;
+                       /* Fallthrough */
+               default:
+                       return Unspecified;
+               }
+       case CIFS_NEGFLAVOR_UNENCAP:
+               switch (requested) {
+               case NTLM:
+               case NTLMv2:
+                       return requested;
+               case Unspecified:
+                       if (global_secflags & CIFSSEC_MAY_NTLMV2)
+                               return NTLMv2;
+                       if (global_secflags & CIFSSEC_MAY_NTLM)
+                               return NTLM;
+                       /* Fallthrough */
+               default:
+                       return Unspecified;
+               }
+       case CIFS_NEGFLAVOR_LANMAN:
+               switch (requested) {
+               case LANMAN:
+                       return requested;
+               case Unspecified:
+                       if (global_secflags & CIFSSEC_MAY_LANMAN)
+                               return LANMAN;
+                       /* Fallthrough */
+               default:
+                       return Unspecified;
+               }
+       default:
+               return Unspecified;
+       }
+}
+
 int
 CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
               const struct nls_table *nls_cp)
@@ -579,11 +621,18 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
        u16 blob_len;
        char *ntlmsspblob = NULL;
 
-       if (ses == NULL)
+       if (ses == NULL) {
+               WARN(1, "%s: ses == NULL!", __func__);
                return -EINVAL;
+       }
 
-       type = ses->server->secType;
+       type = select_sectype(ses->server, ses->sectype);
        cifs_dbg(FYI, "sess setup type %d\n", type);
+       if (type == Unspecified) {
+               cifs_dbg(VFS, "Unable to select appropriate authentication method!");
+               return -EINVAL;
+       }
+
        if (type == RawNTLMSSP) {
                /* if memory allocation is successful, caller of this function
                 * frees it.
@@ -643,8 +692,6 @@ ssetup_ntlmssp_authenticate:
        }
        bcc_ptr = str_area;
 
-       ses->flags &= ~CIFS_SES_LANMAN;
-
        iov[1].iov_base = NULL;
        iov[1].iov_len = 0;
 
@@ -668,7 +715,6 @@ ssetup_ntlmssp_authenticate:
                                 ses->server->sec_mode & SECMODE_PW_ENCRYPT ?
                                        true : false, lnm_session_key);
 
-               ses->flags |= CIFS_SES_LANMAN;
                memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE);
                bcc_ptr += CIFS_AUTH_RESP_SIZE;
 
@@ -938,8 +984,7 @@ ssetup_ntlmssp_authenticate:
                }
                decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp);
        } else {
-               rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining,
-                                        ses, nls_cp);
+               decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp);
        }
 
 ssetup_exit:
index 3efdb9d5c0b8a704789070f1e0aedfaffcb9ec39..e813f04511d8875dfa81b5a472cea2a932a417cd 100644 (file)
@@ -449,8 +449,7 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
         * WRITEX header, not including the 4 byte RFC1001 length.
         */
        if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
-           (!(server->capabilities & CAP_UNIX) &&
-            (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
+           (!(server->capabilities & CAP_UNIX) && server->sign))
                wsize = min_t(unsigned int, wsize,
                                server->maxBuf - sizeof(WRITE_REQ) + 4);
 
@@ -765,20 +764,14 @@ smb_set_file_info(struct inode *inode, const char *full_path,
        }
        tcon = tlink_tcon(tlink);
 
-       /*
-        * NT4 apparently returns success on this call, but it doesn't really
-        * work.
-        */
-       if (!(tcon->ses->flags & CIFS_SES_NT4)) {
-               rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf,
-                                       cifs_sb->local_nls,
+       rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls,
                                        cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if (rc == 0) {
-                       cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
-                       goto out;
-               } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
-                       goto out;
+       if (rc == 0) {
+               cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+               goto out;
+       } else if (rc != -EOPNOTSUPP && rc != -EINVAL) {
+               goto out;
        }
 
        cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n");
@@ -964,4 +957,6 @@ struct smb_version_values smb1_values = {
        .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
        .cap_large_files = CAP_LARGE_FILES,
        .oplock_read = OPLOCK_READ,
+       .signing_enabled = SECMODE_SIGN_ENABLED,
+       .signing_required = SECMODE_SIGN_REQUIRED,
 };
index 7c0e2143e775e04f183ccad271de61e73bc2edf3..c38350851b0883cd6074b04f5aa36398b2528e3c 100644 (file)
@@ -54,5 +54,7 @@
 #define SMB2_SIGNATURE_SIZE (16)
 #define SMB2_NTLMV2_SESSKEY_SIZE (16)
 #define SMB2_HMACSHA256_SIZE (32)
+#define SMB2_CMACAES_SIZE (16)
+#define SMB3_SIGNKEY_SIZE (16)
 
 #endif /* _SMB2_GLOB_H */
index 10383d8c015b12c4aa7bd936972e58bca97a648b..b0c43345cd981c082e3de5965e647a5432197605 100644 (file)
@@ -266,6 +266,10 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
                  ((struct smb2_query_directory_rsp *)hdr)->OutputBufferLength);
                break;
        case SMB2_IOCTL:
+               *off = le32_to_cpu(
+                 ((struct smb2_ioctl_rsp *)hdr)->OutputOffset);
+               *len = le32_to_cpu(((struct smb2_ioctl_rsp *)hdr)->OutputCount);
+               break;
        case SMB2_CHANGE_NOTIFY:
        default:
                /* BB FIXME for unimplemented cases above */
index f2e76f3b0c6166aeb345d5a02a0f4bdde5b84731..6d15cab95b9908baf0509bceef86fbeb79c93ebd 100644 (file)
@@ -280,6 +280,25 @@ smb2_clear_stats(struct cifs_tcon *tcon)
 #endif
 }
 
+static void
+smb2_dump_share_caps(struct seq_file *m, struct cifs_tcon *tcon)
+{
+       seq_puts(m, "\n\tShare Capabilities:");
+       if (tcon->capabilities & SMB2_SHARE_CAP_DFS)
+               seq_puts(m, " DFS,");
+       if (tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY)
+               seq_puts(m, " CONTINUOUS AVAILABILITY,");
+       if (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT)
+               seq_puts(m, " SCALEOUT,");
+       if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER)
+               seq_puts(m, " CLUSTER,");
+       if (tcon->capabilities & SMB2_SHARE_CAP_ASYMMETRIC)
+               seq_puts(m, " ASYMMETRIC,");
+       if (tcon->capabilities == 0)
+               seq_puts(m, " None");
+       seq_printf(m, "\tShare Flags: 0x%x", tcon->share_flags);
+}
+
 static void
 smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
 {
@@ -292,7 +311,6 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
        seq_printf(m, "\nSessionSetups: %d sent %d failed",
                   atomic_read(&sent[SMB2_SESSION_SETUP_HE]),
                   atomic_read(&failed[SMB2_SESSION_SETUP_HE]));
-#define SMB2LOGOFF             0x0002 /* trivial request/resp */
        seq_printf(m, "\nLogoffs: %d sent %d failed",
                   atomic_read(&sent[SMB2_LOGOFF_HE]),
                   atomic_read(&failed[SMB2_LOGOFF_HE]));
@@ -645,6 +663,7 @@ struct smb_version_operations smb30_operations = {
        .dump_detail = smb2_dump_detail,
        .clear_stats = smb2_clear_stats,
        .print_stats = smb2_print_stats,
+       .dump_share_caps = smb2_dump_share_caps,
        .is_oplock_break = smb2_is_valid_oplock_break,
        .need_neg = smb2_need_neg,
        .negotiate = smb2_negotiate,
@@ -690,6 +709,7 @@ struct smb_version_operations smb30_operations = {
        .get_lease_key = smb2_get_lease_key,
        .set_lease_key = smb2_set_lease_key,
        .new_lease_key = smb2_new_lease_key,
+       .generate_signingkey = generate_smb3signingkey,
        .calc_signature = smb3_calc_signature,
 };
 
@@ -709,6 +729,8 @@ struct smb_version_values smb20_values = {
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
        .oplock_read = SMB2_OPLOCK_LEVEL_II,
+       .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
 };
 
 struct smb_version_values smb21_values = {
@@ -727,6 +749,8 @@ struct smb_version_values smb21_values = {
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
        .oplock_read = SMB2_OPLOCK_LEVEL_II,
+       .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
 };
 
 struct smb_version_values smb30_values = {
@@ -745,4 +769,26 @@ struct smb_version_values smb30_values = {
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
        .oplock_read = SMB2_OPLOCK_LEVEL_II,
+       .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
+};
+
+struct smb_version_values smb302_values = {
+       .version_string = SMB302_VERSION_STRING,
+       .protocol_id = SMB302_PROT_ID,
+       .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU,
+       .large_lock_type = 0,
+       .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
+       .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
+       .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
+       .header_size = sizeof(struct smb2_hdr),
+       .max_header_size = MAX_SMB2_HDR_SIZE,
+       .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
+       .lock_cmd = SMB2_LOCK,
+       .cap_unix = 0,
+       .cap_nt_find = SMB2_NT_FIND,
+       .cap_large_files = SMB2_LARGE_FILES,
+       .oplock_read = SMB2_OPLOCK_LEVEL_II,
+       .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
 };
index 2b95ce2b54e80c5a2f60c84b7029e43270b524f6..2b312e4eeaa6c281192c622bc3d54e0327077626 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/smb2pdu.c
  *
- *   Copyright (C) International Business Machines  Corp., 2009, 2012
+ *   Copyright (C) International Business Machines  Corp., 2009, 2013
  *                 Etersoft, 2012
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *              Pavel Shilovsky (pshilovsky@samba.org) 2012
@@ -108,19 +108,33 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
        if (!tcon)
                goto out;
 
+       /* BB FIXME when we do write > 64K add +1 for every 64K in req or rsp */
+       /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */
+       /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */
+       if ((tcon->ses) &&
+           (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
+               hdr->CreditCharge = cpu_to_le16(1);
+       /* else CreditCharge MBZ */
+
        hdr->TreeId = tcon->tid;
        /* Uid is not converted */
        if (tcon->ses)
                hdr->SessionId = tcon->ses->Suid;
-       /* BB check following DFS flags BB */
-       /* BB do we have to add check for SHI1005_FLAGS_DFS_ROOT too? */
-       if (tcon->share_flags & SHI1005_FLAGS_DFS)
-               hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS;
-       /* BB how does SMB2 do case sensitive? */
-       /* if (tcon->nocase)
-               hdr->Flags |= SMBFLG_CASELESS; */
-       if (tcon->ses && tcon->ses->server &&
-           (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED))
+
+       /*
+        * If we would set SMB2_FLAGS_DFS_OPERATIONS on open we also would have
+        * to pass the path on the Open SMB prefixed by \\server\share.
+        * Not sure when we would need to do the augmented path (if ever) and
+        * setting this flag breaks the SMB2 open operation since it is
+        * illegal to send an empty path name (without \\server\share prefix)
+        * when the DFS flag is set in the SMB open header. We could
+        * consider setting the flag on all operations other than open
+        * but it is safer to net set it for now.
+        */
+/*     if (tcon->share_flags & SHI1005_FLAGS_DFS)
+               hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
+
+       if (tcon->ses && tcon->ses->server && tcon->ses->server->sign)
                hdr->Flags |= SMB2_FLAGS_SIGNED;
 out:
        pdu->StructureSize2 = cpu_to_le16(parmsize);
@@ -328,34 +342,22 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        struct kvec iov[1];
        int rc = 0;
        int resp_buftype;
-       struct TCP_Server_Info *server;
-       unsigned int sec_flags;
-       u16 temp = 0;
+       struct TCP_Server_Info *server = ses->server;
        int blob_offset, blob_length;
        char *security_blob;
        int flags = CIFS_NEG_OP;
 
        cifs_dbg(FYI, "Negotiate protocol\n");
 
-       if (ses->server)
-               server = ses->server;
-       else {
-               rc = -EIO;
-               return rc;
+       if (!server) {
+               WARN(1, "%s: server is NULL!\n", __func__);
+               return -EIO;
        }
 
        rc = small_smb2_init(SMB2_NEGOTIATE, NULL, (void **) &req);
        if (rc)
                return rc;
 
-       /* if any of auth flags (ie not sign or seal) are overriden use them */
-       if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
-               sec_flags = ses->overrideSecFlg;  /* BB FIXME fix sign flags?*/
-       else /* if override flags set only sign/seal OR them with global auth */
-               sec_flags = global_secflags | ses->overrideSecFlg;
-
-       cifs_dbg(FYI, "sec_flags 0x%x\n", sec_flags);
-
        req->hdr.SessionId = 0;
 
        req->Dialects[0] = cpu_to_le16(ses->server->vals->protocol_id);
@@ -364,12 +366,12 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        inc_rfc1001_len(req, 2);
 
        /* only one of SMB2 signing flags may be set in SMB2 request */
-       if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN)
-               temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
-       else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */
-               temp = SMB2_NEGOTIATE_SIGNING_ENABLED;
-
-       req->SecurityMode = cpu_to_le16(temp);
+       if (ses->sign)
+               req->SecurityMode = cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED);
+       else if (global_secflags & CIFSSEC_MAY_SIGN)
+               req->SecurityMode = cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED);
+       else
+               req->SecurityMode = 0;
 
        req->Capabilities = cpu_to_le32(ses->server->vals->req_capabilities);
 
@@ -399,6 +401,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
                cifs_dbg(FYI, "negotiated smb2.1 dialect\n");
        else if (rsp->DialectRevision == cpu_to_le16(SMB30_PROT_ID))
                cifs_dbg(FYI, "negotiated smb3.0 dialect\n");
+       else if (rsp->DialectRevision == cpu_to_le16(SMB302_PROT_ID))
+               cifs_dbg(FYI, "negotiated smb3.02 dialect\n");
        else {
                cifs_dbg(VFS, "Illegal dialect returned by server %d\n",
                         le16_to_cpu(rsp->DialectRevision));
@@ -407,6 +411,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        }
        server->dialect = le16_to_cpu(rsp->DialectRevision);
 
+       /* SMB2 only has an extended negflavor */
+       server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
        server->maxBuf = le32_to_cpu(rsp->MaxTransactSize);
        server->max_read = le32_to_cpu(rsp->MaxReadSize);
        server->max_write = le32_to_cpu(rsp->MaxWriteSize);
@@ -418,44 +424,22 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
 
        security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
                                               &rsp->hdr);
-       if (blob_length == 0) {
-               cifs_dbg(VFS, "missing security blob on negprot\n");
-               rc = -EIO;
-               goto neg_exit;
-       }
-
-       cifs_dbg(FYI, "sec_flags 0x%x\n", sec_flags);
-       if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
-               cifs_dbg(FYI, "Signing required\n");
-               if (!(server->sec_mode & (SMB2_NEGOTIATE_SIGNING_REQUIRED |
-                     SMB2_NEGOTIATE_SIGNING_ENABLED))) {
-                       cifs_dbg(VFS, "signing required but server lacks support\n");
-                       rc = -EOPNOTSUPP;
-                       goto neg_exit;
-               }
-               server->sec_mode |= SECMODE_SIGN_REQUIRED;
-       } else if (sec_flags & CIFSSEC_MAY_SIGN) {
-               cifs_dbg(FYI, "Signing optional\n");
-               if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
-                       cifs_dbg(FYI, "Server requires signing\n");
-                       server->sec_mode |= SECMODE_SIGN_REQUIRED;
-               } else {
-                       server->sec_mode &=
-                               ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-               }
-       } else {
-               cifs_dbg(FYI, "Signing disabled\n");
-               if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
-                       cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
-                       rc = -EOPNOTSUPP;
-                       goto neg_exit;
-               }
-               server->sec_mode &=
-                       ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-       }
+       /*
+        * See MS-SMB2 section 2.2.4: if no blob, client picks default which
+        * for us will be
+        *      ses->sectype = RawNTLMSSP;
+        * but for time being this is our only auth choice so doesn't matter.
+        * We just found a server which sets blob length to zero expecting raw.
+        */
+       if (blob_length == 0)
+               cifs_dbg(FYI, "missing security blob on negprot\n");
 
+       rc = cifs_enable_signing(server, ses->sign);
 #ifdef CONFIG_SMB2_ASN1  /* BB REMOVEME when updated asn1.c ready */
-       rc = decode_neg_token_init(security_blob, blob_length,
+       if (rc)
+               goto neg_exit;
+       if (blob_length)
+               rc = decode_neg_token_init(security_blob, blob_length,
                                   &server->sec_type);
        if (rc == 1)
                rc = 0;
@@ -480,9 +464,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
        int rc = 0;
        int resp_buftype;
        __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
-       struct TCP_Server_Info *server;
-       unsigned int sec_flags;
-       u8 temp = 0;
+       struct TCP_Server_Info *server = ses->server;
        u16 blob_length = 0;
        char *security_blob;
        char *ntlmssp_blob = NULL;
@@ -490,11 +472,9 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
 
        cifs_dbg(FYI, "Session Setup\n");
 
-       if (ses->server)
-               server = ses->server;
-       else {
-               rc = -EIO;
-               return rc;
+       if (!server) {
+               WARN(1, "%s: server is NULL!\n", __func__);
+               return -EIO;
        }
 
        /*
@@ -505,7 +485,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
        if (!ses->ntlmssp)
                return -ENOMEM;
 
-       ses->server->secType = RawNTLMSSP;
+       /* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */
+       ses->sectype = RawNTLMSSP;
 
 ssetup_ntlmssp_authenticate:
        if (phase == NtLmChallenge)
@@ -515,28 +496,19 @@ ssetup_ntlmssp_authenticate:
        if (rc)
                return rc;
 
-       /* if any of auth flags (ie not sign or seal) are overriden use them */
-       if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
-               sec_flags = ses->overrideSecFlg;  /* BB FIXME fix sign flags?*/
-       else /* if override flags set only sign/seal OR them with global auth */
-               sec_flags = global_secflags | ses->overrideSecFlg;
-
-       cifs_dbg(FYI, "sec_flags 0x%x\n", sec_flags);
-
        req->hdr.SessionId = 0; /* First session, not a reauthenticate */
        req->VcNumber = 0; /* MBZ */
        /* to enable echos and oplocks */
        req->hdr.CreditRequest = cpu_to_le16(3);
 
        /* only one of SMB2 signing flags may be set in SMB2 request */
-       if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN)
-               temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
-       else if (ses->server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED)
-               temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
-       else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */
-               temp = SMB2_NEGOTIATE_SIGNING_ENABLED;
-
-       req->SecurityMode = temp;
+       if (server->sign)
+               req->SecurityMode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+       else if (global_secflags & CIFSSEC_MAY_SIGN) /* one flag unlike MUST_ */
+               req->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+       else
+               req->SecurityMode = 0;
+
        req->Capabilities = 0;
        req->Channel = 0; /* MBZ */
 
@@ -679,7 +651,7 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
 
         /* since no tcon, smb2_init can not do this, so do here */
        req->hdr.SessionId = ses->Suid;
-       if (server->sec_mode & SECMODE_SIGN_REQUIRED)
+       if (server->sign)
                req->hdr.Flags |= SMB2_FLAGS_SIGNED;
 
        rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0);
@@ -788,11 +760,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        }
 
        tcon->share_flags = le32_to_cpu(rsp->ShareFlags);
+       tcon->capabilities = rsp->Capabilities; /* we keep caps little endian */
        tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess);
        tcon->tidStatus = CifsGood;
        tcon->need_reconnect = false;
        tcon->tid = rsp->hdr.TreeId;
-       strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
+       strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
 
        if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
            ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
@@ -1036,6 +1009,122 @@ creat_exit:
        return rc;
 }
 
+/*
+ *     SMB2 IOCTL is used for both IOCTLs and FSCTLs
+ */
+int
+SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+          u64 volatile_fid, u32 opcode, bool is_fsctl, char *in_data,
+          u32 indatalen, char **out_data, u32 *plen /* returned data len */)
+{
+       struct smb2_ioctl_req *req;
+       struct smb2_ioctl_rsp *rsp;
+       struct TCP_Server_Info *server;
+       struct cifs_ses *ses = tcon->ses;
+       struct kvec iov[2];
+       int resp_buftype;
+       int num_iovecs;
+       int rc = 0;
+
+       cifs_dbg(FYI, "SMB2 IOCTL\n");
+
+       /* zero out returned data len, in case of error */
+       if (plen)
+               *plen = 0;
+
+       if (ses && (ses->server))
+               server = ses->server;
+       else
+               return -EIO;
+
+       rc = small_smb2_init(SMB2_IOCTL, tcon, (void **) &req);
+       if (rc)
+               return rc;
+
+       req->CtlCode = cpu_to_le32(opcode);
+       req->PersistentFileId = persistent_fid;
+       req->VolatileFileId = volatile_fid;
+
+       if (indatalen) {
+               req->InputCount = cpu_to_le32(indatalen);
+               /* do not set InputOffset if no input data */
+               req->InputOffset =
+                      cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer) - 4);
+               iov[1].iov_base = in_data;
+               iov[1].iov_len = indatalen;
+               num_iovecs = 2;
+       } else
+               num_iovecs = 1;
+
+       req->OutputOffset = 0;
+       req->OutputCount = 0; /* MBZ */
+
+       /*
+        * Could increase MaxOutputResponse, but that would require more
+        * than one credit. Windows typically sets this smaller, but for some
+        * ioctls it may be useful to allow server to send more. No point
+        * limiting what the server can send as long as fits in one credit
+        */
+       req->MaxOutputResponse = cpu_to_le32(0xFF00); /* < 64K uses 1 credit */
+
+       if (is_fsctl)
+               req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
+       else
+               req->Flags = 0;
+
+       iov[0].iov_base = (char *)req;
+       /* 4 for rfc1002 length field */
+       iov[0].iov_len = get_rfc1002_length(req) + 4;
+
+       if (indatalen)
+               inc_rfc1001_len(req, indatalen);
+
+       rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
+       rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base;
+
+       if (rc != 0) {
+               if (tcon)
+                       cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+               goto ioctl_exit;
+       }
+
+       /* check if caller wants to look at return data or just return rc */
+       if ((plen == NULL) || (out_data == NULL))
+               goto ioctl_exit;
+
+       *plen = le32_to_cpu(rsp->OutputCount);
+
+       /* We check for obvious errors in the output buffer length and offset */
+       if (*plen == 0)
+               goto ioctl_exit; /* server returned no data */
+       else if (*plen > 0xFF00) {
+               cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen);
+               *plen = 0;
+               rc = -EIO;
+               goto ioctl_exit;
+       }
+
+       if (get_rfc1002_length(rsp) < le32_to_cpu(rsp->OutputOffset) + *plen) {
+               cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen,
+                       le32_to_cpu(rsp->OutputOffset));
+               *plen = 0;
+               rc = -EIO;
+               goto ioctl_exit;
+       }
+
+       *out_data = kmalloc(*plen, GFP_KERNEL);
+       if (*out_data == NULL) {
+               rc = -ENOMEM;
+               goto ioctl_exit;
+       }
+
+       memcpy(*out_data, rsp->hdr.ProtocolId + le32_to_cpu(rsp->OutputOffset),
+              *plen);
+ioctl_exit:
+       free_rsp_buf(resp_buftype, rsp);
+       return rc;
+}
+
 int
 SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
           u64 persistent_fid, u64 volatile_fid)
@@ -1384,8 +1473,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
        case MID_RESPONSE_RECEIVED:
                credits_received = le16_to_cpu(buf->CreditRequest);
                /* result already set, check signature */
-               if (server->sec_mode &
-                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+               if (server->sign) {
                        int rc;
 
                        rc = smb2_verify_signature(&rqst, server);
index 4cb4ced258cb333d326e9fc5ccd353313ec0c8d4..f31043b26bd3226ac4ea309d1c29c3ca3f64df2b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/smb2pdu.h
  *
- *   Copyright (c) International Business Machines  Corp., 2009, 2010
+ *   Copyright (c) International Business Machines  Corp., 2009, 2013
  *                 Etersoft, 2012
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *              Pavel Shilovsky (pshilovsky@samba.org) 2012
@@ -170,6 +170,7 @@ struct smb2_negotiate_req {
 #define SMB20_PROT_ID 0x0202
 #define SMB21_PROT_ID 0x0210
 #define SMB30_PROT_ID 0x0300
+#define SMB302_PROT_ID 0x0302
 #define BAD_PROT_ID   0xFFFF
 
 /* SecurityMode flags */
@@ -283,10 +284,17 @@ struct smb2_tree_connect_rsp {
 #define SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING          0x00000400
 #define SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM      0x00000800
 #define SHI1005_FLAGS_FORCE_LEVELII_OPLOCK             0x00001000
-#define SHI1005_FLAGS_ENABLE_HASH                      0x00002000
+#define SHI1005_FLAGS_ENABLE_HASH_V1                   0x00002000
+#define SHI1005_FLAGS_ENABLE_HASH_V2                   0x00004000
+#define SHI1005_FLAGS_ENCRYPT_DATA                     0x00008000
+#define SHI1005_FLAGS_ALL                              0x0000FF33
 
 /* Possible share capabilities */
-#define SMB2_SHARE_CAP_DFS     cpu_to_le32(0x00000008)
+#define SMB2_SHARE_CAP_DFS     cpu_to_le32(0x00000008) /* all dialects */
+#define SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY cpu_to_le32(0x00000010) /* 3.0 */
+#define SMB2_SHARE_CAP_SCALEOUT        cpu_to_le32(0x00000020) /* 3.0 */
+#define SMB2_SHARE_CAP_CLUSTER cpu_to_le32(0x00000040) /* 3.0 */
+#define SMB2_SHARE_CAP_ASYMMETRIC cpu_to_le32(0x00000080) /* 3.02 */
 
 struct smb2_tree_disconnect_req {
        struct smb2_hdr hdr;
@@ -477,6 +485,75 @@ struct create_lease {
        struct lease_context lcontext;
 } __packed;
 
+/* this goes in the ioctl buffer when doing a copychunk request */
+struct copychunk_ioctl {
+       char SourceKey[24];
+       __le32 ChunkCount; /* we are only sending 1 */
+       __le32 Reserved;
+       /* array will only be one chunk long for us */
+       __le64 SourceOffset;
+       __le64 TargetOffset;
+       __le32 Length; /* how many bytes to copy */
+       __u32 Reserved2;
+} __packed;
+
+/* Response and Request are the same format */
+struct validate_negotiate_info {
+       __le32 Capabilities;
+       __u8   Guid[SMB2_CLIENT_GUID_SIZE];
+       __le16 SecurityMode;
+       __le16 DialectCount;
+       __le16 Dialect[1];
+} __packed;
+
+#define RSS_CAPABLE    0x00000001
+#define RDMA_CAPABLE   0x00000002
+
+struct network_interface_info_ioctl_rsp {
+       __le32 Next; /* next interface. zero if this is last one */
+       __le32 IfIndex;
+       __le32 Capability; /* RSS or RDMA Capable */
+       __le32 Reserved;
+       __le64 LinkSpeed;
+       char    SockAddr_Storage[128];
+} __packed;
+
+#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
+
+struct smb2_ioctl_req {
+       struct smb2_hdr hdr;
+       __le16 StructureSize;   /* Must be 57 */
+       __u16 Reserved;
+       __le32 CtlCode;
+       __u64  PersistentFileId; /* opaque endianness */
+       __u64  VolatileFileId; /* opaque endianness */
+       __le32 InputOffset;
+       __le32 InputCount;
+       __le32 MaxInputResponse;
+       __le32 OutputOffset;
+       __le32 OutputCount;
+       __le32 MaxOutputResponse;
+       __le32 Flags;
+       __u32  Reserved2;
+       char   Buffer[0];
+} __packed;
+
+struct smb2_ioctl_rsp {
+       struct smb2_hdr hdr;
+       __le16 StructureSize;   /* Must be 57 */
+       __u16 Reserved;
+       __le32 CtlCode;
+       __u64  PersistentFileId; /* opaque endianness */
+       __u64  VolatileFileId; /* opaque endianness */
+       __le32 InputOffset;
+       __le32 InputCount;
+       __le32 OutputOffset;
+       __le32 OutputCount;
+       __le32 Flags;
+       __u32  Reserved2;
+       /* char * buffer[] */
+} __packed;
+
 /* Currently defined values for close flags */
 #define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB       cpu_to_le16(0x0001)
 struct smb2_close_req {
@@ -517,17 +594,25 @@ struct smb2_flush_rsp {
        __le16 Reserved;
 } __packed;
 
+/* For read request Flags field below, following flag is defined for SMB3.02 */
+#define SMB2_READFLAG_READ_UNBUFFERED  0x01
+
+/* Channel field for read and write: exactly one of following flags can be set*/
+#define SMB2_CHANNEL_NONE              0x00000000
+#define SMB2_CHANNEL_RDMA_V1           0x00000001 /* SMB3 or later */
+#define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000001 /* SMB3.02 or later */
+
 struct smb2_read_req {
        struct smb2_hdr hdr;
        __le16 StructureSize; /* Must be 49 */
        __u8   Padding; /* offset from start of SMB2 header to place read */
-       __u8   Reserved;
+       __u8   Flags; /* MBZ unless SMB3.02 or later */
        __le32 Length;
        __le64 Offset;
        __u64  PersistentFileId; /* opaque endianness */
        __u64  VolatileFileId; /* opaque endianness */
        __le32 MinimumCount;
-       __le32 Channel; /* Reserved MBZ */
+       __le32 Channel; /* MBZ except for SMB3 or later */
        __le32 RemainingBytes;
        __le16 ReadChannelInfoOffset; /* Reserved MBZ */
        __le16 ReadChannelInfoLength; /* Reserved MBZ */
@@ -545,8 +630,9 @@ struct smb2_read_rsp {
        __u8   Buffer[1];
 } __packed;
 
-/* For write request Flags field below the following flag is defined: */
-#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+/* For write request Flags field below the following flags are defined: */
+#define SMB2_WRITEFLAG_WRITE_THROUGH   0x00000001      /* SMB2.1 or later */
+#define SMB2_WRITEFLAG_WRITE_UNBUFFERED        0x00000002      /* SMB3.02 or later */
 
 struct smb2_write_req {
        struct smb2_hdr hdr;
index 2aa3535e38ced630c3c6e7716ff3540769e46873..d4e1eb807457d440f0d75c278fa789dcd4dc5732 100644 (file)
@@ -111,6 +111,10 @@ extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
                     __u32 desired_access, __u32 create_disposition,
                     __u32 file_attributes, __u32 create_options,
                     __u8 *oplock, struct smb2_file_all_info *buf);
+extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
+                    u64 persistent_fid, u64 volatile_fid, u32 opcode,
+                    bool is_fsctl, char *in_data, u32 indatalen,
+                    char **out_data, u32 *plen /* returned data len */);
 extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
                      u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
index 01f0ac8007809a9514ac72ae34f066914168afb0..09b4fbaadeb6d5c9c79f835f6763b66028e4466d 100644 (file)
@@ -116,11 +116,155 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        return rc;
 }
 
+void
+generate_smb3signingkey(struct TCP_Server_Info *server)
+{
+       unsigned char zero = 0x0;
+       __u8 i[4] = {0, 0, 0, 1};
+       __u8 L[4] = {0, 0, 0, 128};
+       int rc = 0;
+       unsigned char prfhash[SMB2_HMACSHA256_SIZE];
+       unsigned char *hashptr = prfhash;
+
+       memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
+       memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
+
+       rc = crypto_shash_setkey(server->secmech.hmacsha256,
+               server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not set with session key\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+                               i, 4);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not update with n\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+                               "SMB2AESCMAC", 12);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not update with label\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+                               &zero, 1);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not update with zero\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+                               "SmbSign", 8);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not update with context\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+                               L, 4);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not update with L\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
+                               hashptr);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       memcpy(server->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE);
+
+smb3signkey_ret:
+       return;
+}
+
 int
 smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
-       cifs_dbg(FYI, "smb3 signatures not supported yet\n");
-       return -EOPNOTSUPP;
+       int i, rc;
+       unsigned char smb3_signature[SMB2_CMACAES_SIZE];
+       unsigned char *sigptr = smb3_signature;
+       struct kvec *iov = rqst->rq_iov;
+       int n_vec = rqst->rq_nvec;
+       struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+
+       memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
+       memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
+
+       rc = crypto_shash_setkey(server->secmech.cmacaes,
+               server->smb3signingkey, SMB2_CMACAES_SIZE);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
+               return rc;
+       }
+
+       rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
+               return rc;
+       }
+
+       for (i = 0; i < n_vec; i++) {
+               if (iov[i].iov_len == 0)
+                       continue;
+               if (iov[i].iov_base == NULL) {
+                       cifs_dbg(VFS, "null iovec entry");
+                       return -EIO;
+               }
+               /*
+                * The first entry includes a length field (which does not get
+                * signed that occupies the first 4 bytes before the header).
+                */
+               if (i == 0) {
+                       if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
+                               break; /* nothing to sign or corrupt header */
+                       rc =
+                       crypto_shash_update(
+                               &server->secmech.sdesccmacaes->shash,
+                               iov[i].iov_base + 4, iov[i].iov_len - 4);
+               } else {
+                       rc =
+                       crypto_shash_update(
+                               &server->secmech.sdesccmacaes->shash,
+                               iov[i].iov_base, iov[i].iov_len);
+               }
+               if (rc) {
+                       cifs_dbg(VFS, "%s: Couldn't update cmac aes with payload\n",
+                                                       __func__);
+                       return rc;
+               }
+       }
+
+       /* now hash over the rq_pages array */
+       for (i = 0; i < rqst->rq_npages; i++) {
+               struct kvec p_iov;
+
+               cifs_rqst_page_to_kvec(rqst, i, &p_iov);
+               crypto_shash_update(&server->secmech.sdesccmacaes->shash,
+                                       p_iov.iov_base, p_iov.iov_len);
+               kunmap(rqst->rq_pages[i]);
+       }
+
+       rc = crypto_shash_final(&server->secmech.sdesccmacaes->shash,
+                                               sigptr);
+       if (rc)
+               cifs_dbg(VFS, "%s: Could not generate cmac aes\n", __func__);
+
+       memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+
+       return rc;
 }
 
 /* must be called with server->srv_mutex held */
@@ -275,8 +419,7 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 
        dump_smb(mid->resp_buf, min_t(u32, 80, len));
        /* convert the length into a more usable form */
-       if ((len > 24) &&
-           (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) {
+       if (len > 24 && server->sign) {
                int rc;
 
                rc = smb2_verify_signature(&rqst, server);
index 7056b891e087519d7116f015987def8bf31c1ccc..d952ee48f4dcc629a5d1e91c3470cbd2bd6d1aec 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/smbfsctl.h: SMB, CIFS, SMB2 FSCTL definitions
  *
- *   Copyright (c) International Business Machines  Corp., 2002,2009
+ *   Copyright (c) International Business Machines  Corp., 2002,2013
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@
 /* IOCTL information */
 /*
  * List of ioctl/fsctl function codes that are or could be useful in the
- * future to remote clients like cifs or SMB2 client.  There is probably
+ * future to remote clients like cifs or SMB2/SMB3 client.  This is probably
  * a slightly larger set of fsctls that NTFS local filesystem could handle,
  * including the seven below that we do not have struct definitions for.
  * Even with protocol definitions for most of these now available, we still
  * remotely.  Some of the following, such as the encryption/compression ones
  * could be invoked from tools via a specialized hook into the VFS rather
  * than via the standard vfs entry points
+ *
+ * See MS-SMB2 Section 2.2.31 (last checked June 2013, all of that list are
+ * below). Additional detail on less common ones can be found in MS-FSCC
+ * section 2.3.
  */
+#define FSCTL_DFS_GET_REFERRALS      0x00060194
+#define FSCTL_DFS_GET_REFERRALS_EX   0x000601B0
 #define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
 #define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
 #define FSCTL_REQUEST_BATCH_OPLOCK   0x00090008
 #define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */
 #define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */
 #define FSCTL_SET_DEFECT_MANAGEMENT  0x00098134 /* BB add struct */
+#define FSCTL_FILE_LEVEL_TRIM        0x00098208 /* BB add struct */
 #define FSCTL_SIS_LINK_FILES         0x0009C104
 #define FSCTL_PIPE_PEEK              0x0011400C /* BB add struct */
 #define FSCTL_PIPE_TRANSCEIVE        0x0011C017 /* BB add struct */
 /* strange that the number for this op is not sequential with previous op */
 #define FSCTL_PIPE_WAIT              0x00110018 /* BB add struct */
+/* Enumerate previous versions of a file */
+#define FSCTL_SRV_ENUMERATE_SNAPSHOTS 0x00144064
+/* Retrieve an opaque file reference for server-side data movement ie copy */
+#define FSCTL_SRV_REQUEST_RESUME_KEY 0x00140078
+#define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */
 #define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */
 #define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */
+#define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 /* BB add struct */
+/* Perform server-side data movement */
+#define FSCTL_SRV_COPYCHUNK 0x001440F2
+#define FSCTL_SRV_COPYCHUNK_WRITE 0x001480F2
+#define FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC /* BB add struct */
+#define FSCTL_SRV_READ_HASH          0x001441BB /* BB add struct */
 
 #define IO_REPARSE_TAG_MOUNT_POINT   0xA0000003
 #define IO_REPARSE_TAG_HSM           0xC0000004
 #define IO_REPARSE_TAG_SIS           0x80000007
+
+/* fsctl flags */
+/* If Flags is set to this value, the request is an FSCTL not ioctl request */
+#define SMB2_0_IOCTL_IS_FSCTL          0x00000001
+
index bfbf4700d160f8a4d54f7cc0446a35c4de8c747d..6fdcb1b4a106747779ae77ed365116256e79edec 100644 (file)
@@ -447,7 +447,7 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
 {
        int error;
 
-       error = wait_event_freezekillable(server->response_q,
+       error = wait_event_freezekillable_unsafe(server->response_q,
                                    midQ->mid_state != MID_REQUEST_SUBMITTED);
        if (error < 0)
                return -ERESTARTSYS;
@@ -463,7 +463,7 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        struct mid_q_entry *mid;
 
        /* enable signing if server requires it */
-       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (server->sign)
                hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        mid = AllocMidQEntry(hdr, server);
@@ -612,7 +612,7 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
        dump_smb(mid->resp_buf, min_t(u32, 92, len));
 
        /* convert the length into a more usable form */
-       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+       if (server->sign) {
                struct kvec iov;
                int rc = 0;
                struct smb_rqst rqst = { .rq_iov = &iov,
index 87e0ee9f4465e5b0bfc7bde48657314be18258b3..14a14808320cf1e555d8ca14fdd604590d8b723f 100644 (file)
@@ -487,13 +487,7 @@ static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
 
                /* skip null entries */
                if (vdir->d_fileno && name.len) {
-                       /* try to look up this entry in the dcache, that way
-                        * userspace doesn't have to worry about breaking
-                        * getcwd by having mismatched inode numbers for
-                        * internal volume mountpoints. */
-                       ino = find_inode_number(de, &name);
-                       if (!ino) ino = vdir->d_fileno;
-
+                       ino = vdir->d_fileno;
                        type = CDT2DT(vdir->d_type);
                        if (!dir_emit(ctx, name.name, name.len, ino, type))
                                break;
index 2b6cb23dd14e99a4165af595a1f6670e002d8d3b..1d1c41f1014d9039c0a3ec217d6c6e53856760b1 100644 (file)
@@ -203,7 +203,7 @@ configfs_write_file(struct file *file, const char __user *buf, size_t count, lof
        mutex_lock(&buffer->mutex);
        len = fill_write_buffer(buffer, buf, count);
        if (len > 0)
-               len = flush_write_buffer(file->f_path.dentry, buffer, count);
+               len = flush_write_buffer(file->f_path.dentry, buffer, len);
        if (len > 0)
                *ppos += len;
        mutex_unlock(&buffer->mutex);
index dafafbafa7313e2e7ef46d05619482b2edf5645d..72f816d6cad99d4d1f81433e928d42e540295188 100644 (file)
 #include <trace/events/sched.h>
 
 int core_uses_pid;
-char core_pattern[CORENAME_MAX_SIZE] = "core";
 unsigned int core_pipe_limit;
+char core_pattern[CORENAME_MAX_SIZE] = "core";
+static int core_name_size = CORENAME_MAX_SIZE;
 
 struct core_name {
        char *corename;
        int used, size;
 };
-static atomic_t call_count = ATOMIC_INIT(1);
 
 /* The maximal length of core_pattern is also specified in sysctl.c */
 
-static int expand_corename(struct core_name *cn)
+static int expand_corename(struct core_name *cn, int size)
 {
-       char *old_corename = cn->corename;
-
-       cn->size = CORENAME_MAX_SIZE * atomic_inc_return(&call_count);
-       cn->corename = krealloc(old_corename, cn->size, GFP_KERNEL);
+       char *corename = krealloc(cn->corename, size, GFP_KERNEL);
 
-       if (!cn->corename) {
-               kfree(old_corename);
+       if (!corename)
                return -ENOMEM;
-       }
 
+       if (size > core_name_size) /* racy but harmless */
+               core_name_size = size;
+
+       cn->size = ksize(corename);
+       cn->corename = corename;
        return 0;
 }
 
+static int cn_vprintf(struct core_name *cn, const char *fmt, va_list arg)
+{
+       int free, need;
+
+again:
+       free = cn->size - cn->used;
+       need = vsnprintf(cn->corename + cn->used, free, fmt, arg);
+       if (need < free) {
+               cn->used += need;
+               return 0;
+       }
+
+       if (!expand_corename(cn, cn->size + need - free + 1))
+               goto again;
+
+       return -ENOMEM;
+}
+
 static int cn_printf(struct core_name *cn, const char *fmt, ...)
 {
-       char *cur;
-       int need;
-       int ret;
        va_list arg;
+       int ret;
 
        va_start(arg, fmt);
-       need = vsnprintf(NULL, 0, fmt, arg);
+       ret = cn_vprintf(cn, fmt, arg);
        va_end(arg);
 
-       if (likely(need < cn->size - cn->used - 1))
-               goto out_printf;
+       return ret;
+}
 
-       ret = expand_corename(cn);
-       if (ret)
-               goto expand_fail;
+static int cn_esc_printf(struct core_name *cn, const char *fmt, ...)
+{
+       int cur = cn->used;
+       va_list arg;
+       int ret;
 
-out_printf:
-       cur = cn->corename + cn->used;
        va_start(arg, fmt);
-       vsnprintf(cur, need + 1, fmt, arg);
+       ret = cn_vprintf(cn, fmt, arg);
        va_end(arg);
-       cn->used += need;
-       return 0;
 
-expand_fail:
+       for (; cur < cn->used; ++cur) {
+               if (cn->corename[cur] == '/')
+                       cn->corename[cur] = '!';
+       }
        return ret;
 }
 
-static void cn_escape(char *str)
-{
-       for (; *str; str++)
-               if (*str == '/')
-                       *str = '!';
-}
-
 static int cn_print_exe_file(struct core_name *cn)
 {
        struct file *exe_file;
@@ -115,12 +125,8 @@ static int cn_print_exe_file(struct core_name *cn)
        int ret;
 
        exe_file = get_mm_exe_file(current->mm);
-       if (!exe_file) {
-               char *commstart = cn->corename + cn->used;
-               ret = cn_printf(cn, "%s (path unknown)", current->comm);
-               cn_escape(commstart);
-               return ret;
-       }
+       if (!exe_file)
+               return cn_esc_printf(cn, "%s (path unknown)", current->comm);
 
        pathbuf = kmalloc(PATH_MAX, GFP_TEMPORARY);
        if (!pathbuf) {
@@ -134,9 +140,7 @@ static int cn_print_exe_file(struct core_name *cn)
                goto free_buf;
        }
 
-       cn_escape(path);
-
-       ret = cn_printf(cn, "%s", path);
+       ret = cn_esc_printf(cn, "%s", path);
 
 free_buf:
        kfree(pathbuf);
@@ -157,19 +161,19 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm)
        int pid_in_pattern = 0;
        int err = 0;
 
-       cn->size = CORENAME_MAX_SIZE * atomic_read(&call_count);
-       cn->corename = kmalloc(cn->size, GFP_KERNEL);
        cn->used = 0;
-
-       if (!cn->corename)
+       cn->corename = NULL;
+       if (expand_corename(cn, core_name_size))
                return -ENOMEM;
+       cn->corename[0] = '\0';
+
+       if (ispipe)
+               ++pat_ptr;
 
        /* Repeat as long as we have more pattern to process and more output
           space */
        while (*pat_ptr) {
                if (*pat_ptr != '%') {
-                       if (*pat_ptr == 0)
-                               goto out;
                        err = cn_printf(cn, "%c", *pat_ptr++);
                } else {
                        switch (*++pat_ptr) {
@@ -210,22 +214,16 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm)
                                break;
                        }
                        /* hostname */
-                       case 'h': {
-                               char *namestart = cn->corename + cn->used;
+                       case 'h':
                                down_read(&uts_sem);
-                               err = cn_printf(cn, "%s",
+                               err = cn_esc_printf(cn, "%s",
                                              utsname()->nodename);
                                up_read(&uts_sem);
-                               cn_escape(namestart);
                                break;
-                       }
                        /* executable */
-                       case 'e': {
-                               char *commstart = cn->corename + cn->used;
-                               err = cn_printf(cn, "%s", current->comm);
-                               cn_escape(commstart);
+                       case 'e':
+                               err = cn_esc_printf(cn, "%s", current->comm);
                                break;
-                       }
                        case 'E':
                                err = cn_print_exe_file(cn);
                                break;
@@ -244,6 +242,7 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm)
                        return err;
        }
 
+out:
        /* Backward compatibility with core_uses_pid:
         *
         * If core_pattern does not include a %p (as is the default)
@@ -254,7 +253,6 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm)
                if (err)
                        return err;
        }
-out:
        return ispipe;
 }
 
@@ -549,7 +547,7 @@ void do_coredump(siginfo_t *siginfo)
                if (ispipe < 0) {
                        printk(KERN_WARNING "format_corename failed\n");
                        printk(KERN_WARNING "Aborting core\n");
-                       goto fail_corename;
+                       goto fail_unlock;
                }
 
                if (cprm.limit == 1) {
@@ -584,7 +582,7 @@ void do_coredump(siginfo_t *siginfo)
                        goto fail_dropcount;
                }
 
-               helper_argv = argv_split(GFP_KERNEL, cn.corename+1, NULL);
+               helper_argv = argv_split(GFP_KERNEL, cn.corename, NULL);
                if (!helper_argv) {
                        printk(KERN_WARNING "%s failed to allocate memory\n",
                               __func__);
@@ -601,7 +599,7 @@ void do_coredump(siginfo_t *siginfo)
 
                argv_free(helper_argv);
                if (retval) {
-                       printk(KERN_INFO "Core dump to %s pipe failed\n",
+                       printk(KERN_INFO "Core dump to |%s pipe failed\n",
                               cn.corename);
                        goto close_fail;
                }
@@ -669,7 +667,6 @@ fail_dropcount:
                atomic_dec(&core_dump_count);
 fail_unlock:
        kfree(cn.corename);
-fail_corename:
        coredump_finish(mm, core_dumped);
        revert_creds(old_cred);
 fail_creds:
index 5a23073138dfe310fb076e81567bac97cd0be9b6..87bdb5329c3c90b99d67f4b5bab3ae0b347d2acf 100644 (file)
@@ -1730,7 +1730,7 @@ EXPORT_SYMBOL(d_add_ci);
  * Do the slow-case of the dentry name compare.
  *
  * Unlike the dentry_cmp() function, we need to atomically
- * load the name, length and inode information, so that the
+ * load the name and length information, so that the
  * filesystem can rely on them, and can use the 'name' and
  * 'len' information without worrying about walking off the
  * end of memory etc.
@@ -1748,22 +1748,18 @@ enum slow_d_compare {
 
 static noinline enum slow_d_compare slow_dentry_cmp(
                const struct dentry *parent,
-               struct inode *inode,
                struct dentry *dentry,
                unsigned int seq,
                const struct qstr *name)
 {
        int tlen = dentry->d_name.len;
        const char *tname = dentry->d_name.name;
-       struct inode *i = dentry->d_inode;
 
        if (read_seqcount_retry(&dentry->d_seq, seq)) {
                cpu_relax();
                return D_COMP_SEQRETRY;
        }
-       if (parent->d_op->d_compare(parent, inode,
-                               dentry, i,
-                               tlen, tname, name))
+       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
                return D_COMP_NOMATCH;
        return D_COMP_OK;
 }
@@ -1773,7 +1769,6 @@ static noinline enum slow_d_compare slow_dentry_cmp(
  * @parent: parent dentry
  * @name: qstr of name we wish to find
  * @seqp: returns d_seq value at the point where the dentry was found
- * @inode: returns dentry->d_inode when the inode was found valid.
  * Returns: dentry, or NULL
  *
  * __d_lookup_rcu is the dcache lookup function for rcu-walk name
@@ -1800,7 +1795,7 @@ static noinline enum slow_d_compare slow_dentry_cmp(
  */
 struct dentry *__d_lookup_rcu(const struct dentry *parent,
                                const struct qstr *name,
-                               unsigned *seqp, struct inode *inode)
+                               unsigned *seqp)
 {
        u64 hashlen = name->hash_len;
        const unsigned char *str = name->name;
@@ -1834,11 +1829,10 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
 seqretry:
                /*
                 * The dentry sequence count protects us from concurrent
-                * renames, and thus protects inode, parent and name fields.
+                * renames, and thus protects parent and name fields.
                 *
                 * The caller must perform a seqcount check in order
-                * to do anything useful with the returned dentry,
-                * including using the 'd_inode' pointer.
+                * to do anything useful with the returned dentry.
                 *
                 * NOTE! We do a "raw" seqcount_begin here. That means that
                 * we don't wait for the sequence count to stabilize if it
@@ -1852,12 +1846,12 @@ seqretry:
                        continue;
                if (d_unhashed(dentry))
                        continue;
-               *seqp = seq;
 
                if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
                        if (dentry->d_name.hash != hashlen_hash(hashlen))
                                continue;
-                       switch (slow_dentry_cmp(parent, inode, dentry, seq, name)) {
+                       *seqp = seq;
+                       switch (slow_dentry_cmp(parent, dentry, seq, name)) {
                        case D_COMP_OK:
                                return dentry;
                        case D_COMP_NOMATCH:
@@ -1869,6 +1863,7 @@ seqretry:
 
                if (dentry->d_name.hash_len != hashlen)
                        continue;
+               *seqp = seq;
                if (!dentry_cmp(dentry, str, hashlen_len(hashlen)))
                        return dentry;
        }
@@ -1966,9 +1961,7 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
                if (parent->d_flags & DCACHE_OP_COMPARE) {
                        int tlen = dentry->d_name.len;
                        const char *tname = dentry->d_name.name;
-                       if (parent->d_op->d_compare(parent, parent->d_inode,
-                                               dentry, dentry->d_inode,
-                                               tlen, tname, name))
+                       if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
                                goto next;
                } else {
                        if (dentry->d_name.len != len)
@@ -2005,7 +1998,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
         */
        name->hash = full_name_hash(name->name, name->len);
        if (dir->d_flags & DCACHE_OP_HASH) {
-               int err = dir->d_op->d_hash(dir, dir->d_inode, name);
+               int err = dir->d_op->d_hash(dir, name);
                if (unlikely(err < 0))
                        return ERR_PTR(err);
        }
@@ -2975,34 +2968,21 @@ rename_retry:
        goto again;
 }
 
-/**
- * find_inode_number - check for dentry with name
- * @dir: directory to check
- * @name: Name to find.
- *
- * Check whether a dentry already exists for the given name,
- * and return the inode number if it has an inode. Otherwise
- * 0 is returned.
- *
- * This routine is used to post-process directory listings for
- * filesystems using synthetic inode numbers, and is necessary
- * to keep getcwd() working.
- */
-ino_t find_inode_number(struct dentry *dir, struct qstr *name)
+void d_tmpfile(struct dentry *dentry, struct inode *inode)
 {
-       struct dentry * dentry;
-       ino_t ino = 0;
-
-       dentry = d_hash_and_lookup(dir, name);
-       if (!IS_ERR_OR_NULL(dentry)) {
-               if (dentry->d_inode)
-                       ino = dentry->d_inode->i_ino;
-               dput(dentry);
-       }
-       return ino;
+       inode_dec_link_count(inode);
+       BUG_ON(dentry->d_name.name != dentry->d_iname ||
+               !hlist_unhashed(&dentry->d_alias) ||
+               !d_unlinked(dentry));
+       spin_lock(&dentry->d_parent->d_lock);
+       spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+       dentry->d_name.len = sprintf(dentry->d_iname, "#%llu",
+                               (unsigned long long)inode->i_ino);
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&dentry->d_parent->d_lock);
+       d_instantiate(dentry, inode);
 }
-EXPORT_SYMBOL(find_inode_number);
+EXPORT_SYMBOL(d_tmpfile);
 
 static __initdata unsigned long dhash_entries;
 static int __init set_dhash_entries(char *str)
index f71ec125290db7da87355f444f7308826ee1c034..cfa109a4d5a21ac6f784f1a4e8a16b534c9e8d0d 100644 (file)
@@ -2243,12 +2243,11 @@ out:
  */
 int ecryptfs_decode_and_decrypt_filename(char **plaintext_name,
                                         size_t *plaintext_name_size,
-                                        struct dentry *ecryptfs_dir_dentry,
+                                        struct super_block *sb,
                                         const char *name, size_t name_size)
 {
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
-               &ecryptfs_superblock_to_private(
-                       ecryptfs_dir_dentry->d_sb)->mount_crypt_stat;
+               &ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
        char *decoded_name;
        size_t decoded_name_size;
        size_t packet_size;
index f622a733f7adc3ff1778e4f74790db507c61c824..df19d34a033b9521de8623bb33ff2de6c0d9361a 100644 (file)
@@ -575,7 +575,7 @@ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
                             struct inode *ecryptfs_inode);
 int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
                                         size_t *decrypted_name_size,
-                                        struct dentry *ecryptfs_dentry,
+                                        struct super_block *sb,
                                         const char *name, size_t name_size);
 int ecryptfs_fill_zeros(struct file *file, loff_t new_length);
 int ecryptfs_encrypt_and_encode_filename(
index 9aa05e08060b507f05f17a5b464fb1f695c7e3e4..24f1105fda3ab5edfccc7a748f97dd624bf6f0fb 100644 (file)
@@ -70,7 +70,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
 struct ecryptfs_getdents_callback {
        struct dir_context ctx;
        struct dir_context *caller;
-       struct dentry *dentry;
+       struct super_block *sb;
        int filldir_called;
        int entries_written;
 };
@@ -88,7 +88,7 @@ ecryptfs_filldir(void *dirent, const char *lower_name, int lower_namelen,
 
        buf->filldir_called++;
        rc = ecryptfs_decode_and_decrypt_filename(&name, &name_size,
-                                                 buf->dentry, lower_name,
+                                                 buf->sb, lower_name,
                                                  lower_namelen);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to decode and decrypt "
@@ -114,15 +114,14 @@ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx)
 {
        int rc;
        struct file *lower_file;
-       struct inode *inode;
+       struct inode *inode = file_inode(file);
        struct ecryptfs_getdents_callback buf = {
                .ctx.actor = ecryptfs_filldir,
                .caller = ctx,
-               .dentry = file->f_path.dentry
+               .sb = inode->i_sb,
        };
        lower_file = ecryptfs_file_to_lower(file);
        lower_file->f_pos = ctx->pos;
-       inode = file_inode(file);
        rc = iterate_dir(lower_file, &buf.ctx);
        ctx->pos = buf.ctx.pos;
        if (rc < 0)
index 5eab400e25903b71641d4a056254c79f3a776885..a2f2bb2c256dd24cf8a9e597cbbe7f97a290f282 100644 (file)
@@ -679,7 +679,7 @@ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
        set_fs(old_fs);
        if (rc < 0)
                goto out;
-       rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry,
+       rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry->d_sb,
                                                  lower_buf, rc);
 out:
        kfree(lower_buf);
index 141aee31884fffd06c7903b442ebbd7a03c6a704..a8766b880c0783b3adca66bac0e5f0ba76840c70 100644 (file)
@@ -45,8 +45,8 @@ static struct super_block *efivarfs_sb;
  * So we need to perform a case-sensitive match on part 1 and a
  * case-insensitive match on part 2.
  */
-static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode,
-                             const struct dentry *dentry, const struct inode *inode,
+static int efivarfs_d_compare(const struct dentry *parent,
+                             const struct dentry *dentry,
                              unsigned int len, const char *str,
                              const struct qstr *name)
 {
@@ -63,8 +63,7 @@ static int efivarfs_d_compare(const struct dentry *parent, const struct inode *p
        return strncasecmp(name->name + guid, str + guid, EFI_VARIABLE_GUID_LEN);
 }
 
-static int efivarfs_d_hash(const struct dentry *dentry,
-                          const struct inode *inode, struct qstr *qstr)
+static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
 {
        unsigned long hash = init_name_hash();
        const unsigned char *s = qstr->name;
@@ -108,7 +107,7 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
        q.name = name;
        q.len = strlen(name);
 
-       err = efivarfs_d_hash(NULL, NULL, &q);
+       err = efivarfs_d_hash(NULL, &q);
        if (err)
                return ERR_PTR(err);
 
index deecc7294a672c3fa64cf3884c4ee28f4c7f80a7..9ad17b15b454116d91eb5ca3056f5cedc945e076 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/mutex.h>
 #include <linux/anon_inodes.h>
 #include <linux/device.h>
+#include <linux/freezer.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/mman.h>
@@ -1602,7 +1603,8 @@ fetch_events:
                        }
 
                        spin_unlock_irqrestore(&ep->lock, flags);
-                       if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
+                       if (!freezable_schedule_hrtimeout_range(to, slack,
+                                                               HRTIMER_MODE_ABS))
                                timed_out = 1;
 
                        spin_lock_irqsave(&ep->lock, flags);
@@ -1975,8 +1977,8 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
                        return -EINVAL;
                if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
                        return -EFAULT;
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+               sigsaved = current->blocked;
+               set_current_blocked(&ksigmask);
        }
 
        error = sys_epoll_wait(epfd, events, maxevents, timeout);
@@ -1993,7 +1995,7 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
                               sizeof(sigsaved));
                        set_restore_sigmask();
                } else
-                       sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+                       set_current_blocked(&sigsaved);
        }
 
        return error;
@@ -2020,8 +2022,8 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
                if (copy_from_user(&csigmask, sigmask, sizeof(csigmask)))
                        return -EFAULT;
                sigset_from_compat(&ksigmask, &csigmask);
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+               sigsaved = current->blocked;
+               set_current_blocked(&ksigmask);
        }
 
        err = sys_epoll_wait(epfd, events, maxevents, timeout);
@@ -2038,7 +2040,7 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
                               sizeof(sigsaved));
                        set_restore_sigmask();
                } else
-                       sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+                       set_current_blocked(&sigsaved);
        }
 
        return err;
index ffd7a813ad3d06ee1e1de4e996c72282c24e7039..9c73def87642fc8f36624b7fa525504541a59a04 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -110,13 +110,14 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
        static const struct open_flags uselib_flags = {
                .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
                .acc_mode = MAY_READ | MAY_EXEC | MAY_OPEN,
-               .intent = LOOKUP_OPEN
+               .intent = LOOKUP_OPEN,
+               .lookup_flags = LOOKUP_FOLLOW,
        };
 
        if (IS_ERR(tmp))
                goto out;
 
-       file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
+       file = do_filp_open(AT_FDCWD, tmp, &uselib_flags);
        putname(tmp);
        error = PTR_ERR(file);
        if (IS_ERR(file))
@@ -756,10 +757,11 @@ struct file *open_exec(const char *name)
        static const struct open_flags open_exec_flags = {
                .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
                .acc_mode = MAY_EXEC | MAY_OPEN,
-               .intent = LOOKUP_OPEN
+               .intent = LOOKUP_OPEN,
+               .lookup_flags = LOOKUP_FOLLOW,
        };
 
-       file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags, LOOKUP_FOLLOW);
+       file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags);
        if (IS_ERR(file))
                goto out;
 
@@ -930,6 +932,7 @@ static int de_thread(struct task_struct *tsk)
                 * also take its birthdate (always earlier than our own).
                 */
                tsk->start_time = leader->start_time;
+               tsk->real_start_time = leader->real_start_time;
 
                BUG_ON(!same_thread_group(leader, tsk));
                BUG_ON(has_group_leader_pid(tsk));
@@ -945,9 +948,8 @@ static int de_thread(struct task_struct *tsk)
                 * Note: The old leader also uses this pid until release_task
                 *       is called.  Odd but simple and correct.
                 */
-               detach_pid(tsk, PIDTYPE_PID);
                tsk->pid = leader->pid;
-               attach_pid(tsk, PIDTYPE_PID,  task_pid(leader));
+               change_pid(tsk, PIDTYPE_PID, task_pid(leader));
                transfer_pid(leader, tsk, PIDTYPE_PGID);
                transfer_pid(leader, tsk, PIDTYPE_SID);
 
@@ -1463,7 +1465,6 @@ static int do_execve_common(const char *filename,
        struct files_struct *displaced;
        bool clear_in_exec;
        int retval;
-       const struct cred *cred = current_cred();
 
        /*
         * We move the actual failure in case of RLIMIT_NPROC excess from
@@ -1472,7 +1473,7 @@ static int do_execve_common(const char *filename,
         * whether NPROC limit is still exceeded.
         */
        if ((current->flags & PF_NPROC_EXCEEDED) &&
-           atomic_read(&cred->user->processes) > rlimit(RLIMIT_NPROC)) {
+           atomic_read(&current_user()->processes) > rlimit(RLIMIT_NPROC)) {
                retval = -EAGAIN;
                goto out_ret;
        }
index 73b0d9519836e1181b5b9227bd78ccead322a4d3..256dd5f4c1c4ade3f1ba160726ed0defabfccaf8 100644 (file)
@@ -119,6 +119,29 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode
        return ext2_add_nondir(dentry, inode);
 }
 
+static int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       struct inode *inode = ext2_new_inode(dir, mode, NULL);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+
+       inode->i_op = &ext2_file_inode_operations;
+       if (ext2_use_xip(inode->i_sb)) {
+               inode->i_mapping->a_ops = &ext2_aops_xip;
+               inode->i_fop = &ext2_xip_file_operations;
+       } else if (test_opt(inode->i_sb, NOBH)) {
+               inode->i_mapping->a_ops = &ext2_nobh_aops;
+               inode->i_fop = &ext2_file_operations;
+       } else {
+               inode->i_mapping->a_ops = &ext2_aops;
+               inode->i_fop = &ext2_file_operations;
+       }
+       mark_inode_dirty(inode);
+       d_tmpfile(dentry, inode);
+       unlock_new_inode(inode);
+       return 0;
+}
+
 static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev)
 {
        struct inode * inode;
@@ -398,6 +421,7 @@ const struct inode_operations ext2_dir_inode_operations = {
 #endif
        .setattr        = ext2_setattr,
        .get_acl        = ext2_get_acl,
+       .tmpfile        = ext2_tmpfile,
 };
 
 const struct inode_operations ext2_special_inode_operations = {
index f67668f724baaf4112e994ded2e55a4c62089c3a..2bd85486b87974b390892a2280676a49d8eb274e 100644 (file)
@@ -1985,6 +1985,7 @@ static const struct address_space_operations ext3_ordered_aops = {
        .direct_IO              = ext3_direct_IO,
        .migratepage            = buffer_migrate_page,
        .is_partially_uptodate  = block_is_partially_uptodate,
+       .is_dirty_writeback     = buffer_check_dirty_writeback,
        .error_remove_page      = generic_error_remove_page,
 };
 
index cea8ecf3e76e47efb977127a95cb7b70a9d5f377..998ea111e537e8502dd33b15d5d9eb5f5374306d 100644 (file)
@@ -1759,6 +1759,45 @@ retry:
        return err;
 }
 
+static int ext3_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       handle_t *handle;
+       struct inode *inode;
+       int err, retries = 0;
+
+       dquot_initialize(dir);
+
+retry:
+       handle = ext3_journal_start(dir, EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+                         4 + EXT3_XATTR_TRANS_BLOCKS);
+
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       inode = ext3_new_inode (handle, dir, NULL, mode);
+       err = PTR_ERR(inode);
+       if (!IS_ERR(inode)) {
+               inode->i_op = &ext3_file_inode_operations;
+               inode->i_fop = &ext3_file_operations;
+               ext3_set_aops(inode);
+               err = ext3_orphan_add(handle, inode);
+               if (err)
+                       goto err_drop_inode;
+               mark_inode_dirty(inode);
+               d_tmpfile(dentry, inode);
+               unlock_new_inode(inode);
+       }
+       ext3_journal_stop(handle);
+       if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+               goto retry;
+       return err;
+err_drop_inode:
+       ext3_journal_stop(handle);
+       unlock_new_inode(inode);
+       iput(inode);
+       return err;
+}
+
 static int ext3_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
 {
        handle_t *handle;
@@ -2300,7 +2339,7 @@ static int ext3_link (struct dentry * old_dentry,
 
 retry:
        handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
-                                       EXT3_INDEX_EXTRA_TRANS_BLOCKS);
+                                       EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2314,6 +2353,11 @@ retry:
        err = ext3_add_entry(handle, dentry, inode);
        if (!err) {
                ext3_mark_inode_dirty(handle, inode);
+               /* this can happen only for tmpfile being
+                * linked the first time
+                */
+               if (inode->i_nlink == 1)
+                       ext3_orphan_del(handle, inode);
                d_instantiate(dentry, inode);
        } else {
                drop_nlink(inode);
@@ -2516,6 +2560,7 @@ const struct inode_operations ext3_dir_inode_operations = {
        .mkdir          = ext3_mkdir,
        .rmdir          = ext3_rmdir,
        .mknod          = ext3_mknod,
+       .tmpfile        = ext3_tmpfile,
        .rename         = ext3_rename,
        .setattr        = ext3_setattr,
 #ifdef CONFIG_EXT3_FS_XATTR
index b19f0a457f329c5fb0f6974f7afff8dc79f1e31c..6f4cc567c382b7289e2b35a7038756a581b4cd95 100644 (file)
@@ -494,17 +494,7 @@ static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize)
        if (dataoff > isize)
                return -ENXIO;
 
-       if (dataoff < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
-               return -EINVAL;
-       if (dataoff > maxsize)
-               return -EINVAL;
-
-       if (dataoff != file->f_pos) {
-               file->f_pos = dataoff;
-               file->f_version = 0;
-       }
-
-       return dataoff;
+       return vfs_setpos(file, dataoff, maxsize);
 }
 
 /*
@@ -580,17 +570,7 @@ static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize)
        if (holeoff > isize)
                holeoff = isize;
 
-       if (holeoff < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
-               return -EINVAL;
-       if (holeoff > maxsize)
-               return -EINVAL;
-
-       if (holeoff != file->f_pos) {
-               file->f_pos = holeoff;
-               file->f_version = 0;
-       }
-
-       return holeoff;
+       return vfs_setpos(file, holeoff, maxsize);
 }
 
 /*
index ab2f6dc44b3abf88b62902433f48a1aa78ba8561..234b834d5a9749991e30a97e24e6017124c4e51d 100644 (file)
@@ -2296,6 +2296,45 @@ retry:
        return err;
 }
 
+static int ext4_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       handle_t *handle;
+       struct inode *inode;
+       int err, retries = 0;
+
+       dquot_initialize(dir);
+
+retry:
+       inode = ext4_new_inode_start_handle(dir, mode,
+                                           NULL, 0, NULL,
+                                           EXT4_HT_DIR,
+                       EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+                         4 + EXT4_XATTR_TRANS_BLOCKS);
+       handle = ext4_journal_current_handle();
+       err = PTR_ERR(inode);
+       if (!IS_ERR(inode)) {
+               inode->i_op = &ext4_file_inode_operations;
+               inode->i_fop = &ext4_file_operations;
+               ext4_set_aops(inode);
+               err = ext4_orphan_add(handle, inode);
+               if (err)
+                       goto err_drop_inode;
+               mark_inode_dirty(inode);
+               d_tmpfile(dentry, inode);
+               unlock_new_inode(inode);
+       }
+       if (handle)
+               ext4_journal_stop(handle);
+       if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
+               goto retry;
+       return err;
+err_drop_inode:
+       ext4_journal_stop(handle);
+       unlock_new_inode(inode);
+       iput(inode);
+       return err;
+}
+
 struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
                          struct ext4_dir_entry_2 *de,
                          int blocksize, int csum_size,
@@ -2903,7 +2942,7 @@ static int ext4_link(struct dentry *old_dentry,
 retry:
        handle = ext4_journal_start(dir, EXT4_HT_DIR,
                (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
-                EXT4_INDEX_EXTRA_TRANS_BLOCKS));
+                EXT4_INDEX_EXTRA_TRANS_BLOCKS) + 1);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2917,6 +2956,11 @@ retry:
        err = ext4_add_entry(handle, dentry, inode);
        if (!err) {
                ext4_mark_inode_dirty(handle, inode);
+               /* this can happen only for tmpfile being
+                * linked the first time
+                */
+               if (inode->i_nlink == 1)
+                       ext4_orphan_del(handle, inode);
                d_instantiate(dentry, inode);
        } else {
                drop_nlink(inode);
@@ -3169,6 +3213,7 @@ const struct inode_operations ext4_dir_inode_operations = {
        .mkdir          = ext4_mkdir,
        .rmdir          = ext4_rmdir,
        .mknod          = ext4_mknod,
+       .tmpfile        = ext4_tmpfile,
        .rename         = ext4_rename,
        .setattr        = ext4_setattr,
        .setxattr       = generic_setxattr,
index 359d307b5507a5efd72f41c78434f5f9d35b2558..628e22a5a5433dae9287bdb94b10c19c6af8a538 100644 (file)
@@ -30,7 +30,7 @@ void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
                va_start(args, fmt);
                vaf.fmt = fmt;
                vaf.va = &args;
-               printk(KERN_ERR "FAT-fs (%s): error, %pV\n", sb->s_id, &vaf);
+               fat_msg(sb, KERN_ERR, "error, %pV", &vaf);
                va_end(args);
        }
 
@@ -38,8 +38,7 @@ void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
                panic("FAT-fs (%s): fs panic from previous error\n", sb->s_id);
        else if (opts->errors == FAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) {
                sb->s_flags |= MS_RDONLY;
-               printk(KERN_ERR "FAT-fs (%s): Filesystem has been "
-                               "set read-only\n", sb->s_id);
+               fat_msg(sb, KERN_ERR, "Filesystem has been set read-only");
        }
 }
 EXPORT_SYMBOL_GPL(__fat_fs_error);
index 081b759cff83fee7dc4fa3ba901b2ba9f92c888b..a783b0e1272ad16b3bb638e35867e130a0f455b3 100644 (file)
@@ -148,8 +148,7 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len,
  * that the existing dentry can be used. The msdos fs routines will
  * return ENOENT or EINVAL as appropriate.
  */
-static int msdos_hash(const struct dentry *dentry, const struct inode *inode,
-              struct qstr *qstr)
+static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
 {
        struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
        unsigned char msdos_name[MSDOS_NAME];
@@ -165,8 +164,7 @@ static int msdos_hash(const struct dentry *dentry, const struct inode *inode,
  * Compare two msdos names. If either of the names are invalid,
  * we fall back to doing the standard name comparison.
  */
-static int msdos_cmp(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int msdos_cmp(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options;
index 2da952036a3d7527d98b527ff7114b6d14ec4d43..6df8d3d885e5a56374dfeb61c90a7b6d6e148e15 100644 (file)
@@ -107,8 +107,7 @@ static unsigned int vfat_striptail_len(const struct qstr *qstr)
  * that the existing dentry can be used. The vfat fs routines will
  * return ENOENT or EINVAL as appropriate.
  */
-static int vfat_hash(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+static int vfat_hash(const struct dentry *dentry, struct qstr *qstr)
 {
        qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
        return 0;
@@ -120,8 +119,7 @@ static int vfat_hash(const struct dentry *dentry, const struct inode *inode,
  * that the existing dentry can be used. The vfat fs routines will
  * return ENOENT or EINVAL as appropriate.
  */
-static int vfat_hashi(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr)
 {
        struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
        const unsigned char *name;
@@ -142,8 +140,7 @@ static int vfat_hashi(const struct dentry *dentry, const struct inode *inode,
 /*
  * Case insensitive compare of two vfat names.
  */
-static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int vfat_cmpi(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io;
@@ -162,8 +159,7 @@ static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode,
 /*
  * Case sensitive compare of two vfat names.
  */
-static int vfat_cmp(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int vfat_cmp(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        unsigned int alen, blen;
index 485dc0eddd6707839120324ab552d94ef5ed5ab9..08e719b884ca31320bbcded23f6963ae0268779d 100644 (file)
@@ -227,7 +227,7 @@ static void __fput(struct file *file)
 {
        struct dentry *dentry = file->f_path.dentry;
        struct vfsmount *mnt = file->f_path.mnt;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_inode;
 
        might_sleep();
 
index 35f2810331427b9c4b660cc6b83ec1b889d6910b..5c121fe19c5f9b6122b687cc14bbcd7b1bbe0dc9 100644 (file)
@@ -548,8 +548,7 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
                        res = io->bytes < 0 ? io->size : io->bytes;
 
                        if (!is_sync_kiocb(io->iocb)) {
-                               struct path *path = &io->iocb->ki_filp->f_path;
-                               struct inode *inode = path->dentry->d_inode;
+                               struct inode *inode = file_inode(io->iocb->ki_filp);
                                struct fuse_conn *fc = get_fuse_conn(inode);
                                struct fuse_inode *fi = get_fuse_inode(inode);
 
index 9a0cdde14a088c43e12e5d5fc4ba84257ca98b46..0b578598c6ac8a66f17ed7f4511d7ec0cf9132db 100644 (file)
@@ -785,7 +785,7 @@ static const struct super_operations fuse_super_operations = {
 static void sanitize_global_limit(unsigned *limit)
 {
        if (*limit == 0)
-               *limit = ((num_physpages << PAGE_SHIFT) >> 13) /
+               *limit = ((totalram_pages << PAGE_SHIFT) >> 13) /
                         sizeof(struct fuse_req);
 
        if (*limit >= 1 << 16)
index 4fddb3c22d258ca6da35b4e743ec80fc20ee2e08..f2448ab2aac54d99306140a192afa1c1d9e3dc46 100644 (file)
@@ -109,8 +109,7 @@ fail:
        return 0;
 }
 
-static int gfs2_dhash(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *str)
+static int gfs2_dhash(const struct dentry *dentry, struct qstr *str)
 {
        str->hash = gfs2_disk_hash(str->name, str->len);
        return 0;
index f99f9e8a325fa1cd37abcae7f2a09cb21ce6dd14..72c3866a73205217b9fe57d7863ce2376ce8002b 100644 (file)
@@ -912,7 +912,7 @@ out_uninit:
  * cluster; until we do, disable leases (by just returning -EINVAL),
  * unless the administrator has requested purely local locking.
  *
- * Locking: called under lock_flocks
+ * Locking: called under i_lock
  *
  * Returns: errno
  */
index a73b11839a41b24bf300075f2918dc2ec7b063b2..0524cda47a6e72db892c53c7da294aa212a4c17c 100644 (file)
@@ -229,13 +229,10 @@ extern int hfs_part_find(struct super_block *, sector_t *, sector_t *);
 /* string.c */
 extern const struct dentry_operations hfs_dentry_operations;
 
-extern int hfs_hash_dentry(const struct dentry *, const struct inode *,
-               struct qstr *);
+extern int hfs_hash_dentry(const struct dentry *, struct qstr *);
 extern int hfs_strcmp(const unsigned char *, unsigned int,
                      const unsigned char *, unsigned int);
-extern int hfs_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+extern int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 /* trans.c */
index 495a976a3cc9aa0a0b6e56194ae8f91243129ae5..85b610c3909fbad5b5da73343f29cd9b2b84b96d 100644 (file)
@@ -51,8 +51,7 @@ static unsigned char caseorder[256] = {
 /*
  * Hash a string to an integer in a case-independent way
  */
-int hfs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *this)
+int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this)
 {
        const unsigned char *name = this->name;
        unsigned int hash, len = this->len;
@@ -93,8 +92,7 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1,
  * Test for equality of two strings in the HFS filename character ordering.
  * return 1 on failure and 0 on success
  */
-int hfs_compare_dentry(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        const unsigned char *n1, *n2;
index 60b0a3388b262bcdfd2a02d449505e81b40e1d6b..ede79317cfb8cf5fa521dd187465a8cd63787979 100644 (file)
@@ -495,11 +495,8 @@ int hfsplus_uni2asc(struct super_block *,
                const struct hfsplus_unistr *, char *, int *);
 int hfsplus_asc2uni(struct super_block *,
                struct hfsplus_unistr *, int, const char *, int);
-int hfsplus_hash_dentry(const struct dentry *dentry,
-               const struct inode *inode, struct qstr *str);
-int hfsplus_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str);
+int hfsplus_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 /* wrapper.c */
index 2c2e47dcfdd8aaceb0b297e7e340f02e8df6fe5d..e8ef121a4d8b5be7ca35bfe18aa4de4b925dfb59 100644 (file)
@@ -334,8 +334,7 @@ int hfsplus_asc2uni(struct super_block *sb,
  * Composed unicode characters are decomposed and case-folding is performed
  * if the appropriate bits are (un)set on the superblock.
  */
-int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *str)
+int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
 {
        struct super_block *sb = dentry->d_sb;
        const char *astr;
@@ -386,9 +385,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
  * Composed unicode characters are decomposed and case-folding is performed
  * if the appropriate bits are (un)set on the superblock.
  */
-int hfsplus_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+int hfsplus_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct super_block *sb = parent->d_sb;
index 05d4816e4e774abd72e738c1d62761ceb824885f..fa27980f2229216c47c2378ce7431f18bd5a793e 100644 (file)
@@ -12,8 +12,7 @@
  * Note: the dentry argument is the parent dentry.
  */
 
-static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
        unsigned long    hash;
        int              i;
@@ -35,9 +34,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *ino
        return 0;
 }
 
-static int hpfs_compare_dentry(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int hpfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        unsigned al = len;
index fc90ab11c34049e6431e0b9dcf220040cfbbb146..4338ff32959d4e9e3414bd9ed184d4d47b5a53fe 100644 (file)
@@ -69,7 +69,7 @@ static char *dentry_name(struct dentry *dentry, int extra)
        struct dentry *parent;
        char *root, *name;
        const char *seg_name;
-       int len, seg_len;
+       int len, seg_len, root_len;
 
        len = 0;
        parent = dentry;
@@ -81,7 +81,8 @@ static char *dentry_name(struct dentry *dentry, int extra)
        }
 
        root = "proc";
-       len += strlen(root);
+       root_len = strlen(root);
+       len += root_len;
        name = kmalloc(len + extra + 1, GFP_KERNEL);
        if (name == NULL)
                return NULL;
@@ -91,7 +92,7 @@ static char *dentry_name(struct dentry *dentry, int extra)
        while (parent->d_parent != parent) {
                if (is_pid(parent)) {
                        seg_name = "pid";
-                       seg_len = strlen("pid");
+                       seg_len = strlen(seg_name);
                }
                else {
                        seg_name = parent->d_name.name;
@@ -100,10 +101,10 @@ static char *dentry_name(struct dentry *dentry, int extra)
 
                len -= seg_len + 1;
                name[len] = '/';
-               strncpy(&name[len + 1], seg_name, seg_len);
+               memcpy(&name[len + 1], seg_name, seg_len);
                parent = parent->d_parent;
        }
-       strncpy(name, root, strlen(root));
+       memcpy(name, root, root_len);
        return name;
 }
 
index 00d5fc3b86e12419d2d350032b173009bddcd2cd..d6dfb09c828083b8ba64d3e8aacb2b6a64581038 100644 (file)
@@ -333,8 +333,10 @@ EXPORT_SYMBOL(set_nlink);
  */
 void inc_nlink(struct inode *inode)
 {
-       if (WARN_ON(inode->i_nlink == 0))
+       if (unlikely(inode->i_nlink == 0)) {
+               WARN_ON(!(inode->i_state & I_LINKABLE));
                atomic_long_dec(&inode->i_sb->s_remove_count);
+       }
 
        inode->__i_nlink++;
 }
index 68121584ae37d40a074bf81e55184ecb1674d882..7c5f01cf619d689d76ab51cc7cc221bead874cf4 100644 (file)
@@ -96,11 +96,12 @@ struct open_flags {
        umode_t mode;
        int acc_mode;
        int intent;
+       int lookup_flags;
 };
 extern struct file *do_filp_open(int dfd, struct filename *pathname,
-               const struct open_flags *op, int flags);
+               const struct open_flags *op);
 extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
-               const char *, const struct open_flags *, int lookup_flags);
+               const char *, const struct open_flags *);
 
 extern long do_handle_open(int mountdirfd,
                           struct file_handle __user *ufh, int open_flag);
@@ -130,6 +131,7 @@ extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
  * read_write.c
  */
 extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *);
+extern int rw_verify_area(int, struct file *, const loff_t *, size_t);
 
 /*
  * splice.c
index d9b8aebdeb22b467eb9717996b823734f8446300..c348d6d886240cb0354dbc71faf88fef2395db67 100644 (file)
 
 #define BEQUIET
 
-static int isofs_hashi(const struct dentry *parent, const struct inode *inode,
-               struct qstr *qstr);
-static int isofs_hash(const struct dentry *parent, const struct inode *inode,
-               struct qstr *qstr);
+static int isofs_hashi(const struct dentry *parent, struct qstr *qstr);
+static int isofs_hash(const struct dentry *parent, struct qstr *qstr);
 static int isofs_dentry_cmpi(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+               const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 static int isofs_dentry_cmp(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+               const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 
 #ifdef CONFIG_JOLIET
-static int isofs_hashi_ms(const struct dentry *parent, const struct inode *inode,
-               struct qstr *qstr);
-static int isofs_hash_ms(const struct dentry *parent, const struct inode *inode,
-               struct qstr *qstr);
+static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr);
+static int isofs_hash_ms(const struct dentry *parent, struct qstr *qstr);
 static int isofs_dentry_cmpi_ms(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+               const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 static int isofs_dentry_cmp_ms(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+               const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name);
 #endif
 
@@ -265,30 +257,26 @@ static int isofs_dentry_cmp_common(
 }
 
 static int
-isofs_hash(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+isofs_hash(const struct dentry *dentry, struct qstr *qstr)
 {
        return isofs_hash_common(dentry, qstr, 0);
 }
 
 static int
-isofs_hashi(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
 {
        return isofs_hashi_common(dentry, qstr, 0);
 }
 
 static int
-isofs_dentry_cmp(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+isofs_dentry_cmp(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 0, 0);
 }
 
 static int
-isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 0, 1);
@@ -296,30 +284,26 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode,
 
 #ifdef CONFIG_JOLIET
 static int
-isofs_hash_ms(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)
 {
        return isofs_hash_common(dentry, qstr, 1);
 }
 
 static int
-isofs_hashi_ms(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr)
 {
        return isofs_hashi_common(dentry, qstr, 1);
 }
 
 static int
-isofs_dentry_cmp_ms(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+isofs_dentry_cmp_ms(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 1, 0);
 }
 
 static int
-isofs_dentry_cmpi_ms(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+isofs_dentry_cmpi_ms(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        return isofs_dentry_cmp_common(len, str, name, 1, 1);
index c167028844ed539fca2b25931ccfb51a8d32d962..95295640d9c8b0a36c4f6fae469e59488c21a52e 100644 (file)
@@ -37,8 +37,7 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
 
        qstr.name = compare;
        qstr.len = dlen;
-       return dentry->d_op->d_compare(NULL, NULL, NULL, NULL,
-                       dentry->d_name.len, dentry->d_name.name, &qstr);
+       return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
 }
 
 /*
index 89186b7b9002145d268aa7054559b384422dd1d2..8b19027291d6b14b667757256499a750df5312ef 100644 (file)
@@ -1538,8 +1538,7 @@ const struct file_operations jfs_dir_operations = {
        .llseek         = generic_file_llseek,
 };
 
-static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode,
-               struct qstr *this)
+static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
 {
        unsigned long hash;
        int i;
@@ -1552,9 +1551,7 @@ static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode,
        return 0;
 }
 
-static int jfs_ci_compare(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int jfs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        int i, result = 1;
index a2aa97d45670635c4d84ef422ea9a1d794cdce69..10d6c41aecad7bd4db25f65e652479f7536aaf3b 100644 (file)
@@ -305,7 +305,7 @@ static int lockd_start_svc(struct svc_serv *serv)
        svc_sock_update_bufs(serv);
        serv->sv_maxconn = nlm_max_connections;
 
-       nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, serv->sv_name);
+       nlmsvc_task = kthread_run(lockd, nlmsvc_rqst, "%s", serv->sv_name);
        if (IS_ERR(nlmsvc_task)) {
                error = PTR_ERR(nlmsvc_task);
                printk(KERN_WARNING
index e703318c41dface91c09b100a3c88bacd63f6751..067778b0ccc9dddd878277d6ca88e9c5d2fddc5b 100644 (file)
@@ -276,7 +276,7 @@ static int nlmsvc_unlink_block(struct nlm_block *block)
        dprintk("lockd: unlinking block %p...\n", block);
 
        /* Remove block from list */
-       status = posix_unblock_lock(block->b_file->f_file, &block->b_call->a_args.lock.fl);
+       status = posix_unblock_lock(&block->b_call->a_args.lock.fl);
        nlmsvc_remove_block(block);
        return status;
 }
@@ -744,8 +744,20 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
        return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid;
 }
 
+/*
+ * Since NLM uses two "keys" for tracking locks, we need to hash them down
+ * to one for the blocked_hash. Here, we're just xor'ing the host address
+ * with the pid in order to create a key value for picking a hash bucket.
+ */
+static unsigned long
+nlmsvc_owner_key(struct file_lock *fl)
+{
+       return (unsigned long)fl->fl_owner ^ (unsigned long)fl->fl_pid;
+}
+
 const struct lock_manager_operations nlmsvc_lock_operations = {
        .lm_compare_owner = nlmsvc_same_owner,
+       .lm_owner_key = nlmsvc_owner_key,
        .lm_notify = nlmsvc_notify_blocked,
        .lm_grant = nlmsvc_grant_deferred,
 };
index 97e87415b145f7a6a0ed0e1a37c40a657209bf89..dc5c75930f0fea94145c9556f2aab6dbc8ea91a3 100644 (file)
@@ -169,7 +169,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
 
 again:
        file->f_locks = 0;
-       lock_flocks(); /* protects i_flock list */
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl; fl = fl->fl_next) {
                if (fl->fl_lmops != &nlmsvc_lock_operations)
                        continue;
@@ -181,7 +181,7 @@ again:
                if (match(lockhost, host)) {
                        struct file_lock lock = *fl;
 
-                       unlock_flocks();
+                       spin_unlock(&inode->i_lock);
                        lock.fl_type  = F_UNLCK;
                        lock.fl_start = 0;
                        lock.fl_end   = OFFSET_MAX;
@@ -193,7 +193,7 @@ again:
                        goto again;
                }
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 
        return 0;
 }
@@ -228,14 +228,14 @@ nlm_file_inuse(struct nlm_file *file)
        if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
                return 1;
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl; fl = fl->fl_next) {
                if (fl->fl_lmops == &nlmsvc_lock_operations) {
-                       unlock_flocks();
+                       spin_unlock(&inode->i_lock);
                        return 1;
                }
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        file->f_locks = 0;
        return 0;
 }
index cb424a4fed71a42d237b72d16de8318bbbeb0fbd..04e2c1fdb157afeb0bc8fe278a74909cd239126b 100644 (file)
 #include <linux/time.h>
 #include <linux/rcupdate.h>
 #include <linux/pid_namespace.h>
+#include <linux/hashtable.h>
 
 #include <asm/uaccess.h>
 
@@ -153,30 +154,51 @@ int lease_break_time = 45;
 #define for_each_lock(inode, lockp) \
        for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next)
 
-static LIST_HEAD(file_lock_list);
-static LIST_HEAD(blocked_list);
+/*
+ * The global file_lock_list is only used for displaying /proc/locks. Protected
+ * by the file_lock_lock.
+ */
+static HLIST_HEAD(file_lock_list);
 static DEFINE_SPINLOCK(file_lock_lock);
 
 /*
- * Protects the two list heads above, plus the inode->i_flock list
+ * The blocked_hash is used to find POSIX lock loops for deadlock detection.
+ * It is protected by blocked_lock_lock.
+ *
+ * We hash locks by lockowner in order to optimize searching for the lock a
+ * particular lockowner is waiting on.
+ *
+ * FIXME: make this value scale via some heuristic? We generally will want more
+ * buckets when we have more lockowners holding locks, but that's a little
+ * difficult to determine without knowing what the workload will look like.
  */
-void lock_flocks(void)
-{
-       spin_lock(&file_lock_lock);
-}
-EXPORT_SYMBOL_GPL(lock_flocks);
+#define BLOCKED_HASH_BITS      7
+static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS);
 
-void unlock_flocks(void)
-{
-       spin_unlock(&file_lock_lock);
-}
-EXPORT_SYMBOL_GPL(unlock_flocks);
+/*
+ * This lock protects the blocked_hash. Generally, if you're accessing it, you
+ * want to be holding this lock.
+ *
+ * In addition, it also protects the fl->fl_block list, and the fl->fl_next
+ * pointer for file_lock structures that are acting as lock requests (in
+ * contrast to those that are acting as records of acquired locks).
+ *
+ * Note that when we acquire this lock in order to change the above fields,
+ * we often hold the i_lock as well. In certain cases, when reading the fields
+ * protected by this lock, we can skip acquiring it iff we already hold the
+ * i_lock.
+ *
+ * In particular, adding an entry to the fl_block list requires that you hold
+ * both the i_lock and the blocked_lock_lock (acquired in that order). Deleting
+ * an entry from the list however only requires the file_lock_lock.
+ */
+static DEFINE_SPINLOCK(blocked_lock_lock);
 
 static struct kmem_cache *filelock_cache __read_mostly;
 
 static void locks_init_lock_heads(struct file_lock *fl)
 {
-       INIT_LIST_HEAD(&fl->fl_link);
+       INIT_HLIST_NODE(&fl->fl_link);
        INIT_LIST_HEAD(&fl->fl_block);
        init_waitqueue_head(&fl->fl_wait);
 }
@@ -210,7 +232,7 @@ void locks_free_lock(struct file_lock *fl)
 {
        BUG_ON(waitqueue_active(&fl->fl_wait));
        BUG_ON(!list_empty(&fl->fl_block));
-       BUG_ON(!list_empty(&fl->fl_link));
+       BUG_ON(!hlist_unhashed(&fl->fl_link));
 
        locks_release_private(fl);
        kmem_cache_free(filelock_cache, fl);
@@ -484,47 +506,108 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
        return fl1->fl_owner == fl2->fl_owner;
 }
 
+static inline void
+locks_insert_global_locks(struct file_lock *fl)
+{
+       spin_lock(&file_lock_lock);
+       hlist_add_head(&fl->fl_link, &file_lock_list);
+       spin_unlock(&file_lock_lock);
+}
+
+static inline void
+locks_delete_global_locks(struct file_lock *fl)
+{
+       spin_lock(&file_lock_lock);
+       hlist_del_init(&fl->fl_link);
+       spin_unlock(&file_lock_lock);
+}
+
+static unsigned long
+posix_owner_key(struct file_lock *fl)
+{
+       if (fl->fl_lmops && fl->fl_lmops->lm_owner_key)
+               return fl->fl_lmops->lm_owner_key(fl);
+       return (unsigned long)fl->fl_owner;
+}
+
+static inline void
+locks_insert_global_blocked(struct file_lock *waiter)
+{
+       hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter));
+}
+
+static inline void
+locks_delete_global_blocked(struct file_lock *waiter)
+{
+       hash_del(&waiter->fl_link);
+}
+
 /* Remove waiter from blocker's block list.
  * When blocker ends up pointing to itself then the list is empty.
+ *
+ * Must be called with blocked_lock_lock held.
  */
 static void __locks_delete_block(struct file_lock *waiter)
 {
+       locks_delete_global_blocked(waiter);
        list_del_init(&waiter->fl_block);
-       list_del_init(&waiter->fl_link);
        waiter->fl_next = NULL;
 }
 
-/*
- */
-void locks_delete_block(struct file_lock *waiter)
+static void locks_delete_block(struct file_lock *waiter)
 {
-       lock_flocks();
+       spin_lock(&blocked_lock_lock);
        __locks_delete_block(waiter);
-       unlock_flocks();
+       spin_unlock(&blocked_lock_lock);
 }
-EXPORT_SYMBOL(locks_delete_block);
 
 /* Insert waiter into blocker's block list.
  * We use a circular list so that processes can be easily woken up in
  * the order they blocked. The documentation doesn't require this but
  * it seems like the reasonable thing to do.
+ *
+ * Must be called with both the i_lock and blocked_lock_lock held. The fl_block
+ * list itself is protected by the file_lock_list, but by ensuring that the
+ * i_lock is also held on insertions we can avoid taking the blocked_lock_lock
+ * in some cases when we see that the fl_block list is empty.
  */
-static void locks_insert_block(struct file_lock *blocker, 
-                              struct file_lock *waiter)
+static void __locks_insert_block(struct file_lock *blocker,
+                                       struct file_lock *waiter)
 {
        BUG_ON(!list_empty(&waiter->fl_block));
-       list_add_tail(&waiter->fl_block, &blocker->fl_block);
        waiter->fl_next = blocker;
+       list_add_tail(&waiter->fl_block, &blocker->fl_block);
        if (IS_POSIX(blocker))
-               list_add(&waiter->fl_link, &blocked_list);
+               locks_insert_global_blocked(waiter);
 }
 
-/* Wake up processes blocked waiting for blocker.
- * If told to wait then schedule the processes until the block list
- * is empty, otherwise empty the block list ourselves.
+/* Must be called with i_lock held. */
+static void locks_insert_block(struct file_lock *blocker,
+                                       struct file_lock *waiter)
+{
+       spin_lock(&blocked_lock_lock);
+       __locks_insert_block(blocker, waiter);
+       spin_unlock(&blocked_lock_lock);
+}
+
+/*
+ * Wake up processes blocked waiting for blocker.
+ *
+ * Must be called with the inode->i_lock held!
  */
 static void locks_wake_up_blocks(struct file_lock *blocker)
 {
+       /*
+        * Avoid taking global lock if list is empty. This is safe since new
+        * blocked requests are only added to the list under the i_lock, and
+        * the i_lock is always held here. Note that removal from the fl_block
+        * list does not require the i_lock, so we must recheck list_empty()
+        * after acquiring the blocked_lock_lock.
+        */
+       if (list_empty(&blocker->fl_block))
+               return;
+
+       spin_lock(&blocked_lock_lock);
        while (!list_empty(&blocker->fl_block)) {
                struct file_lock *waiter;
 
@@ -536,20 +619,23 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
                else
                        wake_up(&waiter->fl_wait);
        }
+       spin_unlock(&blocked_lock_lock);
 }
 
 /* Insert file lock fl into an inode's lock list at the position indicated
  * by pos. At the same time add the lock to the global file lock list.
+ *
+ * Must be called with the i_lock held!
  */
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
 {
-       list_add(&fl->fl_link, &file_lock_list);
-
        fl->fl_nspid = get_pid(task_tgid(current));
 
        /* insert into file's list */
        fl->fl_next = *pos;
        *pos = fl;
+
+       locks_insert_global_locks(fl);
 }
 
 /*
@@ -557,14 +643,17 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
  * Wake up processes that are blocked waiting for this lock,
  * notify the FS that the lock has been cleared and
  * finally free the lock.
+ *
+ * Must be called with the i_lock held!
  */
 static void locks_delete_lock(struct file_lock **thisfl_p)
 {
        struct file_lock *fl = *thisfl_p;
 
+       locks_delete_global_locks(fl);
+
        *thisfl_p = fl->fl_next;
        fl->fl_next = NULL;
-       list_del_init(&fl->fl_link);
 
        if (fl->fl_nspid) {
                put_pid(fl->fl_nspid);
@@ -625,8 +714,9 @@ void
 posix_test_lock(struct file *filp, struct file_lock *fl)
 {
        struct file_lock *cfl;
+       struct inode *inode = file_inode(filp);
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        for (cfl = file_inode(filp)->i_flock; cfl; cfl = cfl->fl_next) {
                if (!IS_POSIX(cfl))
                        continue;
@@ -639,7 +729,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
                        fl->fl_pid = pid_vnr(cfl->fl_nspid);
        } else
                fl->fl_type = F_UNLCK;
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return;
 }
 EXPORT_SYMBOL(posix_test_lock);
@@ -676,13 +766,14 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
 {
        struct file_lock *fl;
 
-       list_for_each_entry(fl, &blocked_list, fl_link) {
+       hash_for_each_possible(blocked_hash, fl, fl_link, posix_owner_key(block_fl)) {
                if (posix_same_owner(fl, block_fl))
                        return fl->fl_next;
        }
        return NULL;
 }
 
+/* Must be called with the blocked_lock_lock held! */
 static int posix_locks_deadlock(struct file_lock *caller_fl,
                                struct file_lock *block_fl)
 {
@@ -718,7 +809,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
                        return -ENOMEM;
        }
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        if (request->fl_flags & FL_ACCESS)
                goto find_conflict;
 
@@ -748,9 +839,9 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
         * give it the opportunity to lock the file.
         */
        if (found) {
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                cond_resched();
-               lock_flocks();
+               spin_lock(&inode->i_lock);
        }
 
 find_conflict:
@@ -777,7 +868,7 @@ find_conflict:
        error = 0;
 
 out:
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        if (new_fl)
                locks_free_lock(new_fl);
        return error;
@@ -791,7 +882,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
        struct file_lock *left = NULL;
        struct file_lock *right = NULL;
        struct file_lock **before;
-       int error, added = 0;
+       int error;
+       bool added = false;
 
        /*
         * We may need two file_lock structures for this operation,
@@ -806,7 +898,12 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                new_fl2 = locks_alloc_lock();
        }
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
+       /*
+        * New lock request. Walk all POSIX locks and look for conflicts. If
+        * there are any, either return error or put the request on the
+        * blocker's list of waiters and the global blocked_hash.
+        */
        if (request->fl_type != F_UNLCK) {
                for_each_lock(inode, before) {
                        fl = *before;
@@ -819,11 +916,17 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                        error = -EAGAIN;
                        if (!(request->fl_flags & FL_SLEEP))
                                goto out;
+                       /*
+                        * Deadlock detection and insertion into the blocked
+                        * locks list must be done while holding the same lock!
+                        */
                        error = -EDEADLK;
-                       if (posix_locks_deadlock(request, fl))
-                               goto out;
-                       error = FILE_LOCK_DEFERRED;
-                       locks_insert_block(fl, request);
+                       spin_lock(&blocked_lock_lock);
+                       if (likely(!posix_locks_deadlock(request, fl))) {
+                               error = FILE_LOCK_DEFERRED;
+                               __locks_insert_block(fl, request);
+                       }
+                       spin_unlock(&blocked_lock_lock);
                        goto out;
                }
        }
@@ -845,7 +948,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                before = &fl->fl_next;
        }
 
-       /* Process locks with this owner.  */
+       /* Process locks with this owner. */
        while ((fl = *before) && posix_same_owner(request, fl)) {
                /* Detect adjacent or overlapping regions (if same lock type)
                 */
@@ -880,7 +983,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                                continue;
                        }
                        request = fl;
-                       added = 1;
+                       added = true;
                }
                else {
                        /* Processing for different lock types is a bit
@@ -891,7 +994,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                        if (fl->fl_start > request->fl_end)
                                break;
                        if (request->fl_type == F_UNLCK)
-                               added = 1;
+                               added = true;
                        if (fl->fl_start < request->fl_start)
                                left = fl;
                        /* If the next lock in the list has a higher end
@@ -921,7 +1024,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                                locks_release_private(fl);
                                locks_copy_private(fl, request);
                                request = fl;
-                               added = 1;
+                               added = true;
                        }
                }
                /* Go on to next lock.
@@ -931,10 +1034,9 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
        }
 
        /*
-        * The above code only modifies existing locks in case of
-        * merging or replacing.  If new lock(s) need to be inserted
-        * all modifications are done bellow this, so it's safe yet to
-        * bail out.
+        * The above code only modifies existing locks in case of merging or
+        * replacing. If new lock(s) need to be inserted all modifications are
+        * done below this, so it's safe yet to bail out.
         */
        error = -ENOLCK; /* "no luck" */
        if (right && left == right && !new_fl2)
@@ -974,7 +1076,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                locks_wake_up_blocks(left);
        }
  out:
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        /*
         * Free any unused locks.
         */
@@ -1049,14 +1151,14 @@ int locks_mandatory_locked(struct inode *inode)
        /*
         * Search the lock list for this inode for any POSIX locks.
         */
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (!IS_POSIX(fl))
                        continue;
                if (fl->fl_owner != owner)
                        break;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return fl ? -EAGAIN : 0;
 }
 
@@ -1199,7 +1301,7 @@ int __break_lease(struct inode *inode, unsigned int mode)
        if (IS_ERR(new_fl))
                return PTR_ERR(new_fl);
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
 
        time_out_leases(inode);
 
@@ -1249,11 +1351,11 @@ restart:
                        break_time++;
        }
        locks_insert_block(flock, new_fl);
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        error = wait_event_interruptible_timeout(new_fl->fl_wait,
                                                !new_fl->fl_next, break_time);
-       lock_flocks();
-       __locks_delete_block(new_fl);
+       spin_lock(&inode->i_lock);
+       locks_delete_block(new_fl);
        if (error >= 0) {
                if (error == 0)
                        time_out_leases(inode);
@@ -1270,7 +1372,7 @@ restart:
        }
 
 out:
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        locks_free_lock(new_fl);
        return error;
 }
@@ -1323,9 +1425,10 @@ EXPORT_SYMBOL(lease_get_mtime);
 int fcntl_getlease(struct file *filp)
 {
        struct file_lock *fl;
+       struct inode *inode = file_inode(filp);
        int type = F_UNLCK;
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        time_out_leases(file_inode(filp));
        for (fl = file_inode(filp)->i_flock; fl && IS_LEASE(fl);
                        fl = fl->fl_next) {
@@ -1334,11 +1437,11 @@ int fcntl_getlease(struct file *filp)
                        break;
                }
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return type;
 }
 
-int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
+static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
 {
        struct file_lock *fl, **before, **my_before = NULL, *lease;
        struct dentry *dentry = filp->f_path.dentry;
@@ -1403,7 +1506,7 @@ out:
        return error;
 }
 
-int generic_delete_lease(struct file *filp, struct file_lock **flp)
+static int generic_delete_lease(struct file *filp, struct file_lock **flp)
 {
        struct file_lock *fl, **before;
        struct dentry *dentry = filp->f_path.dentry;
@@ -1428,7 +1531,7 @@ int generic_delete_lease(struct file *filp, struct file_lock **flp)
  *     The (input) flp->fl_lmops->lm_break function is required
  *     by break_lease().
  *
- *     Called with file_lock_lock held.
+ *     Called with inode->i_lock held.
  */
 int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
 {
@@ -1497,11 +1600,12 @@ static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
 
 int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
 {
+       struct inode *inode = file_inode(filp);
        int error;
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        error = __vfs_setlease(filp, arg, lease);
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 
        return error;
 }
@@ -1519,6 +1623,7 @@ static int do_fcntl_delete_lease(struct file *filp)
 static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
 {
        struct file_lock *fl, *ret;
+       struct inode *inode = file_inode(filp);
        struct fasync_struct *new;
        int error;
 
@@ -1532,10 +1637,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
                return -ENOMEM;
        }
        ret = fl;
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        error = __vfs_setlease(filp, arg, &ret);
        if (error) {
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                locks_free_lock(fl);
                goto out_free_fasync;
        }
@@ -1552,7 +1657,7 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
                new = NULL;
 
        error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 
 out_free_fasync:
        if (new)
@@ -2076,7 +2181,7 @@ void locks_remove_flock(struct file *filp)
                        fl.fl_ops->fl_release_private(&fl);
        }
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        before = &inode->i_flock;
 
        while ((fl = *before) != NULL) {
@@ -2094,30 +2199,28 @@ void locks_remove_flock(struct file *filp)
                }
                before = &fl->fl_next;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 }
 
 /**
  *     posix_unblock_lock - stop waiting for a file lock
- *      @filp:   how the file was opened
  *     @waiter: the lock which was waiting
  *
  *     lockd needs to block waiting for locks.
  */
 int
-posix_unblock_lock(struct file *filp, struct file_lock *waiter)
+posix_unblock_lock(struct file_lock *waiter)
 {
        int status = 0;
 
-       lock_flocks();
+       spin_lock(&blocked_lock_lock);
        if (waiter->fl_next)
                __locks_delete_block(waiter);
        else
                status = -ENOENT;
-       unlock_flocks();
+       spin_unlock(&blocked_lock_lock);
        return status;
 }
-
 EXPORT_SYMBOL(posix_unblock_lock);
 
 /**
@@ -2215,7 +2318,7 @@ static int locks_show(struct seq_file *f, void *v)
 {
        struct file_lock *fl, *bfl;
 
-       fl = list_entry(v, struct file_lock, fl_link);
+       fl = hlist_entry(v, struct file_lock, fl_link);
 
        lock_get_status(f, fl, *((loff_t *)f->private), "");
 
@@ -2229,21 +2332,23 @@ static void *locks_start(struct seq_file *f, loff_t *pos)
 {
        loff_t *p = f->private;
 
-       lock_flocks();
+       spin_lock(&file_lock_lock);
+       spin_lock(&blocked_lock_lock);
        *p = (*pos + 1);
-       return seq_list_start(&file_lock_list, *pos);
+       return seq_hlist_start(&file_lock_list, *pos);
 }
 
 static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
 {
        loff_t *p = f->private;
        ++*p;
-       return seq_list_next(v, &file_lock_list, pos);
+       return seq_hlist_next(v, &file_lock_list, pos);
 }
 
 static void locks_stop(struct seq_file *f, void *v)
 {
-       unlock_flocks();
+       spin_unlock(&blocked_lock_lock);
+       spin_unlock(&file_lock_lock);
 }
 
 static const struct seq_operations locks_seq_operations = {
@@ -2290,7 +2395,8 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
 {
        struct file_lock *fl;
        int result = 1;
-       lock_flocks();
+
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (IS_POSIX(fl)) {
                        if (fl->fl_type == F_RDLCK)
@@ -2307,7 +2413,7 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
                result = 0;
                break;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return result;
 }
 
@@ -2330,7 +2436,8 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
 {
        struct file_lock *fl;
        int result = 1;
-       lock_flocks();
+
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (IS_POSIX(fl)) {
                        if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
@@ -2345,7 +2452,7 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
                result = 0;
                break;
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return result;
 }
 
index 08c442902fcdbf9ec5a9039621f8b8900ea6bf0e..dfaf6fa9b7b52a28bcb00ce3c4cd3df817158814 100644 (file)
@@ -93,7 +93,7 @@ static int minix_readdir(struct file *file, struct dir_context *ctx)
        unsigned offset;
        unsigned long n;
 
-       ctx->pos = pos = (pos + chunk_size-1) & ~(chunk_size-1);
+       ctx->pos = pos = ALIGN(pos, chunk_size);
        if (pos >= inode->i_size)
                return 0;
 
index 0db73d9dd66845d289f6f1a58e1960ecc1ee3e74..cd950e2331b6c3164376e1b2205b3563f5703525 100644 (file)
@@ -54,6 +54,18 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, umode_t mode,
        return error;
 }
 
+static int minix_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       int error;
+       struct inode *inode = minix_new_inode(dir, mode, &error);
+       if (inode) {
+               minix_set_inode(inode, 0);
+               mark_inode_dirty(inode);
+               d_tmpfile(dentry, inode);
+       }
+       return error;
+}
+
 static int minix_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                bool excl)
 {
@@ -254,4 +266,5 @@ const struct inode_operations minix_dir_inode_operations = {
        .mknod          = minix_mknod,
        .rename         = minix_rename,
        .getattr        = minix_getattr,
+       .tmpfile        = minix_tmpfile,
 };
index 9ed9361223c08f30ebbcca48e165588adeb31378..b2beee7a733fe3f862945f39042e04937f821741 100644 (file)
@@ -1352,7 +1352,7 @@ static int lookup_fast(struct nameidata *nd,
         */
        if (nd->flags & LOOKUP_RCU) {
                unsigned seq;
-               dentry = __d_lookup_rcu(parent, &nd->last, &seq, nd->inode);
+               dentry = __d_lookup_rcu(parent, &nd->last, &seq);
                if (!dentry)
                        goto unlazy;
 
@@ -1787,8 +1787,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        struct dentry *parent = nd->path.dentry;
                        nd->flags &= ~LOOKUP_JUMPED;
                        if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
-                               err = parent->d_op->d_hash(parent, nd->inode,
-                                                          &this);
+                               err = parent->d_op->d_hash(parent, &this);
                                if (err < 0)
                                        break;
                        }
@@ -2121,7 +2120,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
         * to use its own hash..
         */
        if (base->d_flags & DCACHE_OP_HASH) {
-               int err = base->d_op->d_hash(base, base->d_inode, &this);
+               int err = base->d_op->d_hash(base, &this);
                if (err < 0)
                        return ERR_PTR(err);
        }
@@ -2690,28 +2689,10 @@ static int do_last(struct nameidata *nd, struct path *path,
        nd->flags &= ~LOOKUP_PARENT;
        nd->flags |= op->intent;
 
-       switch (nd->last_type) {
-       case LAST_DOTDOT:
-       case LAST_DOT:
+       if (nd->last_type != LAST_NORM) {
                error = handle_dots(nd, nd->last_type);
                if (error)
                        return error;
-               /* fallthrough */
-       case LAST_ROOT:
-               error = complete_walk(nd);
-               if (error)
-                       return error;
-               audit_inode(name, nd->path.dentry, 0);
-               if (open_flag & O_CREAT) {
-                       error = -EISDIR;
-                       goto out;
-               }
-               goto finish_open;
-       case LAST_BIND:
-               error = complete_walk(nd);
-               if (error)
-                       return error;
-               audit_inode(name, dir, 0);
                goto finish_open;
        }
 
@@ -2841,19 +2822,19 @@ finish_lookup:
        }
        nd->inode = inode;
        /* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */
+finish_open:
        error = complete_walk(nd);
        if (error) {
                path_put(&save_parent);
                return error;
        }
+       audit_inode(name, nd->path.dentry, 0);
        error = -EISDIR;
        if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode))
                goto out;
        error = -ENOTDIR;
        if ((nd->flags & LOOKUP_DIRECTORY) && !can_lookup(nd->inode))
                goto out;
-       audit_inode(name, nd->path.dentry, 0);
-finish_open:
        if (!S_ISREG(nd->inode->i_mode))
                will_truncate = false;
 
@@ -2920,6 +2901,67 @@ stale_open:
        goto retry_lookup;
 }
 
+static int do_tmpfile(int dfd, struct filename *pathname,
+               struct nameidata *nd, int flags,
+               const struct open_flags *op,
+               struct file *file, int *opened)
+{
+       static const struct qstr name = QSTR_INIT("/", 1);
+       struct dentry *dentry, *child;
+       struct inode *dir;
+       int error = path_lookupat(dfd, pathname->name,
+                                 flags | LOOKUP_DIRECTORY, nd);
+       if (unlikely(error))
+               return error;
+       error = mnt_want_write(nd->path.mnt);
+       if (unlikely(error))
+               goto out;
+       /* we want directory to be writable */
+       error = inode_permission(nd->inode, MAY_WRITE | MAY_EXEC);
+       if (error)
+               goto out2;
+       dentry = nd->path.dentry;
+       dir = dentry->d_inode;
+       if (!dir->i_op->tmpfile) {
+               error = -EOPNOTSUPP;
+               goto out2;
+       }
+       child = d_alloc(dentry, &name);
+       if (unlikely(!child)) {
+               error = -ENOMEM;
+               goto out2;
+       }
+       nd->flags &= ~LOOKUP_DIRECTORY;
+       nd->flags |= op->intent;
+       dput(nd->path.dentry);
+       nd->path.dentry = child;
+       error = dir->i_op->tmpfile(dir, nd->path.dentry, op->mode);
+       if (error)
+               goto out2;
+       audit_inode(pathname, nd->path.dentry, 0);
+       error = may_open(&nd->path, op->acc_mode, op->open_flag);
+       if (error)
+               goto out2;
+       file->f_path.mnt = nd->path.mnt;
+       error = finish_open(file, nd->path.dentry, NULL, opened);
+       if (error)
+               goto out2;
+       error = open_check_o_direct(file);
+       if (error) {
+               fput(file);
+       } else if (!(op->open_flag & O_EXCL)) {
+               struct inode *inode = file_inode(file);
+               spin_lock(&inode->i_lock);
+               inode->i_state |= I_LINKABLE;
+               spin_unlock(&inode->i_lock);
+       }
+out2:
+       mnt_drop_write(nd->path.mnt);
+out:
+       path_put(&nd->path);
+       return error;
+}
+
 static struct file *path_openat(int dfd, struct filename *pathname,
                struct nameidata *nd, const struct open_flags *op, int flags)
 {
@@ -2935,6 +2977,11 @@ static struct file *path_openat(int dfd, struct filename *pathname,
 
        file->f_flags = op->open_flag;
 
+       if (unlikely(file->f_flags & O_TMPFILE)) {
+               error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened);
+               goto out;
+       }
+
        error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base);
        if (unlikely(error))
                goto out;
@@ -2987,9 +3034,10 @@ out:
 }
 
 struct file *do_filp_open(int dfd, struct filename *pathname,
-               const struct open_flags *op, int flags)
+               const struct open_flags *op)
 {
        struct nameidata nd;
+       int flags = op->lookup_flags;
        struct file *filp;
 
        filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
@@ -3001,17 +3049,16 @@ struct file *do_filp_open(int dfd, struct filename *pathname,
 }
 
 struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
-               const char *name, const struct open_flags *op, int flags)
+               const char *name, const struct open_flags *op)
 {
        struct nameidata nd;
        struct file *file;
        struct filename filename = { .name = name };
+       int flags = op->lookup_flags | LOOKUP_ROOT;
 
        nd.root.mnt = mnt;
        nd.root.dentry = dentry;
 
-       flags |= LOOKUP_ROOT;
-
        if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN)
                return ERR_PTR(-ELOOP);
 
@@ -3586,12 +3633,18 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
 
        mutex_lock(&inode->i_mutex);
        /* Make sure we don't allow creating hardlink to an unlinked file */
-       if (inode->i_nlink == 0)
+       if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
                error =  -ENOENT;
        else if (max_links && inode->i_nlink >= max_links)
                error = -EMLINK;
        else
                error = dir->i_op->link(old_dentry, dir, new_dentry);
+
+       if (!error && (inode->i_state & I_LINKABLE)) {
+               spin_lock(&inode->i_lock);
+               inode->i_state &= ~I_LINKABLE;
+               spin_unlock(&inode->i_lock);
+       }
        mutex_unlock(&inode->i_mutex);
        if (!error)
                fsnotify_link(dir, inode, new_dentry);
index 0e7f00298213f3249b34f8564609c762d2e765ed..3be047474bfc355731c08e2a6c27b40e73ce9e8b 100644 (file)
@@ -73,10 +73,8 @@ const struct inode_operations ncp_dir_inode_operations =
  * Dentry operations routines
  */
 static int ncp_lookup_validate(struct dentry *, unsigned int);
-static int ncp_hash_dentry(const struct dentry *, const struct inode *,
-               struct qstr *);
-static int ncp_compare_dentry(const struct dentry *, const struct inode *,
-               const struct dentry *, const struct inode *,
+static int ncp_hash_dentry(const struct dentry *, struct qstr *);
+static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
                unsigned int, const char *, const struct qstr *);
 static int ncp_delete_dentry(const struct dentry *);
 
@@ -119,11 +117,19 @@ static inline int ncp_case_sensitive(const struct inode *i)
 /*
  * Note: leave the hash unchanged if the directory
  * is case-sensitive.
+ *
+ * Accessing the parent inode can be racy under RCU pathwalking.
+ * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
+ * the callers will handle races.
  */
 static int 
-ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *this)
+ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
 {
+       struct inode *inode = ACCESS_ONCE(dentry->d_inode);
+
+       if (!inode)
+               return 0;
+
        if (!ncp_case_sensitive(inode)) {
                struct super_block *sb = dentry->d_sb;
                struct nls_table *t;
@@ -140,14 +146,24 @@ ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
        return 0;
 }
 
+/*
+ * Accessing the parent inode can be racy under RCU pathwalking.
+ * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
+ * the callers will handle races.
+ */
 static int
-ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
+       struct inode *pinode;
+
        if (len != name->len)
                return 1;
 
+       pinode = ACCESS_ONCE(parent->d_inode);
+       if (!pinode)
+               return 1;
+
        if (ncp_case_sensitive(pinode))
                return strncmp(str, name->name, len);
 
@@ -659,8 +675,6 @@ end_advance:
        if (!valid)
                ctl.valid = 0;
        if (!ctl.filled && (ctl.fpos == ctx->pos)) {
-               if (!ino)
-                       ino = find_inode_number(dentry, &qname);
                if (!ino)
                        ino = iunique(dir->i_sb, 2);
                ctl.filled = !dir_emit(ctx, qname.name, qname.len,
@@ -1123,17 +1137,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
 
-       if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) {
-               /*
-                * fail with EBUSY if there are still references to this
-                * directory.
-                */
-               dentry_unhash(new_dentry);
-               error = -EBUSY;
-               if (!d_unhashed(new_dentry))
-                       goto out;
-       }
-
        ncp_age_dentry(server, old_dentry);
        ncp_age_dentry(server, new_dentry);
 
index 26910c8154da1be65c0318eb088d5d69d3e08baf..0765ad12c3827cf9822dacc1875cb64a957c9864 100644 (file)
@@ -891,6 +891,10 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
        if (!server)    /* How this could happen? */
                goto out;
 
+       result = -EPERM;
+       if (IS_DEADDIR(dentry->d_inode))
+               goto out;
+
        /* ageing the dentry to force validation */
        ncp_age_dentry(server, dentry);
 
index ee24df5af1f929671ae0c6d8145d7951e767fc17..3c5dd55d284ce3baa24d3f2c4071ca53e883a223 100644 (file)
@@ -117,7 +117,7 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma)
                return -EINVAL;
        /* we do not support files bigger than 4GB... We eventually 
           supports just 4GB... */
-       if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff 
+       if (vma_pages(vma) + vma->vm_pgoff
           > (1U << (32 - PAGE_SHIFT)))
                return -EFBIG;
 
index cff089a412c7f4bde3bd2f1d5138a4679535b772..da6a43d19aa3a04f09eb3b9276bce3decea31ecb 100644 (file)
@@ -211,7 +211,6 @@ static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
        struct svc_rqst *rqstp;
        int (*callback_svc)(void *vrqstp);
        struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
-       char svc_name[12];
        int ret;
 
        nfs_callback_bc_serv(minorversion, xprt, serv);
@@ -235,10 +234,10 @@ static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
 
        svc_sock_update_bufs(serv);
 
-       sprintf(svc_name, "nfsv4.%u-svc", minorversion);
        cb_info->serv = serv;
        cb_info->rqst = rqstp;
-       cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name);
+       cb_info->task = kthread_run(callback_svc, cb_info->rqst,
+                                   "nfsv4.%u-svc", minorversion);
        if (IS_ERR(cb_info->task)) {
                ret = PTR_ERR(cb_info->task);
                svc_exit_thread(cb_info->rqst);
index 57db3244f4d967dd5479dbf3ab883c6d28cc2cbd..7ec4814e298d4d957fd4bfa17cb59de20e429ba9 100644 (file)
@@ -73,20 +73,20 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
        if (inode->i_flock == NULL)
                goto out;
 
-       /* Protect inode->i_flock using the file locks lock */
-       lock_flocks();
+       /* Protect inode->i_flock using the i_lock */
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
                        continue;
                if (nfs_file_open_context(fl->fl_file) != ctx)
                        continue;
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                status = nfs4_lock_delegation_recall(fl, state, stateid);
                if (status < 0)
                        goto out;
-               lock_flocks();
+               spin_lock(&inode->i_lock);
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 out:
        return status;
 }
index 5d051419527baafc06f2ec4644549469380a478d..d7ed697133f0b6c6ac667c4e3e334646a6a67b63 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/pagevec.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/swap.h>
 #include <linux/sched.h>
 #include <linux/kmemleak.h>
 #include <linux/xattr.h>
@@ -1758,7 +1759,6 @@ EXPORT_SYMBOL_GPL(nfs_unlink);
  */
 int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
-       struct pagevec lru_pvec;
        struct page *page;
        char *kaddr;
        struct iattr attr;
@@ -1798,11 +1798,8 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
         * No big deal if we can't add this page to the page cache here.
         * READLINK will get the missing page from the server if needed.
         */
-       pagevec_init(&lru_pvec, 0);
-       if (!add_to_page_cache(page, dentry->d_inode->i_mapping, 0,
+       if (!add_to_page_cache_lru(page, dentry->d_inode->i_mapping, 0,
                                                        GFP_KERNEL)) {
-               pagevec_add(&lru_pvec, page);
-               pagevec_lru_add_file(&lru_pvec);
                SetPageUptodate(page);
                unlock_page(page);
        } else
index 6b4a79f4ad1d30a0ddf036df224ab80594274f38..94e94bd11aae6d0a6c32acf5c16491448edb93f8 100644 (file)
@@ -495,6 +495,35 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
        return nfs_fscache_release_page(page, gfp);
 }
 
+static void nfs_check_dirty_writeback(struct page *page,
+                               bool *dirty, bool *writeback)
+{
+       struct nfs_inode *nfsi;
+       struct address_space *mapping = page_file_mapping(page);
+
+       if (!mapping || PageSwapCache(page))
+               return;
+
+       /*
+        * Check if an unstable page is currently being committed and
+        * if so, have the VM treat it as if the page is under writeback
+        * so it will not block due to pages that will shortly be freeable.
+        */
+       nfsi = NFS_I(mapping->host);
+       if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) {
+               *writeback = true;
+               return;
+       }
+
+       /*
+        * If PagePrivate() is set, then the page is not freeable and as the
+        * inode is not being committed, it's not going to be cleaned in the
+        * near future so treat it as dirty
+        */
+       if (PagePrivate(page))
+               *dirty = true;
+}
+
 /*
  * Attempt to clear the private state associated with a page when an error
  * occurs that requires the cached contents of an inode to be written back or
@@ -542,6 +571,7 @@ const struct address_space_operations nfs_file_aops = {
        .direct_IO = nfs_direct_IO,
        .migratepage = nfs_migrate_page,
        .launder_page = nfs_launder_page,
+       .is_dirty_writeback = nfs_check_dirty_writeback,
        .error_remove_page = generic_error_remove_page,
 #ifdef CONFIG_NFS_SWAP
        .swap_activate = nfs_swap_activate,
index c1c7a9d78722257867846f39c74780536b28d0c5..ce727047ee87786bcf4d20d8573a24a0990e2e62 100644 (file)
@@ -79,7 +79,7 @@ int nfs_wait_bit_killable(void *word)
 {
        if (fatal_signal_pending(current))
                return -ERESTARTSYS;
-       freezable_schedule();
+       freezable_schedule_unsafe();
        return 0;
 }
 EXPORT_SYMBOL_GPL(nfs_wait_bit_killable);
index 43ea96ced28cbc763a60048ab95cefcf737ecf40..ce90eb4775c2f888547bd98911062f8eede4af97 100644 (file)
@@ -33,7 +33,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
                res = rpc_call_sync(clnt, msg, flags);
                if (res != -EJUKEBOX)
                        break;
-               freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
+               freezable_schedule_timeout_killable_unsafe(NFS_JUKEBOX_RETRY_TIME);
                res = -ERESTARTSYS;
        } while (!fatal_signal_pending(current));
        return res;
index d7ba5616989c49fe52d396d41187a663744598f1..28241a42f363581341b3ed81de137fc0da1b428e 100644 (file)
@@ -268,7 +268,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
                *timeout = NFS4_POLL_RETRY_MIN;
        if (*timeout > NFS4_POLL_RETRY_MAX)
                *timeout = NFS4_POLL_RETRY_MAX;
-       freezable_schedule_timeout_killable(*timeout);
+       freezable_schedule_timeout_killable_unsafe(*timeout);
        if (fatal_signal_pending(current))
                res = -ERESTARTSYS;
        *timeout <<= 1;
@@ -4528,7 +4528,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
 static unsigned long
 nfs4_set_lock_task_retry(unsigned long timeout)
 {
-       freezable_schedule_timeout_killable(timeout);
+       freezable_schedule_timeout_killable_unsafe(timeout);
        timeout <<= 1;
        if (timeout > NFS4_LOCK_MAXTIMEOUT)
                return NFS4_LOCK_MAXTIMEOUT;
index 1fab140764c42756867f064a81b61903b8858a91..55418811a55aba706cf4682bd38f13818d816759 100644 (file)
@@ -1194,7 +1194,7 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
        snprintf(buf, sizeof(buf), "%s-manager",
                        rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
        rcu_read_unlock();
-       task = kthread_run(nfs4_run_state_manager, clp, buf);
+       task = kthread_run(nfs4_run_state_manager, clp, "%s", buf);
        if (IS_ERR(task)) {
                printk(KERN_ERR "%s: kthread_run: %ld\n",
                        __func__, PTR_ERR(task));
@@ -1373,13 +1373,13 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
        /* Guard against delegation returns and new lock/unlock calls */
        down_write(&nfsi->rwsem);
        /* Protect inode->i_flock using the BKL */
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
                        continue;
                if (nfs_file_open_context(fl->fl_file)->state != state)
                        continue;
-               unlock_flocks();
+               spin_unlock(&inode->i_lock);
                status = ops->recover_lock(state, fl);
                switch (status) {
                        case 0:
@@ -1406,9 +1406,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
                                /* kill_proc(fl->fl_pid, SIGLOST, 1); */
                                status = 0;
                }
-               lock_flocks();
+               spin_lock(&inode->i_lock);
        }
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
 out:
        up_write(&nfsi->rwsem);
        return status;
index 316ec843dec238b027ebf94629c1d56955b60731..f17051838b41aeda88075ac9f81f72f3a1559ce9 100644 (file)
@@ -2645,13 +2645,13 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
 
        list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
 
-       /* only place dl_time is set. protected by lock_flocks*/
+       /* Only place dl_time is set; protected by i_lock: */
        dp->dl_time = get_seconds();
 
        nfsd4_cb_recall(dp);
 }
 
-/* Called from break_lease() with lock_flocks() held. */
+/* Called from break_lease() with i_lock held. */
 static void nfsd_break_deleg_cb(struct file_lock *fl)
 {
        struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
@@ -4520,7 +4520,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
        struct inode *inode = filp->fi_inode;
        int status = 0;
 
-       lock_flocks();
+       spin_lock(&inode->i_lock);
        for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
                if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
                        status = 1;
@@ -4528,7 +4528,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
                }
        }
 out:
-       unlock_flocks();
+       spin_unlock(&inode->i_lock);
        return status;
 }
 
index eed4d7b262491ae8e48ee401f81f38e25f40ddb1..741fd02e04447fbcc44f2ad3733a1f509cba4c48 100644 (file)
@@ -397,6 +397,69 @@ nilfs_palloc_rest_groups_in_desc_block(const struct inode *inode,
                     max - curr + 1);
 }
 
+/**
+ * nilfs_palloc_count_desc_blocks - count descriptor blocks number
+ * @inode: inode of metadata file using this allocator
+ * @desc_blocks: descriptor blocks number [out]
+ */
+static int nilfs_palloc_count_desc_blocks(struct inode *inode,
+                                           unsigned long *desc_blocks)
+{
+       unsigned long blknum;
+       int ret;
+
+       ret = nilfs_bmap_last_key(NILFS_I(inode)->i_bmap, &blknum);
+       if (likely(!ret))
+               *desc_blocks = DIV_ROUND_UP(
+                       blknum, NILFS_MDT(inode)->mi_blocks_per_desc_block);
+       return ret;
+}
+
+/**
+ * nilfs_palloc_mdt_file_can_grow - check potential opportunity for
+ *                                     MDT file growing
+ * @inode: inode of metadata file using this allocator
+ * @desc_blocks: known current descriptor blocks count
+ */
+static inline bool nilfs_palloc_mdt_file_can_grow(struct inode *inode,
+                                                   unsigned long desc_blocks)
+{
+       return (nilfs_palloc_groups_per_desc_block(inode) * desc_blocks) <
+                       nilfs_palloc_groups_count(inode);
+}
+
+/**
+ * nilfs_palloc_count_max_entries - count max number of entries that can be
+ *                                     described by descriptor blocks count
+ * @inode: inode of metadata file using this allocator
+ * @nused: current number of used entries
+ * @nmaxp: max number of entries [out]
+ */
+int nilfs_palloc_count_max_entries(struct inode *inode, u64 nused, u64 *nmaxp)
+{
+       unsigned long desc_blocks = 0;
+       u64 entries_per_desc_block, nmax;
+       int err;
+
+       err = nilfs_palloc_count_desc_blocks(inode, &desc_blocks);
+       if (unlikely(err))
+               return err;
+
+       entries_per_desc_block = (u64)nilfs_palloc_entries_per_group(inode) *
+                               nilfs_palloc_groups_per_desc_block(inode);
+       nmax = entries_per_desc_block * desc_blocks;
+
+       if (nused == nmax &&
+                       nilfs_palloc_mdt_file_can_grow(inode, desc_blocks))
+               nmax += entries_per_desc_block;
+
+       if (nused > nmax)
+               return -ERANGE;
+
+       *nmaxp = nmax;
+       return 0;
+}
+
 /**
  * nilfs_palloc_prepare_alloc_entry - prepare to allocate a persistent object
  * @inode: inode of metadata file using this allocator
index fb7238100548e3e3ba1dcc0c75b362a930a22718..4bd6451b570398b25fa935fc2e080a24a546829a 100644 (file)
@@ -48,6 +48,8 @@ int nilfs_palloc_get_entry_block(struct inode *, __u64, int,
 void *nilfs_palloc_block_get_entry(const struct inode *, __u64,
                                   const struct buffer_head *, void *);
 
+int nilfs_palloc_count_max_entries(struct inode *, u64, u64 *);
+
 /**
  * nilfs_palloc_req - persistent allocator request and reply
  * @pr_entry_nr: entry number (vblocknr or inode number)
index d8e65bde083c0c46fb157d321d8ed63a6a6e0ad0..6548c7851b485450c6f33dce3eab35e1ff167d8d 100644 (file)
@@ -159,6 +159,28 @@ int nilfs_ifile_get_inode_block(struct inode *ifile, ino_t ino,
        return err;
 }
 
+/**
+ * nilfs_ifile_count_free_inodes - calculate free inodes count
+ * @ifile: ifile inode
+ * @nmaxinodes: current maximum of available inodes count [out]
+ * @nfreeinodes: free inodes count [out]
+ */
+int nilfs_ifile_count_free_inodes(struct inode *ifile,
+                                   u64 *nmaxinodes, u64 *nfreeinodes)
+{
+       u64 nused;
+       int err;
+
+       *nmaxinodes = 0;
+       *nfreeinodes = 0;
+
+       nused = atomic64_read(&NILFS_I(ifile)->i_root->inodes_count);
+       err = nilfs_palloc_count_max_entries(ifile, nused, nmaxinodes);
+       if (likely(!err))
+               *nfreeinodes = *nmaxinodes - nused;
+       return err;
+}
+
 /**
  * nilfs_ifile_read - read or get ifile inode
  * @sb: super block instance
index 59b6f2b51df6e7c7e1ef659e7a806f294bbc58ad..679674d13372accd37a57a8fb78d026ca32f194a 100644 (file)
@@ -49,6 +49,8 @@ int nilfs_ifile_create_inode(struct inode *, ino_t *, struct buffer_head **);
 int nilfs_ifile_delete_inode(struct inode *, ino_t);
 int nilfs_ifile_get_inode_block(struct inode *, ino_t, struct buffer_head **);
 
+int nilfs_ifile_count_free_inodes(struct inode *, u64 *, u64 *);
+
 int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
                     size_t inode_size, struct nilfs_inode *raw_inode,
                     struct inode **inodep);
index bccfec8343c5ee34925cea97b8fc4006f8265084..b1a5277cfd182adcbfda860ad395e07a14f94db8 100644 (file)
@@ -54,7 +54,7 @@ void nilfs_inode_add_blocks(struct inode *inode, int n)
 
        inode_add_bytes(inode, (1 << inode->i_blkbits) * n);
        if (root)
-               atomic_add(n, &root->blocks_count);
+               atomic64_add(n, &root->blocks_count);
 }
 
 void nilfs_inode_sub_blocks(struct inode *inode, int n)
@@ -63,7 +63,7 @@ void nilfs_inode_sub_blocks(struct inode *inode, int n)
 
        inode_sub_bytes(inode, (1 << inode->i_blkbits) * n);
        if (root)
-               atomic_sub(n, &root->blocks_count);
+               atomic64_sub(n, &root->blocks_count);
 }
 
 /**
@@ -369,7 +369,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode)
                goto failed_ifile_create_inode;
        /* reference count of i_bh inherits from nilfs_mdt_read_block() */
 
-       atomic_inc(&root->inodes_count);
+       atomic64_inc(&root->inodes_count);
        inode_init_owner(inode, dir, mode);
        inode->i_ino = ino;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
@@ -801,7 +801,7 @@ void nilfs_evict_inode(struct inode *inode)
 
        ret = nilfs_ifile_delete_inode(ii->i_root->ifile, inode->i_ino);
        if (!ret)
-               atomic_dec(&ii->i_root->inodes_count);
+               atomic64_dec(&ii->i_root->inodes_count);
 
        nilfs_clear_inode(inode);
 
index a5752a589932d936b12cfdda27a6fb718e6cfb51..bd88a7461063bba02f31c6f873902c9c8e87e943 100644 (file)
@@ -835,9 +835,9 @@ static int nilfs_segctor_fill_in_checkpoint(struct nilfs_sc_info *sci)
        raw_cp->cp_snapshot_list.ssl_next = 0;
        raw_cp->cp_snapshot_list.ssl_prev = 0;
        raw_cp->cp_inodes_count =
-               cpu_to_le64(atomic_read(&sci->sc_root->inodes_count));
+               cpu_to_le64(atomic64_read(&sci->sc_root->inodes_count));
        raw_cp->cp_blocks_count =
-               cpu_to_le64(atomic_read(&sci->sc_root->blocks_count));
+               cpu_to_le64(atomic64_read(&sci->sc_root->blocks_count));
        raw_cp->cp_nblk_inc =
                cpu_to_le64(sci->sc_nblk_inc + sci->sc_nblk_this_inc);
        raw_cp->cp_create = cpu_to_le64(sci->sc_seg_ctime);
index c7d1f9f18b094fb1f281fb0dfcb6b53328dc72fe..1427de5ebf4d7d2a66d05d3ef0b164ef4a9312d5 100644 (file)
@@ -554,8 +554,10 @@ int nilfs_attach_checkpoint(struct super_block *sb, __u64 cno, int curr_mnt,
        if (err)
                goto failed_bh;
 
-       atomic_set(&root->inodes_count, le64_to_cpu(raw_cp->cp_inodes_count));
-       atomic_set(&root->blocks_count, le64_to_cpu(raw_cp->cp_blocks_count));
+       atomic64_set(&root->inodes_count,
+                       le64_to_cpu(raw_cp->cp_inodes_count));
+       atomic64_set(&root->blocks_count,
+                       le64_to_cpu(raw_cp->cp_blocks_count));
 
        nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp);
 
@@ -609,6 +611,7 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        unsigned long overhead;
        unsigned long nrsvblocks;
        sector_t nfreeblocks;
+       u64 nmaxinodes, nfreeinodes;
        int err;
 
        /*
@@ -633,14 +636,34 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        if (unlikely(err))
                return err;
 
+       err = nilfs_ifile_count_free_inodes(root->ifile,
+                                           &nmaxinodes, &nfreeinodes);
+       if (unlikely(err)) {
+               printk(KERN_WARNING
+                       "NILFS warning: fail to count free inodes: err %d.\n",
+                       err);
+               if (err == -ERANGE) {
+                       /*
+                        * If nilfs_palloc_count_max_entries() returns
+                        * -ERANGE error code then we simply treat
+                        * curent inodes count as maximum possible and
+                        * zero as free inodes value.
+                        */
+                       nmaxinodes = atomic64_read(&root->inodes_count);
+                       nfreeinodes = 0;
+                       err = 0;
+               } else
+                       return err;
+       }
+
        buf->f_type = NILFS_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
        buf->f_blocks = blocks - overhead;
        buf->f_bfree = nfreeblocks;
        buf->f_bavail = (buf->f_bfree >= nrsvblocks) ?
                (buf->f_bfree - nrsvblocks) : 0;
-       buf->f_files = atomic_read(&root->inodes_count);
-       buf->f_ffree = 0; /* nilfs_count_free_inodes(sb); */
+       buf->f_files = nmaxinodes;
+       buf->f_ffree = nfreeinodes;
        buf->f_namelen = NILFS_NAME_LEN;
        buf->f_fsid.val[0] = (u32)id;
        buf->f_fsid.val[1] = (u32)(id >> 32);
index 41e6a04a561f36ac1bd190b80dd2c10def4cf176..94c451ce6d247b5ca0e284a8667308d6509d0741 100644 (file)
@@ -764,8 +764,8 @@ nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno)
        new->ifile = NULL;
        new->nilfs = nilfs;
        atomic_set(&new->count, 1);
-       atomic_set(&new->inodes_count, 0);
-       atomic_set(&new->blocks_count, 0);
+       atomic64_set(&new->inodes_count, 0);
+       atomic64_set(&new->blocks_count, 0);
 
        rb_link_node(&new->rb_node, parent, p);
        rb_insert_color(&new->rb_node, &nilfs->ns_cptree);
index be1267a34ceae883b7d705c967347ad4a4185b57..de8cc53b4a5c1f5e246ad77b540345184479c5cf 100644 (file)
@@ -241,8 +241,8 @@ struct nilfs_root {
        struct the_nilfs *nilfs;
        struct inode *ifile;
 
-       atomic_t inodes_count;
-       atomic_t blocks_count;
+       atomic64_t inodes_count;
+       atomic64_t blocks_count;
 };
 
 /* Special checkpoint number */
index 6c80083a984fc192ebc73bad2a2edc86b4c25e11..1ea52f7c031fbd2aed6247ec445d10103ec973ad 100644 (file)
@@ -399,9 +399,6 @@ static int fanotify_release(struct inode *ignored, struct file *file)
        wake_up(&group->fanotify_data.access_waitq);
 #endif
 
-       if (file->f_flags & FASYNC)
-               fsnotify_fasync(-1, file, 0);
-
        /* matches the fanotify_init->fsnotify_alloc_group */
        fsnotify_destroy_group(group);
 
index b8a9d87231b1badec1fb31f27c84265ca708aa55..17e6bdde96c5e4707a29906e207e981761ca49c8 100644 (file)
@@ -5655,7 +5655,7 @@ int ocfs2_remove_btree_range(struct inode *inode,
                                               &ref_tree, NULL);
                if (ret) {
                        mlog_errno(ret);
-                       goto out;
+                       goto bail;
                }
 
                ret = ocfs2_prepare_refcount_change_for_del(inode,
@@ -5666,7 +5666,7 @@ int ocfs2_remove_btree_range(struct inode *inode,
                                                            &extra_blocks);
                if (ret < 0) {
                        mlog_errno(ret);
-                       goto out;
+                       goto bail;
                }
        }
 
@@ -5674,7 +5674,7 @@ int ocfs2_remove_btree_range(struct inode *inode,
                                                 extra_blocks);
        if (ret) {
                mlog_errno(ret);
-               return ret;
+               goto bail;
        }
 
        mutex_lock(&tl_inode->i_mutex);
@@ -5734,7 +5734,7 @@ out_commit:
        ocfs2_commit_trans(osb, handle);
 out:
        mutex_unlock(&tl_inode->i_mutex);
-
+bail:
        if (meta_ac)
                ocfs2_free_alloc_context(meta_ac);
 
index 42252bf64b5127f39eecb25a7aecd6f1cd57e511..5c1c864e81cc0dbcb0cd2f358f52f3c62ae6907d 100644 (file)
@@ -176,7 +176,7 @@ static void o2hb_dead_threshold_set(unsigned int threshold)
        }
 }
 
-static int o2hb_global_hearbeat_mode_set(unsigned int hb_mode)
+static int o2hb_global_heartbeat_mode_set(unsigned int hb_mode)
 {
        int ret = -1;
 
@@ -500,7 +500,7 @@ static int o2hb_issue_node_write(struct o2hb_region *reg,
        }
 
        atomic_inc(&write_wc->wc_num_reqs);
-       submit_bio(WRITE, bio);
+       submit_bio(WRITE_SYNC, bio);
 
        status = 0;
 bail:
@@ -2271,7 +2271,7 @@ ssize_t o2hb_heartbeat_group_mode_store(struct o2hb_heartbeat_group *group,
                if (strnicmp(page, o2hb_heartbeat_mode_desc[i], len))
                        continue;
 
-               ret = o2hb_global_hearbeat_mode_set(i);
+               ret = o2hb_global_heartbeat_mode_set(i);
                if (!ret)
                        printk(KERN_NOTICE "o2hb: Heartbeat mode set to %s\n",
                               o2hb_heartbeat_mode_desc[i]);
@@ -2304,7 +2304,7 @@ static struct configfs_attribute *o2hb_heartbeat_group_attrs[] = {
        NULL,
 };
 
-static struct configfs_item_operations o2hb_hearbeat_group_item_ops = {
+static struct configfs_item_operations o2hb_heartbeat_group_item_ops = {
        .show_attribute         = o2hb_heartbeat_group_show,
        .store_attribute        = o2hb_heartbeat_group_store,
 };
@@ -2316,7 +2316,7 @@ static struct configfs_group_operations o2hb_heartbeat_group_group_ops = {
 
 static struct config_item_type o2hb_heartbeat_group_type = {
        .ct_group_ops   = &o2hb_heartbeat_group_group_ops,
-       .ct_item_ops    = &o2hb_hearbeat_group_item_ops,
+       .ct_item_ops    = &o2hb_heartbeat_group_item_ops,
        .ct_attrs       = o2hb_heartbeat_group_attrs,
        .ct_owner       = THIS_MODULE,
 };
@@ -2389,6 +2389,9 @@ static int o2hb_region_pin(const char *region_uuid)
        assert_spin_locked(&o2hb_live_lock);
 
        list_for_each_entry(reg, &o2hb_all_regions, hr_all_item) {
+               if (reg->hr_item_dropped)
+                       continue;
+
                uuid = config_item_name(&reg->hr_item);
 
                /* local heartbeat */
@@ -2439,6 +2442,9 @@ static void o2hb_region_unpin(const char *region_uuid)
        assert_spin_locked(&o2hb_live_lock);
 
        list_for_each_entry(reg, &o2hb_all_regions, hr_all_item) {
+               if (reg->hr_item_dropped)
+                       continue;
+
                uuid = config_item_name(&reg->hr_item);
                if (region_uuid) {
                        if (strcmp(region_uuid, uuid))
@@ -2654,6 +2660,9 @@ int o2hb_get_all_regions(char *region_uuids, u8 max_regions)
 
        p = region_uuids;
        list_for_each_entry(reg, &o2hb_all_regions, hr_all_item) {
+               if (reg->hr_item_dropped)
+                       continue;
+
                mlog(0, "Region: %s\n", config_item_name(&reg->hr_item));
                if (numregs < max_regions) {
                        memcpy(p, config_item_name(&reg->hr_item),
index c19897d0fe142a5a9926da9552572daf78982938..1ec141e758d73497288f35a13f4e7a965f381a30 100644 (file)
@@ -264,7 +264,7 @@ void o2quo_hb_still_up(u8 node)
 /* This is analogous to hb_up.  as a node's connection comes up we delay the
  * quorum decision until we see it heartbeating.  the hold will be droped in
  * hb_up or hb_down.  it might be perpetuated by con_err until hb_down.  if
- * it's already heartbeating we we might be dropping a hold that conn_up got.
+ * it's already heartbeating we might be dropping a hold that conn_up got.
  * */
 void o2quo_conn_up(u8 node)
 {
index aa88bd8bcedc6733b89e1ceeb705adcfbb57242f..d644dc611425a4b71680b1ecbc76c37a1b0f15cf 100644 (file)
@@ -406,6 +406,9 @@ static void sc_kref_release(struct kref *kref)
        sc->sc_node = NULL;
 
        o2net_debug_del_sc(sc);
+
+       if (sc->sc_page)
+               __free_page(sc->sc_page);
        kfree(sc);
 }
 
@@ -630,19 +633,19 @@ static void o2net_state_change(struct sock *sk)
        state_change = sc->sc_state_change;
 
        switch(sk->sk_state) {
-               /* ignore connecting sockets as they make progress */
-               case TCP_SYN_SENT:
-               case TCP_SYN_RECV:
-                       break;
-               case TCP_ESTABLISHED:
-                       o2net_sc_queue_work(sc, &sc->sc_connect_work);
-                       break;
-               default:
-                       printk(KERN_INFO "o2net: Connection to " SC_NODEF_FMT
-                             " shutdown, state %d\n",
-                             SC_NODEF_ARGS(sc), sk->sk_state);
-                       o2net_sc_queue_work(sc, &sc->sc_shutdown_work);
-                       break;
+       /* ignore connecting sockets as they make progress */
+       case TCP_SYN_SENT:
+       case TCP_SYN_RECV:
+               break;
+       case TCP_ESTABLISHED:
+               o2net_sc_queue_work(sc, &sc->sc_connect_work);
+               break;
+       default:
+               printk(KERN_INFO "o2net: Connection to " SC_NODEF_FMT
+                       " shutdown, state %d\n",
+                       SC_NODEF_ARGS(sc), sk->sk_state);
+               o2net_sc_queue_work(sc, &sc->sc_shutdown_work);
+               break;
        }
 out:
        read_unlock(&sk->sk_callback_lock);
index 975810b98492a34f4576b9d3d3ac3e4421fb18c1..47e67c2d228feff6259aa6d2a47b4b7c7b2ee103 100644 (file)
@@ -178,6 +178,7 @@ static enum dlm_status dlmlock_master(struct dlm_ctxt *dlm,
                                     lock->ml.node);
                        }
                } else {
+                       status = DLM_NORMAL;
                        dlm_lock_get(lock);
                        list_add_tail(&lock->list, &res->blocked);
                        kick_thread = 1;
index e68588e6b1e8eeb2f491f7b10b1c5a84d8ccb910..773bd32bfd8c8bb56bcf5f7ee7880cd65bbe8f26 100644 (file)
@@ -55,9 +55,6 @@
 static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node);
 
 static int dlm_recovery_thread(void *data);
-void dlm_complete_recovery_thread(struct dlm_ctxt *dlm);
-int dlm_launch_recovery_thread(struct dlm_ctxt *dlm);
-void dlm_kick_recovery_thread(struct dlm_ctxt *dlm);
 static int dlm_do_recovery(struct dlm_ctxt *dlm);
 
 static int dlm_pick_recovery_master(struct dlm_ctxt *dlm);
@@ -789,7 +786,7 @@ static int dlm_request_all_locks(struct dlm_ctxt *dlm, u8 request_from,
                                 u8 dead_node)
 {
        struct dlm_lock_request lr;
-       enum dlm_status ret;
+       int ret;
 
        mlog(0, "\n");
 
@@ -802,7 +799,6 @@ static int dlm_request_all_locks(struct dlm_ctxt *dlm, u8 request_from,
        lr.dead_node = dead_node;
 
        // send message
-       ret = DLM_NOLOCKMGR;
        ret = o2net_send_message(DLM_LOCK_REQUEST_MSG, dlm->key,
                                 &lr, sizeof(lr), request_from, NULL);
 
@@ -2696,6 +2692,7 @@ int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data,
                     dlm->name, br->node_idx, br->dead_node,
                     dlm->reco.dead_node, dlm->reco.new_master);
                spin_unlock(&dlm->spinlock);
+               dlm_put(dlm);
                return -EAGAIN;
        }
        spin_unlock(&dlm->spinlock);
index 8a38714f1d92ec98b197e28e1a06adcce6e6b582..41000f223ca42bb855a57f1cc27f08a28ecccba9 100644 (file)
@@ -2646,17 +2646,7 @@ static loff_t ocfs2_file_llseek(struct file *file, loff_t offset, int whence)
                goto out;
        }
 
-       if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
-               ret = -EINVAL;
-       if (!ret && offset > inode->i_sb->s_maxbytes)
-               ret = -EINVAL;
-       if (ret)
-               goto out;
-
-       if (offset != file->f_pos) {
-               file->f_pos = offset;
-               file->f_version = 0;
-       }
+       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out:
        mutex_unlock(&inode->i_mutex);
index a3385b63ff5e542bcfaabe59744fa3af38b537e4..96f9ac237e86dbc301339c07b882bbff508f9143 100644 (file)
@@ -200,7 +200,6 @@ void ocfs2_complete_quota_recovery(struct ocfs2_super *osb);
 
 static inline void ocfs2_start_checkpoint(struct ocfs2_super *osb)
 {
-       atomic_set(&osb->needs_checkpoint, 1);
        wake_up(&osb->checkpoint_event);
 }
 
@@ -538,7 +537,7 @@ static inline int ocfs2_calc_extend_credits(struct super_block *sb,
        extent_blocks = 1 + 1 + le16_to_cpu(root_el->l_tree_depth);
 
        return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks +
-              ocfs2_quota_trans_credits(sb);
+              ocfs2_quota_trans_credits(sb) + bits_wanted;
 }
 
 static inline int ocfs2_calc_symlink_credits(struct super_block *sb)
index b4a5cdf9dbc57339b29530b343b5a582bcb39e36..be3f8676a4385970f0edc92fff291c997c3d2823 100644 (file)
@@ -522,7 +522,7 @@ static int __ocfs2_mknod_locked(struct inode *dir,
 
        fe->i_last_eb_blk = 0;
        strcpy(fe->i_signature, OCFS2_INODE_SIGNATURE);
-       le32_add_cpu(&fe->i_flags, OCFS2_VALID_FL);
+       fe->i_flags |= cpu_to_le32(OCFS2_VALID_FL);
        fe->i_atime = fe->i_ctime = fe->i_mtime =
                cpu_to_le64(CURRENT_TIME.tv_sec);
        fe->i_mtime_nsec = fe->i_ctime_nsec = fe->i_atime_nsec =
@@ -773,7 +773,7 @@ static int ocfs2_remote_dentry_delete(struct dentry *dentry)
        return ret;
 }
 
-static inline int inode_is_unlinkable(struct inode *inode)
+static inline int ocfs2_inode_is_unlinkable(struct inode *inode)
 {
        if (S_ISDIR(inode->i_mode)) {
                if (inode->i_nlink == 2)
@@ -791,6 +791,7 @@ static int ocfs2_unlink(struct inode *dir,
 {
        int status;
        int child_locked = 0;
+       bool is_unlinkable = false;
        struct inode *inode = dentry->d_inode;
        struct inode *orphan_dir = NULL;
        struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
@@ -865,7 +866,7 @@ static int ocfs2_unlink(struct inode *dir,
                goto leave;
        }
 
-       if (inode_is_unlinkable(inode)) {
+       if (ocfs2_inode_is_unlinkable(inode)) {
                status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
                                                  OCFS2_I(inode)->ip_blkno,
                                                  orphan_name, &orphan_insert);
@@ -873,6 +874,7 @@ static int ocfs2_unlink(struct inode *dir,
                        mlog_errno(status);
                        goto leave;
                }
+               is_unlinkable = true;
        }
 
        handle = ocfs2_start_trans(osb, ocfs2_unlink_credits(osb->sb));
@@ -892,15 +894,6 @@ static int ocfs2_unlink(struct inode *dir,
 
        fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
-       if (inode_is_unlinkable(inode)) {
-               status = ocfs2_orphan_add(osb, handle, inode, fe_bh, orphan_name,
-                                         &orphan_insert, orphan_dir);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto leave;
-               }
-       }
-
        /* delete the name from the parent dir */
        status = ocfs2_delete_entry(handle, dir, &lookup);
        if (status < 0) {
@@ -923,6 +916,14 @@ static int ocfs2_unlink(struct inode *dir,
                mlog_errno(status);
                if (S_ISDIR(inode->i_mode))
                        inc_nlink(dir);
+               goto leave;
+       }
+
+       if (is_unlinkable) {
+               status = ocfs2_orphan_add(osb, handle, inode, fe_bh,
+                               orphan_name, &orphan_insert, orphan_dir);
+               if (status < 0)
+                       mlog_errno(status);
        }
 
 leave:
@@ -2012,6 +2013,21 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
                goto leave;
        }
 
+       /*
+        * We're going to journal the change of i_flags and i_orphaned_slot.
+        * It's safe anyway, though some callers may duplicate the journaling.
+        * Journaling within the func just make the logic look more
+        * straightforward.
+        */
+       status = ocfs2_journal_access_di(handle,
+                                        INODE_CACHE(inode),
+                                        fe_bh,
+                                        OCFS2_JOURNAL_ACCESS_WRITE);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
        /* we're a cluster, and nlink can change on disk from
         * underneath us... */
        orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data;
@@ -2026,25 +2042,10 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
                                   orphan_dir_bh, lookup);
        if (status < 0) {
                mlog_errno(status);
-               goto leave;
-       }
-
-       /*
-        * We're going to journal the change of i_flags and i_orphaned_slot.
-        * It's safe anyway, though some callers may duplicate the journaling.
-        * Journaling within the func just make the logic look more
-        * straightforward.
-        */
-       status = ocfs2_journal_access_di(handle,
-                                        INODE_CACHE(inode),
-                                        fe_bh,
-                                        OCFS2_JOURNAL_ACCESS_WRITE);
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
+               goto rollback;
        }
 
-       le32_add_cpu(&fe->i_flags, OCFS2_ORPHANED_FL);
+       fe->i_flags |= cpu_to_le32(OCFS2_ORPHANED_FL);
        OCFS2_I(inode)->ip_flags &= ~OCFS2_INODE_SKIP_ORPHAN_DIR;
 
        /* Record which orphan dir our inode now resides
@@ -2057,11 +2058,16 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
        trace_ocfs2_orphan_add_end((unsigned long long)OCFS2_I(inode)->ip_blkno,
                                   osb->slot_num);
 
+rollback:
+       if (status < 0) {
+               if (S_ISDIR(inode->i_mode))
+                       ocfs2_add_links_count(orphan_fe, -1);
+               set_nlink(orphan_dir_inode, ocfs2_read_links_count(orphan_fe));
+       }
+
 leave:
        brelse(orphan_dir_bh);
 
-       if (status)
-               mlog_errno(status);
        return status;
 }
 
@@ -2434,7 +2440,7 @@ int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
        }
 
        di = (struct ocfs2_dinode *)di_bh->b_data;
-       le32_add_cpu(&di->i_flags, -OCFS2_ORPHANED_FL);
+       di->i_flags &= ~cpu_to_le32(OCFS2_ORPHANED_FL);
        di->i_orphaned_slot = 0;
        set_nlink(inode, 1);
        ocfs2_set_links_count(di, inode->i_nlink);
index d355e6e36b366bfe7dc8cc91cbabdad05976ba2c..3a903470c794ec61dace1c03f9446cfe5f388e9c 100644 (file)
@@ -347,7 +347,6 @@ struct ocfs2_super
        struct task_struct *recovery_thread_task;
        int disable_recovery;
        wait_queue_head_t checkpoint_event;
-       atomic_t needs_checkpoint;
        struct ocfs2_journal *journal;
        unsigned long osb_commit_interval;
 
index b7e74b580c0f98bdbdf116ab6d43a45d5a3e0ed7..5397c07ce6080b8f6e3c5917225eba98a070a4ba 100644 (file)
@@ -1422,7 +1422,7 @@ static int ocfs2_relink_block_group(handle_t *handle,
        int status;
        /* there is a really tiny chance the journal calls could fail,
         * but we wouldn't want inconsistent blocks in *any* case. */
-       u64 fe_ptr, bg_ptr, prev_bg_ptr;
+       u64 bg_ptr, prev_bg_ptr;
        struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data;
        struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data;
        struct ocfs2_group_desc *prev_bg = (struct ocfs2_group_desc *) prev_bg_bh->b_data;
@@ -1437,51 +1437,44 @@ static int ocfs2_relink_block_group(handle_t *handle,
                (unsigned long long)le64_to_cpu(bg->bg_blkno),
                (unsigned long long)le64_to_cpu(prev_bg->bg_blkno));
 
-       fe_ptr = le64_to_cpu(fe->id2.i_chain.cl_recs[chain].c_blkno);
        bg_ptr = le64_to_cpu(bg->bg_next_group);
        prev_bg_ptr = le64_to_cpu(prev_bg->bg_next_group);
 
        status = ocfs2_journal_access_gd(handle, INODE_CACHE(alloc_inode),
                                         prev_bg_bh,
                                         OCFS2_JOURNAL_ACCESS_WRITE);
-       if (status < 0) {
-               mlog_errno(status);
-               goto out_rollback;
-       }
+       if (status < 0)
+               goto out;
 
        prev_bg->bg_next_group = bg->bg_next_group;
        ocfs2_journal_dirty(handle, prev_bg_bh);
 
        status = ocfs2_journal_access_gd(handle, INODE_CACHE(alloc_inode),
                                         bg_bh, OCFS2_JOURNAL_ACCESS_WRITE);
-       if (status < 0) {
-               mlog_errno(status);
-               goto out_rollback;
-       }
+       if (status < 0)
+               goto out_rollback_prev_bg;
 
        bg->bg_next_group = fe->id2.i_chain.cl_recs[chain].c_blkno;
        ocfs2_journal_dirty(handle, bg_bh);
 
        status = ocfs2_journal_access_di(handle, INODE_CACHE(alloc_inode),
                                         fe_bh, OCFS2_JOURNAL_ACCESS_WRITE);
-       if (status < 0) {
-               mlog_errno(status);
-               goto out_rollback;
-       }
+       if (status < 0)
+               goto out_rollback_bg;
 
        fe->id2.i_chain.cl_recs[chain].c_blkno = bg->bg_blkno;
        ocfs2_journal_dirty(handle, fe_bh);
 
-out_rollback:
-       if (status < 0) {
-               fe->id2.i_chain.cl_recs[chain].c_blkno = cpu_to_le64(fe_ptr);
-               bg->bg_next_group = cpu_to_le64(bg_ptr);
-               prev_bg->bg_next_group = cpu_to_le64(prev_bg_ptr);
-       }
-
-       if (status)
+out:
+       if (status < 0)
                mlog_errno(status);
        return status;
+
+out_rollback_bg:
+       bg->bg_next_group = cpu_to_le64(bg_ptr);
+out_rollback_prev_bg:
+       prev_bg->bg_next_group = cpu_to_le64(prev_bg_ptr);
+       goto out;
 }
 
 static inline int ocfs2_block_group_reasonably_empty(struct ocfs2_group_desc *bg,
index 01b85165552b75f1cf2e17893bea1054eb19ff81..854d80955bf8e66ea088a879d9faaf9178781441 100644 (file)
@@ -286,10 +286,9 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
        spin_unlock(&osb->osb_lock);
 
        out += snprintf(buf + out, len - out,
-                       "%10s => Pid: %d  Interval: %lu  Needs: %d\n", "Commit",
+                       "%10s => Pid: %d  Interval: %lu\n", "Commit",
                        (osb->commit_task ? task_pid_nr(osb->commit_task) : -1),
-                       osb->osb_commit_interval,
-                       atomic_read(&osb->needs_checkpoint));
+                       osb->osb_commit_interval);
 
        out += snprintf(buf + out, len - out,
                        "%10s => State: %d  TxnId: %lu  NumTxns: %d\n",
@@ -2154,7 +2153,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
        }
 
        init_waitqueue_head(&osb->checkpoint_event);
-       atomic_set(&osb->needs_checkpoint, 0);
 
        osb->s_atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
 
index 2e3ea308c14430640fe3a28f35d5149fc3d7cdf0..317ef0abccbbd22bf320c31ddc0c99ba9f4aa713 100644 (file)
@@ -2751,20 +2751,12 @@ static int ocfs2_xattr_ibody_set(struct inode *inode,
 {
        int ret;
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
-       struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
        struct ocfs2_xa_loc loc;
 
        if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
                return -ENOSPC;
 
        down_write(&oi->ip_alloc_sem);
-       if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
-               if (!ocfs2_xattr_has_space_inline(inode, di)) {
-                       ret = -ENOSPC;
-                       goto out;
-               }
-       }
-
        if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
                ret = ocfs2_xattr_ibody_init(inode, xs->inode_bh, ctxt);
                if (ret) {
@@ -6499,6 +6491,16 @@ static int ocfs2_reflink_xattr_inline(struct ocfs2_xattr_reflink *args)
        }
 
        new_oi = OCFS2_I(args->new_inode);
+       /*
+        * Adjust extent record count to reserve space for extended attribute.
+        * Inline data count had been adjusted in ocfs2_duplicate_inline_data().
+        */
+       if (!(new_oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) &&
+           !(ocfs2_inode_is_fast_symlink(args->new_inode))) {
+               struct ocfs2_extent_list *el = &new_di->id2.i_list;
+               le16_add_cpu(&el->l_count, -(inline_size /
+                                       sizeof(struct ocfs2_extent_rec)));
+       }
        spin_lock(&new_oi->ip_lock);
        new_oi->ip_dyn_features |= OCFS2_HAS_XATTR_FL | OCFS2_INLINE_XATTR_FL;
        new_di->i_dyn_features = cpu_to_le16(new_oi->ip_dyn_features);
index 8c741002f947908d26788ad83c91f28bc44c8295..fca72c4d3f17ac13758ac5315e413d749bf7667b 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -840,11 +840,15 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
        if (flags & __O_SYNC)
                flags |= O_DSYNC;
 
-       /*
-        * If we have O_PATH in the open flag. Then we
-        * cannot have anything other than the below set of flags
-        */
-       if (flags & O_PATH) {
+       if (flags & O_TMPFILE) {
+               if (!(flags & O_CREAT))
+                       return -EINVAL;
+               acc_mode = MAY_OPEN | ACC_MODE(flags);
+       } else if (flags & O_PATH) {
+               /*
+                * If we have O_PATH in the open flag. Then we
+                * cannot have anything other than the below set of flags
+                */
                flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
                acc_mode = 0;
        } else {
@@ -876,7 +880,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
                lookup_flags |= LOOKUP_DIRECTORY;
        if (!(flags & O_NOFOLLOW))
                lookup_flags |= LOOKUP_FOLLOW;
-       return lookup_flags;
+       op->lookup_flags = lookup_flags;
+       return 0;
 }
 
 /**
@@ -893,8 +898,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
 struct file *file_open_name(struct filename *name, int flags, umode_t mode)
 {
        struct open_flags op;
-       int lookup = build_open_flags(flags, mode, &op);
-       return do_filp_open(AT_FDCWD, name, &op, lookup);
+       int err = build_open_flags(flags, mode, &op);
+       return err ? ERR_PTR(err) : do_filp_open(AT_FDCWD, name, &op);
 }
 
 /**
@@ -919,37 +924,43 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
                            const char *filename, int flags)
 {
        struct open_flags op;
-       int lookup = build_open_flags(flags, 0, &op);
+       int err = build_open_flags(flags, 0, &op);
+       if (err)
+               return ERR_PTR(err);
        if (flags & O_CREAT)
                return ERR_PTR(-EINVAL);
        if (!filename && (flags & O_DIRECTORY))
                if (!dentry->d_inode->i_op->lookup)
                        return ERR_PTR(-ENOTDIR);
-       return do_file_open_root(dentry, mnt, filename, &op, lookup);
+       return do_file_open_root(dentry, mnt, filename, &op);
 }
 EXPORT_SYMBOL(file_open_root);
 
 long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
 {
        struct open_flags op;
-       int lookup = build_open_flags(flags, mode, &op);
-       struct filename *tmp = getname(filename);
-       int fd = PTR_ERR(tmp);
-
-       if (!IS_ERR(tmp)) {
-               fd = get_unused_fd_flags(flags);
-               if (fd >= 0) {
-                       struct file *f = do_filp_open(dfd, tmp, &op, lookup);
-                       if (IS_ERR(f)) {
-                               put_unused_fd(fd);
-                               fd = PTR_ERR(f);
-                       } else {
-                               fsnotify_open(f);
-                               fd_install(fd, f);
-                       }
+       int fd = build_open_flags(flags, mode, &op);
+       struct filename *tmp;
+
+       if (fd)
+               return fd;
+
+       tmp = getname(filename);
+       if (IS_ERR(tmp))
+               return PTR_ERR(tmp);
+
+       fd = get_unused_fd_flags(flags);
+       if (fd >= 0) {
+               struct file *f = do_filp_open(dfd, tmp, &op);
+               if (IS_ERR(f)) {
+                       put_unused_fd(fd);
+                       fd = PTR_ERR(f);
+               } else {
+                       fsnotify_open(f);
+                       fd_install(fd, f);
                }
-               putname(tmp);
        }
+       putname(tmp);
        return fd;
 }
 
index 0016350ad95e13a646978f8d3f19fb1afa145424..1485e38daaa38100278f56e710a8233338693fd5 100644 (file)
@@ -1686,41 +1686,29 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx,
        instantiate_t instantiate, struct task_struct *task, const void *ptr)
 {
        struct dentry *child, *dir = file->f_path.dentry;
+       struct qstr qname = QSTR_INIT(name, len);
        struct inode *inode;
-       struct qstr qname;
-       ino_t ino = 0;
-       unsigned type = DT_UNKNOWN;
+       unsigned type;
+       ino_t ino;
 
-       qname.name = name;
-       qname.len  = len;
-       qname.hash = full_name_hash(name, len);
-
-       child = d_lookup(dir, &qname);
+       child = d_hash_and_lookup(dir, &qname);
        if (!child) {
-               struct dentry *new;
-               new = d_alloc(dir, &qname);
-               if (new) {
-                       child = instantiate(dir->d_inode, new, task, ptr);
-                       if (child)
-                               dput(new);
-                       else
-                               child = new;
+               child = d_alloc(dir, &qname);
+               if (!child)
+                       goto end_instantiate;
+               if (instantiate(dir->d_inode, child, task, ptr) < 0) {
+                       dput(child);
+                       goto end_instantiate;
                }
        }
-       if (!child || IS_ERR(child) || !child->d_inode)
-               goto end_instantiate;
        inode = child->d_inode;
-       if (inode) {
-               ino = inode->i_ino;
-               type = inode->i_mode >> 12;
-       }
+       ino = inode->i_ino;
+       type = inode->i_mode >> 12;
        dput(child);
-end_instantiate:
-       if (!ino)
-               ino = find_inode_number(dir, &qname);
-       if (!ino)
-               ino = 1;
        return dir_emit(ctx, name, len, ino, type);
+
+end_instantiate:
+       return dir_emit(ctx, name, len, 1, DT_UNKNOWN);
 }
 
 #ifdef CONFIG_CHECKPOINT_RESTORE
@@ -1846,7 +1834,7 @@ struct map_files_info {
        unsigned char   name[4*sizeof(long)+2]; /* max: %lx-%lx\0 */
 };
 
-static struct dentry *
+static int
 proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
                           struct task_struct *task, const void *ptr)
 {
@@ -1856,7 +1844,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
 
        inode = proc_pid_make_inode(dir->i_sb, task);
        if (!inode)
-               return ERR_PTR(-ENOENT);
+               return -ENOENT;
 
        ei = PROC_I(inode);
        ei->op.proc_get_link = proc_map_files_get_link;
@@ -1873,7 +1861,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
        d_set_d_op(dentry, &tid_map_files_dentry_operations);
        d_add(dentry, inode);
 
-       return NULL;
+       return 0;
 }
 
 static struct dentry *proc_map_files_lookup(struct inode *dir,
@@ -1882,23 +1870,23 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
        unsigned long vm_start, vm_end;
        struct vm_area_struct *vma;
        struct task_struct *task;
-       struct dentry *result;
+       int result;
        struct mm_struct *mm;
 
-       result = ERR_PTR(-EPERM);
+       result = -EPERM;
        if (!capable(CAP_SYS_ADMIN))
                goto out;
 
-       result = ERR_PTR(-ENOENT);
+       result = -ENOENT;
        task = get_proc_task(dir);
        if (!task)
                goto out;
 
-       result = ERR_PTR(-EACCES);
+       result = -EACCES;
        if (!ptrace_may_access(task, PTRACE_MODE_READ))
                goto out_put_task;
 
-       result = ERR_PTR(-ENOENT);
+       result = -ENOENT;
        if (dname_to_vma_addr(dentry, &vm_start, &vm_end))
                goto out_put_task;
 
@@ -1921,7 +1909,7 @@ out_no_vma:
 out_put_task:
        put_task_struct(task);
 out:
-       return result;
+       return ERR_PTR(result);
 }
 
 static const struct inode_operations proc_map_files_inode_operations = {
@@ -2135,13 +2123,12 @@ static const struct file_operations proc_timers_operations = {
 };
 #endif /* CONFIG_CHECKPOINT_RESTORE */
 
-static struct dentry *proc_pident_instantiate(struct inode *dir,
+static int proc_pident_instantiate(struct inode *dir,
        struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
        const struct pid_entry *p = ptr;
        struct inode *inode;
        struct proc_inode *ei;
-       struct dentry *error = ERR_PTR(-ENOENT);
 
        inode = proc_pid_make_inode(dir->i_sb, task);
        if (!inode)
@@ -2160,9 +2147,9 @@ static struct dentry *proc_pident_instantiate(struct inode *dir,
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
 out:
-       return error;
+       return -ENOENT;
 }
 
 static struct dentry *proc_pident_lookup(struct inode *dir, 
@@ -2170,11 +2157,11 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
                                         const struct pid_entry *ents,
                                         unsigned int nents)
 {
-       struct dentry *error;
+       int error;
        struct task_struct *task = get_proc_task(dir);
        const struct pid_entry *p, *last;
 
-       error = ERR_PTR(-ENOENT);
+       error = -ENOENT;
 
        if (!task)
                goto out_no_task;
@@ -2197,7 +2184,7 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
 out:
        put_task_struct(task);
 out_no_task:
-       return error;
+       return ERR_PTR(error);
 }
 
 static int proc_pident_readdir(struct file *file, struct dir_context *ctx,
@@ -2780,11 +2767,10 @@ void proc_flush_task(struct task_struct *task)
        }
 }
 
-static struct dentry *proc_pid_instantiate(struct inode *dir,
-                                          struct dentry * dentry,
-                                          struct task_struct *task, const void *ptr)
+static int proc_pid_instantiate(struct inode *dir,
+                                  struct dentry * dentry,
+                                  struct task_struct *task, const void *ptr)
 {
-       struct dentry *error = ERR_PTR(-ENOENT);
        struct inode *inode;
 
        inode = proc_pid_make_inode(dir->i_sb, task);
@@ -2804,14 +2790,14 @@ static struct dentry *proc_pid_instantiate(struct inode *dir,
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
 out:
-       return error;
+       return -ENOENT;
 }
 
 struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
-       struct dentry *result = NULL;
+       int result = 0;
        struct task_struct *task;
        unsigned tgid;
        struct pid_namespace *ns;
@@ -2832,7 +2818,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign
        result = proc_pid_instantiate(dir, dentry, task, NULL);
        put_task_struct(task);
 out:
-       return result;
+       return ERR_PTR(result);
 }
 
 /*
@@ -2884,21 +2870,21 @@ retry:
 int proc_pid_readdir(struct file *file, struct dir_context *ctx)
 {
        struct tgid_iter iter;
-       struct pid_namespace *ns;
+       struct pid_namespace *ns = file->f_dentry->d_sb->s_fs_info;
        loff_t pos = ctx->pos;
 
        if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
                return 0;
 
        if (pos == TGID_OFFSET - 1) {
-               if (!proc_fill_cache(file, ctx, "self", 4, NULL, NULL, NULL))
+               struct inode *inode = ns->proc_self->d_inode;
+               if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
                        return 0;
                iter.tgid = 0;
        } else {
                iter.tgid = pos - TGID_OFFSET;
        }
        iter.task = NULL;
-       ns = file->f_dentry->d_sb->s_fs_info;
        for (iter = next_tgid(ns, iter);
             iter.task;
             iter.tgid += 1, iter = next_tgid(ns, iter)) {
@@ -3027,10 +3013,9 @@ static const struct inode_operations proc_tid_base_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-static struct dentry *proc_task_instantiate(struct inode *dir,
+static int proc_task_instantiate(struct inode *dir,
        struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
-       struct dentry *error = ERR_PTR(-ENOENT);
        struct inode *inode;
        inode = proc_pid_make_inode(dir->i_sb, task);
 
@@ -3049,14 +3034,14 @@ static struct dentry *proc_task_instantiate(struct inode *dir,
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
 out:
-       return error;
+       return -ENOENT;
 }
 
 static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
-       struct dentry *result = ERR_PTR(-ENOENT);
+       int result = -ENOENT;
        struct task_struct *task;
        struct task_struct *leader = get_proc_task(dir);
        unsigned tid;
@@ -3086,7 +3071,7 @@ out_drop_task:
 out:
        put_task_struct(leader);
 out_no_task:
-       return result;
+       return ERR_PTR(result);
 }
 
 /*
index 1441f143c43b6d187f5d6f2b181118148d2501e5..75f2890abbd8ddcc8a674b1c42397cc1456fd33e 100644 (file)
@@ -167,11 +167,10 @@ static int proc_fd_link(struct dentry *dentry, struct path *path)
        return ret;
 }
 
-static struct dentry *
+static int
 proc_fd_instantiate(struct inode *dir, struct dentry *dentry,
                    struct task_struct *task, const void *ptr)
 {
-       struct dentry *error = ERR_PTR(-ENOENT);
        unsigned fd = (unsigned long)ptr;
        struct proc_inode *ei;
        struct inode *inode;
@@ -194,9 +193,9 @@ proc_fd_instantiate(struct inode *dir, struct dentry *dentry,
 
        /* Close the race of the process dying before we return the dentry */
        if (tid_fd_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
  out:
-       return error;
+       return -ENOENT;
 }
 
 static struct dentry *proc_lookupfd_common(struct inode *dir,
@@ -204,7 +203,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
                                           instantiate_t instantiate)
 {
        struct task_struct *task = get_proc_task(dir);
-       struct dentry *result = ERR_PTR(-ENOENT);
+       int result = -ENOENT;
        unsigned fd = name_to_int(dentry);
 
        if (!task)
@@ -216,7 +215,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
 out:
        put_task_struct(task);
 out_no_task:
-       return result;
+       return ERR_PTR(result);
 }
 
 static int proc_readfd_common(struct file *file, struct dir_context *ctx,
@@ -300,11 +299,10 @@ const struct inode_operations proc_fd_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-static struct dentry *
+static int
 proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry,
                        struct task_struct *task, const void *ptr)
 {
-       struct dentry *error = ERR_PTR(-ENOENT);
        unsigned fd = (unsigned long)ptr;
        struct proc_inode *ei;
        struct inode *inode;
@@ -324,9 +322,9 @@ proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry,
 
        /* Close the race of the process dying before we return the dentry */
        if (tid_fd_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
  out:
-       return error;
+       return -ENOENT;
 }
 
 static struct dentry *
index 4eae2e149f31c05bb2d802c05f64bf91afdd4d29..651d09a11dde360a3ebabc26cc206aefb3b0515c 100644 (file)
@@ -170,7 +170,7 @@ extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned
 extern loff_t mem_lseek(struct file *, loff_t, int);
 
 /* Lookups */
-typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
+typedef int instantiate_t(struct inode *, struct dentry *,
                                     struct task_struct *, const void *);
 extern bool proc_fill_cache(struct file *, struct dir_context *, const char *, int,
                           instantiate_t, struct task_struct *, const void *);
index 0a22194e5d586f2dc3e7488702475746ed5f9da4..06ea155e1a590530d0c16ee964107bcf54756995 100644 (file)
@@ -408,7 +408,7 @@ static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff)
        prpsinfo.pr_zomb        = 0;
 
        strcpy(prpsinfo.pr_fname, "vmlinux");
-       strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ);
+       strlcpy(prpsinfo.pr_psargs, saved_command_line, sizeof(prpsinfo.pr_psargs));
 
        nhdr->p_filesz  += notesize(&notes[1]);
        bufp = storenote(&notes[1], bufp);
index f6abbbbfad8a765d115013ae65b07632b7e15258..49a7fff2e83a9906f39a685ddad0e98211dd155f 100644 (file)
@@ -187,13 +187,12 @@ static const struct inode_operations proc_ns_link_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-static struct dentry *proc_ns_instantiate(struct inode *dir,
+static int proc_ns_instantiate(struct inode *dir,
        struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
        const struct proc_ns_operations *ns_ops = ptr;
        struct inode *inode;
        struct proc_inode *ei;
-       struct dentry *error = ERR_PTR(-ENOENT);
 
        inode = proc_pid_make_inode(dir->i_sb, task);
        if (!inode)
@@ -208,9 +207,9 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, 0))
-               error = NULL;
+               return 0;
 out:
-       return error;
+       return -ENOENT;
 }
 
 static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
@@ -248,12 +247,12 @@ const struct file_operations proc_ns_dir_operations = {
 static struct dentry *proc_ns_dir_lookup(struct inode *dir,
                                struct dentry *dentry, unsigned int flags)
 {
-       struct dentry *error;
+       int error;
        struct task_struct *task = get_proc_task(dir);
        const struct proc_ns_operations **entry, **last;
        unsigned int len = dentry->d_name.len;
 
-       error = ERR_PTR(-ENOENT);
+       error = -ENOENT;
 
        if (!task)
                goto out_no_task;
@@ -272,7 +271,7 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir,
 out:
        put_task_struct(task);
 out_no_task:
-       return error;
+       return ERR_PTR(error);
 }
 
 const struct inode_operations proc_ns_dir_inode_operations = {
index f3a570e7c2575a723b5ac4061c1dd7aca1cb80c8..71290463a1d3fa87a5132e21615792fe7fbaf9f4 100644 (file)
@@ -796,15 +796,16 @@ static int sysctl_is_seen(struct ctl_table_header *p)
        return res;
 }
 
-static int proc_sys_compare(const struct dentry *parent,
-               const struct inode *pinode,
-               const struct dentry *dentry, const struct inode *inode,
+static int proc_sys_compare(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct ctl_table_header *head;
+       struct inode *inode;
+
        /* Although proc doesn't have negative dentries, rcu-walk means
         * that inode here can be NULL */
        /* AV: can it, indeed? */
+       inode = ACCESS_ONCE(dentry->d_inode);
        if (!inode)
                return 1;
        if (name->len != len)
index 3e636d864d5666aa2b7a58a5f61af214e6d30832..dbf61f6174f0f473d3d9a19311a09170f8dab9f3 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/rmap.h>
 #include <linux/swap.h>
 #include <linux/swapops.h>
+#include <linux/mmu_notifier.h>
 
 #include <asm/elf.h>
 #include <asm/uaccess.h>
@@ -688,10 +689,58 @@ const struct file_operations proc_tid_smaps_operations = {
        .release        = seq_release_private,
 };
 
+/*
+ * We do not want to have constant page-shift bits sitting in
+ * pagemap entries and are about to reuse them some time soon.
+ *
+ * Here's the "migration strategy":
+ * 1. when the system boots these bits remain what they are,
+ *    but a warning about future change is printed in log;
+ * 2. once anyone clears soft-dirty bits via clear_refs file,
+ *    these flag is set to denote, that user is aware of the
+ *    new API and those page-shift bits change their meaning.
+ *    The respective warning is printed in dmesg;
+ * 3. In a couple of releases we will remove all the mentions
+ *    of page-shift in pagemap entries.
+ */
+
+static bool soft_dirty_cleared __read_mostly;
+
+enum clear_refs_types {
+       CLEAR_REFS_ALL = 1,
+       CLEAR_REFS_ANON,
+       CLEAR_REFS_MAPPED,
+       CLEAR_REFS_SOFT_DIRTY,
+       CLEAR_REFS_LAST,
+};
+
+struct clear_refs_private {
+       struct vm_area_struct *vma;
+       enum clear_refs_types type;
+};
+
+static inline void clear_soft_dirty(struct vm_area_struct *vma,
+               unsigned long addr, pte_t *pte)
+{
+#ifdef CONFIG_MEM_SOFT_DIRTY
+       /*
+        * The soft-dirty tracker uses #PF-s to catch writes
+        * to pages, so write-protect the pte as well. See the
+        * Documentation/vm/soft-dirty.txt for full description
+        * of how soft-dirty works.
+        */
+       pte_t ptent = *pte;
+       ptent = pte_wrprotect(ptent);
+       ptent = pte_clear_flags(ptent, _PAGE_SOFT_DIRTY);
+       set_pte_at(vma->vm_mm, addr, pte, ptent);
+#endif
+}
+
 static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
                                unsigned long end, struct mm_walk *walk)
 {
-       struct vm_area_struct *vma = walk->private;
+       struct clear_refs_private *cp = walk->private;
+       struct vm_area_struct *vma = cp->vma;
        pte_t *pte, ptent;
        spinlock_t *ptl;
        struct page *page;
@@ -706,6 +755,11 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
                if (!pte_present(ptent))
                        continue;
 
+               if (cp->type == CLEAR_REFS_SOFT_DIRTY) {
+                       clear_soft_dirty(vma, addr, pte);
+                       continue;
+               }
+
                page = vm_normal_page(vma, addr, ptent);
                if (!page)
                        continue;
@@ -719,10 +773,6 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
        return 0;
 }
 
-#define CLEAR_REFS_ALL 1
-#define CLEAR_REFS_ANON 2
-#define CLEAR_REFS_MAPPED 3
-
 static ssize_t clear_refs_write(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
 {
@@ -730,7 +780,8 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
        char buffer[PROC_NUMBUF];
        struct mm_struct *mm;
        struct vm_area_struct *vma;
-       int type;
+       enum clear_refs_types type;
+       int itype;
        int rv;
 
        memset(buffer, 0, sizeof(buffer));
@@ -738,23 +789,37 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
                count = sizeof(buffer) - 1;
        if (copy_from_user(buffer, buf, count))
                return -EFAULT;
-       rv = kstrtoint(strstrip(buffer), 10, &type);
+       rv = kstrtoint(strstrip(buffer), 10, &itype);
        if (rv < 0)
                return rv;
-       if (type < CLEAR_REFS_ALL || type > CLEAR_REFS_MAPPED)
+       type = (enum clear_refs_types)itype;
+       if (type < CLEAR_REFS_ALL || type >= CLEAR_REFS_LAST)
                return -EINVAL;
+
+       if (type == CLEAR_REFS_SOFT_DIRTY) {
+               soft_dirty_cleared = true;
+               pr_warn_once("The pagemap bits 55-60 has changed their meaning! "
+                               "See the linux/Documentation/vm/pagemap.txt for details.\n");
+       }
+
        task = get_proc_task(file_inode(file));
        if (!task)
                return -ESRCH;
        mm = get_task_mm(task);
        if (mm) {
+               struct clear_refs_private cp = {
+                       .type = type,
+               };
                struct mm_walk clear_refs_walk = {
                        .pmd_entry = clear_refs_pte_range,
                        .mm = mm,
+                       .private = &cp,
                };
                down_read(&mm->mmap_sem);
+               if (type == CLEAR_REFS_SOFT_DIRTY)
+                       mmu_notifier_invalidate_range_start(mm, 0, -1);
                for (vma = mm->mmap; vma; vma = vma->vm_next) {
-                       clear_refs_walk.private = vma;
+                       cp.vma = vma;
                        if (is_vm_hugetlb_page(vma))
                                continue;
                        /*
@@ -773,6 +838,8 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
                        walk_page_range(vma->vm_start, vma->vm_end,
                                        &clear_refs_walk);
                }
+               if (type == CLEAR_REFS_SOFT_DIRTY)
+                       mmu_notifier_invalidate_range_end(mm, 0, -1);
                flush_tlb_mm(mm);
                up_read(&mm->mmap_sem);
                mmput(mm);
@@ -794,6 +861,7 @@ typedef struct {
 struct pagemapread {
        int pos, len;
        pagemap_entry_t *buffer;
+       bool v2;
 };
 
 #define PAGEMAP_WALK_SIZE      (PMD_SIZE)
@@ -807,14 +875,17 @@ struct pagemapread {
 #define PM_PSHIFT_BITS      6
 #define PM_PSHIFT_OFFSET    (PM_STATUS_OFFSET - PM_PSHIFT_BITS)
 #define PM_PSHIFT_MASK      (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET)
-#define PM_PSHIFT(x)        (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK)
+#define __PM_PSHIFT(x)      (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK)
 #define PM_PFRAME_MASK      ((1LL << PM_PSHIFT_OFFSET) - 1)
 #define PM_PFRAME(x)        ((x) & PM_PFRAME_MASK)
+/* in "new" pagemap pshift bits are occupied with more status bits */
+#define PM_STATUS2(v2, x)   (__PM_PSHIFT(v2 ? x : PAGE_SHIFT))
 
+#define __PM_SOFT_DIRTY      (1LL)
 #define PM_PRESENT          PM_STATUS(4LL)
 #define PM_SWAP             PM_STATUS(2LL)
 #define PM_FILE             PM_STATUS(1LL)
-#define PM_NOT_PRESENT      PM_PSHIFT(PAGE_SHIFT)
+#define PM_NOT_PRESENT(v2)  PM_STATUS2(v2, 0)
 #define PM_END_OF_BUFFER    1
 
 static inline pagemap_entry_t make_pme(u64 val)
@@ -837,7 +908,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end,
        struct pagemapread *pm = walk->private;
        unsigned long addr;
        int err = 0;
-       pagemap_entry_t pme = make_pme(PM_NOT_PRESENT);
+       pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2));
 
        for (addr = start; addr < end; addr += PAGE_SIZE) {
                err = add_to_pagemap(addr, &pme, pm);
@@ -847,11 +918,12 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end,
        return err;
 }
 
-static void pte_to_pagemap_entry(pagemap_entry_t *pme,
+static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
                struct vm_area_struct *vma, unsigned long addr, pte_t pte)
 {
        u64 frame, flags;
        struct page *page = NULL;
+       int flags2 = 0;
 
        if (pte_present(pte)) {
                frame = pte_pfn(pte);
@@ -866,19 +938,21 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme,
                if (is_migration_entry(entry))
                        page = migration_entry_to_page(entry);
        } else {
-               *pme = make_pme(PM_NOT_PRESENT);
+               *pme = make_pme(PM_NOT_PRESENT(pm->v2));
                return;
        }
 
        if (page && !PageAnon(page))
                flags |= PM_FILE;
+       if (pte_soft_dirty(pte))
+               flags2 |= __PM_SOFT_DIRTY;
 
-       *pme = make_pme(PM_PFRAME(frame) | PM_PSHIFT(PAGE_SHIFT) | flags);
+       *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, flags2) | flags);
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme,
-                                       pmd_t pmd, int offset)
+static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
+               pmd_t pmd, int offset, int pmd_flags2)
 {
        /*
         * Currently pmd for thp is always present because thp can not be
@@ -887,13 +961,13 @@ static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme,
         */
        if (pmd_present(pmd))
                *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset)
-                               | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT);
+                               | PM_STATUS2(pm->v2, pmd_flags2) | PM_PRESENT);
        else
-               *pme = make_pme(PM_NOT_PRESENT);
+               *pme = make_pme(PM_NOT_PRESENT(pm->v2));
 }
 #else
-static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme,
-                                               pmd_t pmd, int offset)
+static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
+               pmd_t pmd, int offset, int pmd_flags2)
 {
 }
 #endif
@@ -905,17 +979,20 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
        struct pagemapread *pm = walk->private;
        pte_t *pte;
        int err = 0;
-       pagemap_entry_t pme = make_pme(PM_NOT_PRESENT);
+       pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2));
 
        /* find the first VMA at or above 'addr' */
        vma = find_vma(walk->mm, addr);
        if (vma && pmd_trans_huge_lock(pmd, vma) == 1) {
+               int pmd_flags2;
+
+               pmd_flags2 = (pmd_soft_dirty(*pmd) ? __PM_SOFT_DIRTY : 0);
                for (; addr != end; addr += PAGE_SIZE) {
                        unsigned long offset;
 
                        offset = (addr & ~PAGEMAP_WALK_MASK) >>
                                        PAGE_SHIFT;
-                       thp_pmd_to_pagemap_entry(&pme, *pmd, offset);
+                       thp_pmd_to_pagemap_entry(&pme, pm, *pmd, offset, pmd_flags2);
                        err = add_to_pagemap(addr, &pme, pm);
                        if (err)
                                break;
@@ -932,7 +1009,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
                 * and need a new, higher one */
                if (vma && (addr >= vma->vm_end)) {
                        vma = find_vma(walk->mm, addr);
-                       pme = make_pme(PM_NOT_PRESENT);
+                       pme = make_pme(PM_NOT_PRESENT(pm->v2));
                }
 
                /* check that 'vma' actually covers this address,
@@ -940,7 +1017,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
                if (vma && (vma->vm_start <= addr) &&
                    !is_vm_hugetlb_page(vma)) {
                        pte = pte_offset_map(pmd, addr);
-                       pte_to_pagemap_entry(&pme, vma, addr, *pte);
+                       pte_to_pagemap_entry(&pme, pm, vma, addr, *pte);
                        /* unmap before userspace copy */
                        pte_unmap(pte);
                }
@@ -955,14 +1032,14 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
 }
 
 #ifdef CONFIG_HUGETLB_PAGE
-static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme,
+static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
                                        pte_t pte, int offset)
 {
        if (pte_present(pte))
                *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset)
-                               | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT);
+                               | PM_STATUS2(pm->v2, 0) | PM_PRESENT);
        else
-               *pme = make_pme(PM_NOT_PRESENT);
+               *pme = make_pme(PM_NOT_PRESENT(pm->v2));
 }
 
 /* This function walks within one hugetlb entry in the single call */
@@ -976,7 +1053,7 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask,
 
        for (; addr != end; addr += PAGE_SIZE) {
                int offset = (addr & ~hmask) >> PAGE_SHIFT;
-               huge_pte_to_pagemap_entry(&pme, *pte, offset);
+               huge_pte_to_pagemap_entry(&pme, pm, *pte, offset);
                err = add_to_pagemap(addr, &pme, pm);
                if (err)
                        return err;
@@ -1038,6 +1115,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
        if (!count)
                goto out_task;
 
+       pm.v2 = soft_dirty_cleared;
        pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
        pm.buffer = kmalloc(pm.len, GFP_TEMPORARY);
        ret = -ENOMEM;
@@ -1110,9 +1188,18 @@ out:
        return ret;
 }
 
+static int pagemap_open(struct inode *inode, struct file *file)
+{
+       pr_warn_once("Bits 55-60 of /proc/PID/pagemap entries are about "
+                       "to stop being page-shift some time soon. See the "
+                       "linux/Documentation/vm/pagemap.txt for details.\n");
+       return 0;
+}
+
 const struct file_operations proc_pagemap_operations = {
        .llseek         = mem_lseek, /* borrow this */
        .read           = pagemap_read,
+       .open           = pagemap_open,
 };
 #endif /* CONFIG_PROC_PAGE_MONITOR */
 
index 9610ac772d7e8e79a197725fbed6f77ef5b1dc96..061894625903ded399f2ab9285daa5f69adba854 100644 (file)
@@ -20,8 +20,7 @@ static int uptime_proc_show(struct seq_file *m, void *v)
        for_each_possible_cpu(i)
                idletime += (__force u64) kcpustat_cpu(i).cpustat[CPUTIME_IDLE];
 
-       do_posix_clock_monotonic_gettime(&uptime);
-       monotonic_to_bootbased(&uptime);
+       get_monotonic_boottime(&uptime);
        nsec = cputime64_to_jiffies64(idletime) * TICK_NSEC;
        idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
        idle.tv_nsec = rem;
index 17f7e080d7ff6c5c301c6b71bd1c793b1439357c..28503172f2e4a2d16a87a87098ad5db615317565 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/crash_dump.h>
 #include <linux/list.h>
+#include <linux/vmalloc.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include "internal.h"
@@ -32,6 +33,10 @@ static LIST_HEAD(vmcore_list);
 /* Stores the pointer to the buffer containing kernel elf core headers. */
 static char *elfcorebuf;
 static size_t elfcorebuf_sz;
+static size_t elfcorebuf_sz_orig;
+
+static char *elfnotes_buf;
+static size_t elfnotes_sz;
 
 /* Total size of vmcore file. */
 static u64 vmcore_size;
@@ -118,27 +123,6 @@ static ssize_t read_from_oldmem(char *buf, size_t count,
        return read;
 }
 
-/* Maps vmcore file offset to respective physical address in memroy. */
-static u64 map_offset_to_paddr(loff_t offset, struct list_head *vc_list,
-                                       struct vmcore **m_ptr)
-{
-       struct vmcore *m;
-       u64 paddr;
-
-       list_for_each_entry(m, vc_list, list) {
-               u64 start, end;
-               start = m->offset;
-               end = m->offset + m->size - 1;
-               if (offset >= start && offset <= end) {
-                       paddr = m->paddr + offset - start;
-                       *m_ptr = m;
-                       return paddr;
-               }
-       }
-       *m_ptr = NULL;
-       return 0;
-}
-
 /* Read from the ELF header and then the crash dump. On error, negative value is
  * returned otherwise number of bytes read are returned.
  */
@@ -147,8 +131,8 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
 {
        ssize_t acc = 0, tmp;
        size_t tsz;
-       u64 start, nr_bytes;
-       struct vmcore *curr_m = NULL;
+       u64 start;
+       struct vmcore *m = NULL;
 
        if (buflen == 0 || *fpos >= vmcore_size)
                return 0;
@@ -159,9 +143,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
 
        /* Read ELF core header */
        if (*fpos < elfcorebuf_sz) {
-               tsz = elfcorebuf_sz - *fpos;
-               if (buflen < tsz)
-                       tsz = buflen;
+               tsz = min(elfcorebuf_sz - (size_t)*fpos, buflen);
                if (copy_to_user(buffer, elfcorebuf + *fpos, tsz))
                        return -EFAULT;
                buflen -= tsz;
@@ -174,39 +156,161 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
                        return acc;
        }
 
-       start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m);
-       if (!curr_m)
-               return -EINVAL;
-
-       while (buflen) {
-               tsz = min_t(size_t, buflen, PAGE_SIZE - (start & ~PAGE_MASK));
+       /* Read Elf note segment */
+       if (*fpos < elfcorebuf_sz + elfnotes_sz) {
+               void *kaddr;
 
-               /* Calculate left bytes in current memory segment. */
-               nr_bytes = (curr_m->size - (start - curr_m->paddr));
-               if (tsz > nr_bytes)
-                       tsz = nr_bytes;
-
-               tmp = read_from_oldmem(buffer, tsz, &start, 1);
-               if (tmp < 0)
-                       return tmp;
+               tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)*fpos, buflen);
+               kaddr = elfnotes_buf + *fpos - elfcorebuf_sz;
+               if (copy_to_user(buffer, kaddr, tsz))
+                       return -EFAULT;
                buflen -= tsz;
                *fpos += tsz;
                buffer += tsz;
                acc += tsz;
-               if (start >= (curr_m->paddr + curr_m->size)) {
-                       if (curr_m->list.next == &vmcore_list)
-                               return acc;     /*EOF*/
-                       curr_m = list_entry(curr_m->list.next,
-                                               struct vmcore, list);
-                       start = curr_m->paddr;
+
+               /* leave now if filled buffer already */
+               if (buflen == 0)
+                       return acc;
+       }
+
+       list_for_each_entry(m, &vmcore_list, list) {
+               if (*fpos < m->offset + m->size) {
+                       tsz = min_t(size_t, m->offset + m->size - *fpos, buflen);
+                       start = m->paddr + *fpos - m->offset;
+                       tmp = read_from_oldmem(buffer, tsz, &start, 1);
+                       if (tmp < 0)
+                               return tmp;
+                       buflen -= tsz;
+                       *fpos += tsz;
+                       buffer += tsz;
+                       acc += tsz;
+
+                       /* leave now if filled buffer already */
+                       if (buflen == 0)
+                               return acc;
                }
        }
+
        return acc;
 }
 
+/**
+ * alloc_elfnotes_buf - allocate buffer for ELF note segment in
+ *                      vmalloc memory
+ *
+ * @notes_sz: size of buffer
+ *
+ * If CONFIG_MMU is defined, use vmalloc_user() to allow users to mmap
+ * the buffer to user-space by means of remap_vmalloc_range().
+ *
+ * If CONFIG_MMU is not defined, use vzalloc() since mmap_vmcore() is
+ * disabled and there's no need to allow users to mmap the buffer.
+ */
+static inline char *alloc_elfnotes_buf(size_t notes_sz)
+{
+#ifdef CONFIG_MMU
+       return vmalloc_user(notes_sz);
+#else
+       return vzalloc(notes_sz);
+#endif
+}
+
+/*
+ * Disable mmap_vmcore() if CONFIG_MMU is not defined. MMU is
+ * essential for mmap_vmcore() in order to map physically
+ * non-contiguous objects (ELF header, ELF note segment and memory
+ * regions in the 1st kernel pointed to by PT_LOAD entries) into
+ * virtually contiguous user-space in ELF layout.
+ */
+#ifdef CONFIG_MMU
+static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
+{
+       size_t size = vma->vm_end - vma->vm_start;
+       u64 start, end, len, tsz;
+       struct vmcore *m;
+
+       start = (u64)vma->vm_pgoff << PAGE_SHIFT;
+       end = start + size;
+
+       if (size > vmcore_size || end > vmcore_size)
+               return -EINVAL;
+
+       if (vma->vm_flags & (VM_WRITE | VM_EXEC))
+               return -EPERM;
+
+       vma->vm_flags &= ~(VM_MAYWRITE | VM_MAYEXEC);
+       vma->vm_flags |= VM_MIXEDMAP;
+
+       len = 0;
+
+       if (start < elfcorebuf_sz) {
+               u64 pfn;
+
+               tsz = min(elfcorebuf_sz - (size_t)start, size);
+               pfn = __pa(elfcorebuf + start) >> PAGE_SHIFT;
+               if (remap_pfn_range(vma, vma->vm_start, pfn, tsz,
+                                   vma->vm_page_prot))
+                       return -EAGAIN;
+               size -= tsz;
+               start += tsz;
+               len += tsz;
+
+               if (size == 0)
+                       return 0;
+       }
+
+       if (start < elfcorebuf_sz + elfnotes_sz) {
+               void *kaddr;
+
+               tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)start, size);
+               kaddr = elfnotes_buf + start - elfcorebuf_sz;
+               if (remap_vmalloc_range_partial(vma, vma->vm_start + len,
+                                               kaddr, tsz))
+                       goto fail;
+               size -= tsz;
+               start += tsz;
+               len += tsz;
+
+               if (size == 0)
+                       return 0;
+       }
+
+       list_for_each_entry(m, &vmcore_list, list) {
+               if (start < m->offset + m->size) {
+                       u64 paddr = 0;
+
+                       tsz = min_t(size_t, m->offset + m->size - start, size);
+                       paddr = m->paddr + start - m->offset;
+                       if (remap_pfn_range(vma, vma->vm_start + len,
+                                           paddr >> PAGE_SHIFT, tsz,
+                                           vma->vm_page_prot))
+                               goto fail;
+                       size -= tsz;
+                       start += tsz;
+                       len += tsz;
+
+                       if (size == 0)
+                               return 0;
+               }
+       }
+
+       return 0;
+fail:
+       do_munmap(vma->vm_mm, vma->vm_start, len);
+       return -EAGAIN;
+}
+#else
+static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
+{
+       return -ENOSYS;
+}
+#endif
+
 static const struct file_operations proc_vmcore_operations = {
        .read           = read_vmcore,
        .llseek         = default_llseek,
+       .mmap           = mmap_vmcore,
 };
 
 static struct vmcore* __init get_new_element(void)
@@ -214,61 +318,40 @@ static struct vmcore* __init get_new_element(void)
        return kzalloc(sizeof(struct vmcore), GFP_KERNEL);
 }
 
-static u64 __init get_vmcore_size_elf64(char *elfptr)
+static u64 __init get_vmcore_size(size_t elfsz, size_t elfnotesegsz,
+                                 struct list_head *vc_list)
 {
-       int i;
-       u64 size;
-       Elf64_Ehdr *ehdr_ptr;
-       Elf64_Phdr *phdr_ptr;
-
-       ehdr_ptr = (Elf64_Ehdr *)elfptr;
-       phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
-       size = sizeof(Elf64_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr));
-       for (i = 0; i < ehdr_ptr->e_phnum; i++) {
-               size += phdr_ptr->p_memsz;
-               phdr_ptr++;
-       }
-       return size;
-}
-
-static u64 __init get_vmcore_size_elf32(char *elfptr)
-{
-       int i;
        u64 size;
-       Elf32_Ehdr *ehdr_ptr;
-       Elf32_Phdr *phdr_ptr;
+       struct vmcore *m;
 
-       ehdr_ptr = (Elf32_Ehdr *)elfptr;
-       phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
-       size = sizeof(Elf32_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr));
-       for (i = 0; i < ehdr_ptr->e_phnum; i++) {
-               size += phdr_ptr->p_memsz;
-               phdr_ptr++;
+       size = elfsz + elfnotesegsz;
+       list_for_each_entry(m, vc_list, list) {
+               size += m->size;
        }
        return size;
 }
 
-/* Merges all the PT_NOTE headers into one. */
-static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
-                                               struct list_head *vc_list)
+/**
+ * update_note_header_size_elf64 - update p_memsz member of each PT_NOTE entry
+ *
+ * @ehdr_ptr: ELF header
+ *
+ * This function updates p_memsz member of each PT_NOTE entry in the
+ * program header table pointed to by @ehdr_ptr to real size of ELF
+ * note segment.
+ */
+static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr)
 {
-       int i, nr_ptnote=0, rc=0;
-       char *tmp;
-       Elf64_Ehdr *ehdr_ptr;
-       Elf64_Phdr phdr, *phdr_ptr;
+       int i, rc=0;
+       Elf64_Phdr *phdr_ptr;
        Elf64_Nhdr *nhdr_ptr;
-       u64 phdr_sz = 0, note_off;
 
-       ehdr_ptr = (Elf64_Ehdr *)elfptr;
-       phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
+       phdr_ptr = (Elf64_Phdr *)(ehdr_ptr + 1);
        for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
-               int j;
                void *notes_section;
-               struct vmcore *new;
                u64 offset, max_sz, sz, real_sz = 0;
                if (phdr_ptr->p_type != PT_NOTE)
                        continue;
-               nr_ptnote++;
                max_sz = phdr_ptr->p_memsz;
                offset = phdr_ptr->p_offset;
                notes_section = kmalloc(max_sz, GFP_KERNEL);
@@ -280,7 +363,7 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
                        return rc;
                }
                nhdr_ptr = notes_section;
-               for (j = 0; j < max_sz; j += sz) {
+               while (real_sz < max_sz) {
                        if (nhdr_ptr->n_namesz == 0)
                                break;
                        sz = sizeof(Elf64_Nhdr) +
@@ -289,26 +372,122 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
                        real_sz += sz;
                        nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
                }
-
-               /* Add this contiguous chunk of notes section to vmcore list.*/
-               new = get_new_element();
-               if (!new) {
-                       kfree(notes_section);
-                       return -ENOMEM;
-               }
-               new->paddr = phdr_ptr->p_offset;
-               new->size = real_sz;
-               list_add_tail(&new->list, vc_list);
-               phdr_sz += real_sz;
                kfree(notes_section);
+               phdr_ptr->p_memsz = real_sz;
+       }
+
+       return 0;
+}
+
+/**
+ * get_note_number_and_size_elf64 - get the number of PT_NOTE program
+ * headers and sum of real size of their ELF note segment headers and
+ * data.
+ *
+ * @ehdr_ptr: ELF header
+ * @nr_ptnote: buffer for the number of PT_NOTE program headers
+ * @sz_ptnote: buffer for size of unique PT_NOTE program header
+ *
+ * This function is used to merge multiple PT_NOTE program headers
+ * into a unique single one. The resulting unique entry will have
+ * @sz_ptnote in its phdr->p_mem.
+ *
+ * It is assumed that program headers with PT_NOTE type pointed to by
+ * @ehdr_ptr has already been updated by update_note_header_size_elf64
+ * and each of PT_NOTE program headers has actual ELF note segment
+ * size in its p_memsz member.
+ */
+static int __init get_note_number_and_size_elf64(const Elf64_Ehdr *ehdr_ptr,
+                                                int *nr_ptnote, u64 *sz_ptnote)
+{
+       int i;
+       Elf64_Phdr *phdr_ptr;
+
+       *nr_ptnote = *sz_ptnote = 0;
+
+       phdr_ptr = (Elf64_Phdr *)(ehdr_ptr + 1);
+       for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+               if (phdr_ptr->p_type != PT_NOTE)
+                       continue;
+               *nr_ptnote += 1;
+               *sz_ptnote += phdr_ptr->p_memsz;
+       }
+
+       return 0;
+}
+
+/**
+ * copy_notes_elf64 - copy ELF note segments in a given buffer
+ *
+ * @ehdr_ptr: ELF header
+ * @notes_buf: buffer into which ELF note segments are copied
+ *
+ * This function is used to copy ELF note segment in the 1st kernel
+ * into the buffer @notes_buf in the 2nd kernel. It is assumed that
+ * size of the buffer @notes_buf is equal to or larger than sum of the
+ * real ELF note segment headers and data.
+ *
+ * It is assumed that program headers with PT_NOTE type pointed to by
+ * @ehdr_ptr has already been updated by update_note_header_size_elf64
+ * and each of PT_NOTE program headers has actual ELF note segment
+ * size in its p_memsz member.
+ */
+static int __init copy_notes_elf64(const Elf64_Ehdr *ehdr_ptr, char *notes_buf)
+{
+       int i, rc=0;
+       Elf64_Phdr *phdr_ptr;
+
+       phdr_ptr = (Elf64_Phdr*)(ehdr_ptr + 1);
+
+       for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+               u64 offset;
+               if (phdr_ptr->p_type != PT_NOTE)
+                       continue;
+               offset = phdr_ptr->p_offset;
+               rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0);
+               if (rc < 0)
+                       return rc;
+               notes_buf += phdr_ptr->p_memsz;
        }
 
+       return 0;
+}
+
+/* Merges all the PT_NOTE headers into one. */
+static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
+                                          char **notes_buf, size_t *notes_sz)
+{
+       int i, nr_ptnote=0, rc=0;
+       char *tmp;
+       Elf64_Ehdr *ehdr_ptr;
+       Elf64_Phdr phdr;
+       u64 phdr_sz = 0, note_off;
+
+       ehdr_ptr = (Elf64_Ehdr *)elfptr;
+
+       rc = update_note_header_size_elf64(ehdr_ptr);
+       if (rc < 0)
+               return rc;
+
+       rc = get_note_number_and_size_elf64(ehdr_ptr, &nr_ptnote, &phdr_sz);
+       if (rc < 0)
+               return rc;
+
+       *notes_sz = roundup(phdr_sz, PAGE_SIZE);
+       *notes_buf = alloc_elfnotes_buf(*notes_sz);
+       if (!*notes_buf)
+               return -ENOMEM;
+
+       rc = copy_notes_elf64(ehdr_ptr, *notes_buf);
+       if (rc < 0)
+               return rc;
+
        /* Prepare merged PT_NOTE program header. */
        phdr.p_type    = PT_NOTE;
        phdr.p_flags   = 0;
        note_off = sizeof(Elf64_Ehdr) +
                        (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr);
-       phdr.p_offset  = note_off;
+       phdr.p_offset  = roundup(note_off, PAGE_SIZE);
        phdr.p_vaddr   = phdr.p_paddr = 0;
        phdr.p_filesz  = phdr.p_memsz = phdr_sz;
        phdr.p_align   = 0;
@@ -322,6 +501,8 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
        i = (nr_ptnote - 1) * sizeof(Elf64_Phdr);
        *elfsz = *elfsz - i;
        memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf64_Ehdr)-sizeof(Elf64_Phdr)));
+       memset(elfptr + *elfsz, 0, i);
+       *elfsz = roundup(*elfsz, PAGE_SIZE);
 
        /* Modify e_phnum to reflect merged headers. */
        ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
@@ -329,27 +510,27 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
        return 0;
 }
 
-/* Merges all the PT_NOTE headers into one. */
-static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
-                                               struct list_head *vc_list)
+/**
+ * update_note_header_size_elf32 - update p_memsz member of each PT_NOTE entry
+ *
+ * @ehdr_ptr: ELF header
+ *
+ * This function updates p_memsz member of each PT_NOTE entry in the
+ * program header table pointed to by @ehdr_ptr to real size of ELF
+ * note segment.
+ */
+static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr)
 {
-       int i, nr_ptnote=0, rc=0;
-       char *tmp;
-       Elf32_Ehdr *ehdr_ptr;
-       Elf32_Phdr phdr, *phdr_ptr;
+       int i, rc=0;
+       Elf32_Phdr *phdr_ptr;
        Elf32_Nhdr *nhdr_ptr;
-       u64 phdr_sz = 0, note_off;
 
-       ehdr_ptr = (Elf32_Ehdr *)elfptr;
-       phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
+       phdr_ptr = (Elf32_Phdr *)(ehdr_ptr + 1);
        for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
-               int j;
                void *notes_section;
-               struct vmcore *new;
                u64 offset, max_sz, sz, real_sz = 0;
                if (phdr_ptr->p_type != PT_NOTE)
                        continue;
-               nr_ptnote++;
                max_sz = phdr_ptr->p_memsz;
                offset = phdr_ptr->p_offset;
                notes_section = kmalloc(max_sz, GFP_KERNEL);
@@ -361,7 +542,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
                        return rc;
                }
                nhdr_ptr = notes_section;
-               for (j = 0; j < max_sz; j += sz) {
+               while (real_sz < max_sz) {
                        if (nhdr_ptr->n_namesz == 0)
                                break;
                        sz = sizeof(Elf32_Nhdr) +
@@ -370,26 +551,122 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
                        real_sz += sz;
                        nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
                }
-
-               /* Add this contiguous chunk of notes section to vmcore list.*/
-               new = get_new_element();
-               if (!new) {
-                       kfree(notes_section);
-                       return -ENOMEM;
-               }
-               new->paddr = phdr_ptr->p_offset;
-               new->size = real_sz;
-               list_add_tail(&new->list, vc_list);
-               phdr_sz += real_sz;
                kfree(notes_section);
+               phdr_ptr->p_memsz = real_sz;
+       }
+
+       return 0;
+}
+
+/**
+ * get_note_number_and_size_elf32 - get the number of PT_NOTE program
+ * headers and sum of real size of their ELF note segment headers and
+ * data.
+ *
+ * @ehdr_ptr: ELF header
+ * @nr_ptnote: buffer for the number of PT_NOTE program headers
+ * @sz_ptnote: buffer for size of unique PT_NOTE program header
+ *
+ * This function is used to merge multiple PT_NOTE program headers
+ * into a unique single one. The resulting unique entry will have
+ * @sz_ptnote in its phdr->p_mem.
+ *
+ * It is assumed that program headers with PT_NOTE type pointed to by
+ * @ehdr_ptr has already been updated by update_note_header_size_elf32
+ * and each of PT_NOTE program headers has actual ELF note segment
+ * size in its p_memsz member.
+ */
+static int __init get_note_number_and_size_elf32(const Elf32_Ehdr *ehdr_ptr,
+                                                int *nr_ptnote, u64 *sz_ptnote)
+{
+       int i;
+       Elf32_Phdr *phdr_ptr;
+
+       *nr_ptnote = *sz_ptnote = 0;
+
+       phdr_ptr = (Elf32_Phdr *)(ehdr_ptr + 1);
+       for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+               if (phdr_ptr->p_type != PT_NOTE)
+                       continue;
+               *nr_ptnote += 1;
+               *sz_ptnote += phdr_ptr->p_memsz;
+       }
+
+       return 0;
+}
+
+/**
+ * copy_notes_elf32 - copy ELF note segments in a given buffer
+ *
+ * @ehdr_ptr: ELF header
+ * @notes_buf: buffer into which ELF note segments are copied
+ *
+ * This function is used to copy ELF note segment in the 1st kernel
+ * into the buffer @notes_buf in the 2nd kernel. It is assumed that
+ * size of the buffer @notes_buf is equal to or larger than sum of the
+ * real ELF note segment headers and data.
+ *
+ * It is assumed that program headers with PT_NOTE type pointed to by
+ * @ehdr_ptr has already been updated by update_note_header_size_elf32
+ * and each of PT_NOTE program headers has actual ELF note segment
+ * size in its p_memsz member.
+ */
+static int __init copy_notes_elf32(const Elf32_Ehdr *ehdr_ptr, char *notes_buf)
+{
+       int i, rc=0;
+       Elf32_Phdr *phdr_ptr;
+
+       phdr_ptr = (Elf32_Phdr*)(ehdr_ptr + 1);
+
+       for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+               u64 offset;
+               if (phdr_ptr->p_type != PT_NOTE)
+                       continue;
+               offset = phdr_ptr->p_offset;
+               rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0);
+               if (rc < 0)
+                       return rc;
+               notes_buf += phdr_ptr->p_memsz;
        }
 
+       return 0;
+}
+
+/* Merges all the PT_NOTE headers into one. */
+static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
+                                          char **notes_buf, size_t *notes_sz)
+{
+       int i, nr_ptnote=0, rc=0;
+       char *tmp;
+       Elf32_Ehdr *ehdr_ptr;
+       Elf32_Phdr phdr;
+       u64 phdr_sz = 0, note_off;
+
+       ehdr_ptr = (Elf32_Ehdr *)elfptr;
+
+       rc = update_note_header_size_elf32(ehdr_ptr);
+       if (rc < 0)
+               return rc;
+
+       rc = get_note_number_and_size_elf32(ehdr_ptr, &nr_ptnote, &phdr_sz);
+       if (rc < 0)
+               return rc;
+
+       *notes_sz = roundup(phdr_sz, PAGE_SIZE);
+       *notes_buf = alloc_elfnotes_buf(*notes_sz);
+       if (!*notes_buf)
+               return -ENOMEM;
+
+       rc = copy_notes_elf32(ehdr_ptr, *notes_buf);
+       if (rc < 0)
+               return rc;
+
        /* Prepare merged PT_NOTE program header. */
        phdr.p_type    = PT_NOTE;
        phdr.p_flags   = 0;
        note_off = sizeof(Elf32_Ehdr) +
                        (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr);
-       phdr.p_offset  = note_off;
+       phdr.p_offset  = roundup(note_off, PAGE_SIZE);
        phdr.p_vaddr   = phdr.p_paddr = 0;
        phdr.p_filesz  = phdr.p_memsz = phdr_sz;
        phdr.p_align   = 0;
@@ -403,6 +680,8 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
        i = (nr_ptnote - 1) * sizeof(Elf32_Phdr);
        *elfsz = *elfsz - i;
        memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf32_Ehdr)-sizeof(Elf32_Phdr)));
+       memset(elfptr + *elfsz, 0, i);
+       *elfsz = roundup(*elfsz, PAGE_SIZE);
 
        /* Modify e_phnum to reflect merged headers. */
        ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
@@ -414,6 +693,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
  * the new offset fields of exported program headers. */
 static int __init process_ptload_program_headers_elf64(char *elfptr,
                                                size_t elfsz,
+                                               size_t elfnotes_sz,
                                                struct list_head *vc_list)
 {
        int i;
@@ -425,32 +705,38 @@ static int __init process_ptload_program_headers_elf64(char *elfptr,
        ehdr_ptr = (Elf64_Ehdr *)elfptr;
        phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */
 
-       /* First program header is PT_NOTE header. */
-       vmcore_off = sizeof(Elf64_Ehdr) +
-                       (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr) +
-                       phdr_ptr->p_memsz; /* Note sections */
+       /* Skip Elf header, program headers and Elf note segment. */
+       vmcore_off = elfsz + elfnotes_sz;
 
        for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+               u64 paddr, start, end, size;
+
                if (phdr_ptr->p_type != PT_LOAD)
                        continue;
 
+               paddr = phdr_ptr->p_offset;
+               start = rounddown(paddr, PAGE_SIZE);
+               end = roundup(paddr + phdr_ptr->p_memsz, PAGE_SIZE);
+               size = end - start;
+
                /* Add this contiguous chunk of memory to vmcore list.*/
                new = get_new_element();
                if (!new)
                        return -ENOMEM;
-               new->paddr = phdr_ptr->p_offset;
-               new->size = phdr_ptr->p_memsz;
+               new->paddr = start;
+               new->size = size;
                list_add_tail(&new->list, vc_list);
 
                /* Update the program header offset. */
-               phdr_ptr->p_offset = vmcore_off;
-               vmcore_off = vmcore_off + phdr_ptr->p_memsz;
+               phdr_ptr->p_offset = vmcore_off + (paddr - start);
+               vmcore_off = vmcore_off + size;
        }
        return 0;
 }
 
 static int __init process_ptload_program_headers_elf32(char *elfptr,
                                                size_t elfsz,
+                                               size_t elfnotes_sz,
                                                struct list_head *vc_list)
 {
        int i;
@@ -462,43 +748,44 @@ static int __init process_ptload_program_headers_elf32(char *elfptr,
        ehdr_ptr = (Elf32_Ehdr *)elfptr;
        phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */
 
-       /* First program header is PT_NOTE header. */
-       vmcore_off = sizeof(Elf32_Ehdr) +
-                       (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr) +
-                       phdr_ptr->p_memsz; /* Note sections */
+       /* Skip Elf header, program headers and Elf note segment. */
+       vmcore_off = elfsz + elfnotes_sz;
 
        for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+               u64 paddr, start, end, size;
+
                if (phdr_ptr->p_type != PT_LOAD)
                        continue;
 
+               paddr = phdr_ptr->p_offset;
+               start = rounddown(paddr, PAGE_SIZE);
+               end = roundup(paddr + phdr_ptr->p_memsz, PAGE_SIZE);
+               size = end - start;
+
                /* Add this contiguous chunk of memory to vmcore list.*/
                new = get_new_element();
                if (!new)
                        return -ENOMEM;
-               new->paddr = phdr_ptr->p_offset;
-               new->size = phdr_ptr->p_memsz;
+               new->paddr = start;
+               new->size = size;
                list_add_tail(&new->list, vc_list);
 
                /* Update the program header offset */
-               phdr_ptr->p_offset = vmcore_off;
-               vmcore_off = vmcore_off + phdr_ptr->p_memsz;
+               phdr_ptr->p_offset = vmcore_off + (paddr - start);
+               vmcore_off = vmcore_off + size;
        }
        return 0;
 }
 
 /* Sets offset fields of vmcore elements. */
-static void __init set_vmcore_list_offsets_elf64(char *elfptr,
-                                               struct list_head *vc_list)
+static void __init set_vmcore_list_offsets(size_t elfsz, size_t elfnotes_sz,
+                                          struct list_head *vc_list)
 {
        loff_t vmcore_off;
-       Elf64_Ehdr *ehdr_ptr;
        struct vmcore *m;
 
-       ehdr_ptr = (Elf64_Ehdr *)elfptr;
-
-       /* Skip Elf header and program headers. */
-       vmcore_off = sizeof(Elf64_Ehdr) +
-                       (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr);
+       /* Skip Elf header, program headers and Elf note segment. */
+       vmcore_off = elfsz + elfnotes_sz;
 
        list_for_each_entry(m, vc_list, list) {
                m->offset = vmcore_off;
@@ -506,24 +793,12 @@ static void __init set_vmcore_list_offsets_elf64(char *elfptr,
        }
 }
 
-/* Sets offset fields of vmcore elements. */
-static void __init set_vmcore_list_offsets_elf32(char *elfptr,
-                                               struct list_head *vc_list)
+static void free_elfcorebuf(void)
 {
-       loff_t vmcore_off;
-       Elf32_Ehdr *ehdr_ptr;
-       struct vmcore *m;
-
-       ehdr_ptr = (Elf32_Ehdr *)elfptr;
-
-       /* Skip Elf header and program headers. */
-       vmcore_off = sizeof(Elf32_Ehdr) +
-                       (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr);
-
-       list_for_each_entry(m, vc_list, list) {
-               m->offset = vmcore_off;
-               vmcore_off += m->size;
-       }
+       free_pages((unsigned long)elfcorebuf, get_order(elfcorebuf_sz_orig));
+       elfcorebuf = NULL;
+       vfree(elfnotes_buf);
+       elfnotes_buf = NULL;
 }
 
 static int __init parse_crash_elf64_headers(void)
@@ -554,31 +829,32 @@ static int __init parse_crash_elf64_headers(void)
        }
 
        /* Read in all elf headers. */
-       elfcorebuf_sz = sizeof(Elf64_Ehdr) + ehdr.e_phnum * sizeof(Elf64_Phdr);
-       elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL);
+       elfcorebuf_sz_orig = sizeof(Elf64_Ehdr) +
+                               ehdr.e_phnum * sizeof(Elf64_Phdr);
+       elfcorebuf_sz = elfcorebuf_sz_orig;
+       elfcorebuf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+                                             get_order(elfcorebuf_sz_orig));
        if (!elfcorebuf)
                return -ENOMEM;
        addr = elfcorehdr_addr;
-       rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0);
-       if (rc < 0) {
-               kfree(elfcorebuf);
-               return rc;
-       }
+       rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz_orig, &addr, 0);
+       if (rc < 0)
+               goto fail;
 
        /* Merge all PT_NOTE headers into one. */
-       rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
-       if (rc) {
-               kfree(elfcorebuf);
-               return rc;
-       }
+       rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz,
+                                     &elfnotes_buf, &elfnotes_sz);
+       if (rc)
+               goto fail;
        rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz,
-                                                       &vmcore_list);
-       if (rc) {
-               kfree(elfcorebuf);
-               return rc;
-       }
-       set_vmcore_list_offsets_elf64(elfcorebuf, &vmcore_list);
+                                                 elfnotes_sz, &vmcore_list);
+       if (rc)
+               goto fail;
+       set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list);
        return 0;
+fail:
+       free_elfcorebuf();
+       return rc;
 }
 
 static int __init parse_crash_elf32_headers(void)
@@ -609,31 +885,31 @@ static int __init parse_crash_elf32_headers(void)
        }
 
        /* Read in all elf headers. */
-       elfcorebuf_sz = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr);
-       elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL);
+       elfcorebuf_sz_orig = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr);
+       elfcorebuf_sz = elfcorebuf_sz_orig;
+       elfcorebuf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+                                             get_order(elfcorebuf_sz_orig));
        if (!elfcorebuf)
                return -ENOMEM;
        addr = elfcorehdr_addr;
-       rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0);
-       if (rc < 0) {
-               kfree(elfcorebuf);
-               return rc;
-       }
+       rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz_orig, &addr, 0);
+       if (rc < 0)
+               goto fail;
 
        /* Merge all PT_NOTE headers into one. */
-       rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
-       if (rc) {
-               kfree(elfcorebuf);
-               return rc;
-       }
+       rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz,
+                                     &elfnotes_buf, &elfnotes_sz);
+       if (rc)
+               goto fail;
        rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz,
-                                                               &vmcore_list);
-       if (rc) {
-               kfree(elfcorebuf);
-               return rc;
-       }
-       set_vmcore_list_offsets_elf32(elfcorebuf, &vmcore_list);
+                                                 elfnotes_sz, &vmcore_list);
+       if (rc)
+               goto fail;
+       set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list);
        return 0;
+fail:
+       free_elfcorebuf();
+       return rc;
 }
 
 static int __init parse_crash_elf_headers(void)
@@ -655,20 +931,19 @@ static int __init parse_crash_elf_headers(void)
                rc = parse_crash_elf64_headers();
                if (rc)
                        return rc;
-
-               /* Determine vmcore size. */
-               vmcore_size = get_vmcore_size_elf64(elfcorebuf);
        } else if (e_ident[EI_CLASS] == ELFCLASS32) {
                rc = parse_crash_elf32_headers();
                if (rc)
                        return rc;
-
-               /* Determine vmcore size. */
-               vmcore_size = get_vmcore_size_elf32(elfcorebuf);
        } else {
                pr_warn("Warning: Core image elf header is not sane\n");
                return -EINVAL;
        }
+
+       /* Determine vmcore size. */
+       vmcore_size = get_vmcore_size(elfcorebuf_sz, elfnotes_sz,
+                                     &vmcore_list);
+
        return 0;
 }
 
@@ -711,7 +986,6 @@ void vmcore_cleanup(void)
                list_del(&m->list);
                kfree(m);
        }
-       kfree(elfcorebuf);
-       elfcorebuf = NULL;
+       free_elfcorebuf();
 }
 EXPORT_SYMBOL_GPL(vmcore_cleanup);
index e4bcb2cf055a1dc8f81df7cbb38e8cdab4add0b0..bfd95bf38005cba25bc5cece73555701b25c76f2 100644 (file)
@@ -178,6 +178,8 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry)
        if (p->psi->erase)
                p->psi->erase(p->type, p->id, p->count,
                              dentry->d_inode->i_ctime, p->psi);
+       else
+               return -EPERM;
 
        return simple_unlink(dir, dentry);
 }
index 86d1038b5a1292b464c561ba7086518cdd7eaf80..b7ffe2bcd9c47283bd9d5361403901db13988e8e 100644 (file)
@@ -239,17 +239,15 @@ int pstore_register(struct pstore_info *psi)
 {
        struct module *owner = psi->owner;
 
+       if (backend && strcmp(backend, psi->name))
+               return -EPERM;
+
        spin_lock(&pstore_lock);
        if (psinfo) {
                spin_unlock(&pstore_lock);
                return -EBUSY;
        }
 
-       if (backend && strcmp(backend, psi->name)) {
-               spin_unlock(&pstore_lock);
-               return -EINVAL;
-       }
-
        if (!psi->write)
                psi->write = pstore_write_compat;
        psinfo = psi;
@@ -274,6 +272,9 @@ int pstore_register(struct pstore_info *psi)
                add_timer(&pstore_timer);
        }
 
+       pr_info("pstore: Registered %s as persistent store backend\n",
+               psi->name);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(pstore_register);
index 1376e5a8f0d6c6cfa430f87ed31d36cc9af5e007..43abee2c6cb95c07dbd202976276103693524c9c 100644 (file)
@@ -399,8 +399,6 @@ static int ramoops_probe(struct platform_device *pdev)
                goto fail_out;
        }
 
-       if (!is_power_of_2(pdata->mem_size))
-               pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
        if (!is_power_of_2(pdata->record_size))
                pdata->record_size = rounddown_pow_of_two(pdata->record_size);
        if (!is_power_of_2(pdata->console_size))
index 59337326e288fda783d4ff3aa8894cd1cd0253b1..de272d4267634f220e61a436c9fc5a7d9f5d3083 100644 (file)
@@ -46,7 +46,7 @@ static inline size_t buffer_start(struct persistent_ram_zone *prz)
 }
 
 /* increase and wrap the start pointer, returning the old value */
-static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
+static size_t buffer_start_add_atomic(struct persistent_ram_zone *prz, size_t a)
 {
        int old;
        int new;
@@ -62,7 +62,7 @@ static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
 }
 
 /* increase the size counter until it hits the max size */
-static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
+static void buffer_size_add_atomic(struct persistent_ram_zone *prz, size_t a)
 {
        size_t old;
        size_t new;
@@ -78,6 +78,53 @@ static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
        } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
 }
 
+static DEFINE_RAW_SPINLOCK(buffer_lock);
+
+/* increase and wrap the start pointer, returning the old value */
+static size_t buffer_start_add_locked(struct persistent_ram_zone *prz, size_t a)
+{
+       int old;
+       int new;
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&buffer_lock, flags);
+
+       old = atomic_read(&prz->buffer->start);
+       new = old + a;
+       while (unlikely(new > prz->buffer_size))
+               new -= prz->buffer_size;
+       atomic_set(&prz->buffer->start, new);
+
+       raw_spin_unlock_irqrestore(&buffer_lock, flags);
+
+       return old;
+}
+
+/* increase the size counter until it hits the max size */
+static void buffer_size_add_locked(struct persistent_ram_zone *prz, size_t a)
+{
+       size_t old;
+       size_t new;
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&buffer_lock, flags);
+
+       old = atomic_read(&prz->buffer->size);
+       if (old == prz->buffer_size)
+               goto exit;
+
+       new = old + a;
+       if (new > prz->buffer_size)
+               new = prz->buffer_size;
+       atomic_set(&prz->buffer->size, new);
+
+exit:
+       raw_spin_unlock_irqrestore(&buffer_lock, flags);
+}
+
+static size_t (*buffer_start_add)(struct persistent_ram_zone *, size_t) = buffer_start_add_atomic;
+static void (*buffer_size_add)(struct persistent_ram_zone *, size_t) = buffer_size_add_atomic;
+
 static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
        uint8_t *data, size_t len, uint8_t *ecc)
 {
@@ -372,6 +419,9 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size)
                return NULL;
        }
 
+       buffer_start_add = buffer_start_add_locked;
+       buffer_size_add = buffer_size_add_locked;
+
        return ioremap(start, size);
 }
 
index 2cefa417be349b0016ffa8606635db9e85751015..122a3846d9e14270a26952e92b25971257ebd82b 100644 (file)
@@ -41,8 +41,19 @@ static inline int unsigned_offsets(struct file *file)
        return file->f_mode & FMODE_UNSIGNED_OFFSET;
 }
 
-static loff_t lseek_execute(struct file *file, struct inode *inode,
-               loff_t offset, loff_t maxsize)
+/**
+ * vfs_setpos - update the file offset for lseek
+ * @file:      file structure in question
+ * @offset:    file offset to seek to
+ * @maxsize:   maximum file size
+ *
+ * This is a low-level filesystem helper for updating the file offset to
+ * the value specified by @offset if the given offset is valid and it is
+ * not equal to the current file offset.
+ *
+ * Return the specified offset on success and -EINVAL on invalid offset.
+ */
+loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize)
 {
        if (offset < 0 && !unsigned_offsets(file))
                return -EINVAL;
@@ -55,6 +66,7 @@ static loff_t lseek_execute(struct file *file, struct inode *inode,
        }
        return offset;
 }
+EXPORT_SYMBOL(vfs_setpos);
 
 /**
  * generic_file_llseek_size - generic llseek implementation for regular files
@@ -76,8 +88,6 @@ loff_t
 generic_file_llseek_size(struct file *file, loff_t offset, int whence,
                loff_t maxsize, loff_t eof)
 {
-       struct inode *inode = file->f_mapping->host;
-
        switch (whence) {
        case SEEK_END:
                offset += eof;
@@ -97,8 +107,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence,
                 * like SEEK_SET.
                 */
                spin_lock(&file->f_lock);
-               offset = lseek_execute(file, inode, file->f_pos + offset,
-                                      maxsize);
+               offset = vfs_setpos(file, file->f_pos + offset, maxsize);
                spin_unlock(&file->f_lock);
                return offset;
        case SEEK_DATA:
@@ -120,7 +129,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence,
                break;
        }
 
-       return lseek_execute(file, inode, offset, maxsize);
+       return vfs_setpos(file, offset, maxsize);
 }
 EXPORT_SYMBOL(generic_file_llseek_size);
 
@@ -144,6 +153,26 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int whence)
 }
 EXPORT_SYMBOL(generic_file_llseek);
 
+/**
+ * fixed_size_llseek - llseek implementation for fixed-sized devices
+ * @file:      file structure to seek on
+ * @offset:    file offset to seek to
+ * @whence:    type of seek
+ * @size:      size of the file
+ *
+ */
+loff_t fixed_size_llseek(struct file *file, loff_t offset, int whence, loff_t size)
+{
+       switch (whence) {
+       case SEEK_SET: case SEEK_CUR: case SEEK_END:
+               return generic_file_llseek_size(file, offset, whence,
+                                               size, size);
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL(fixed_size_llseek);
+
 /**
  * noop_llseek - No Operation Performed llseek implementation
  * @file:      file structure to seek on
@@ -296,7 +325,7 @@ out_putf:
  * them to something that fits in "int" so that others
  * won't have to do range checks all the time.
  */
-int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
+int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count)
 {
        struct inode *inode;
        loff_t pos;
@@ -477,7 +506,8 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_read(f.file, buf, count, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
        return ret;
@@ -492,7 +522,8 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_write(f.file, buf, count, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
 
@@ -780,7 +811,8 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_readv(f.file, vec, vlen, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
 
@@ -799,7 +831,8 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
        if (f.file) {
                loff_t pos = file_pos_read(f.file);
                ret = vfs_writev(f.file, vec, vlen, &pos);
-               file_pos_write(f.file, pos);
+               if (ret >= 0)
+                       file_pos_write(f.file, pos);
                fdput(f);
        }
 
@@ -959,7 +992,8 @@ COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd,
                return -EBADF;
        pos = f.file->f_pos;
        ret = compat_readv(f.file, vec, vlen, &pos);
-       f.file->f_pos = pos;
+       if (ret >= 0)
+               f.file->f_pos = pos;
        fdput(f);
        return ret;
 }
@@ -1025,7 +1059,8 @@ COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd,
                return -EBADF;
        pos = f.file->f_pos;
        ret = compat_writev(f.file, vec, vlen, &pos);
-       f.file->f_pos = pos;
+       if (ret >= 0)
+               f.file->f_pos = pos;
        fdput(f);
        return ret;
 }
@@ -1129,7 +1164,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
        if (in.file->f_flags & O_NONBLOCK)
                fl = SPLICE_F_NONBLOCK;
 #endif
+       file_start_write(out.file);
        retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl);
+       file_end_write(out.file);
 
        if (retval > 0) {
                add_rchar(current, retval);
index 8c1c96c27062a504bfc151f33d335fcd8f6779b5..6b14dc7df3a46df3293da538abc2d65b3b67f94f 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/rcupdate.h>
 #include <linux/hrtimer.h>
 #include <linux/sched/rt.h>
+#include <linux/freezer.h>
 
 #include <asm/uaccess.h>
 
@@ -236,7 +237,8 @@ int poll_schedule_timeout(struct poll_wqueues *pwq, int state,
 
        set_current_state(state);
        if (!pwq->triggered)
-               rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS);
+               rc = freezable_schedule_hrtimeout_range(expires, slack,
+                                                       HRTIMER_MODE_ABS);
        __set_current_state(TASK_RUNNING);
 
        /*
index d37431dd60a1009f224d4c1bdc65b4fff505d2db..3b7ee656f3aaeacd719955b2bba80fd5d8d43b0a 100644 (file)
@@ -1098,27 +1098,13 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
 {
        ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
                                loff_t *, size_t, unsigned int);
-       int ret;
-
-       if (unlikely(!(out->f_mode & FMODE_WRITE)))
-               return -EBADF;
-
-       if (unlikely(out->f_flags & O_APPEND))
-               return -EINVAL;
-
-       ret = rw_verify_area(WRITE, out, ppos, len);
-       if (unlikely(ret < 0))
-               return ret;
 
        if (out->f_op && out->f_op->splice_write)
                splice_write = out->f_op->splice_write;
        else
                splice_write = default_file_splice_write;
 
-       file_start_write(out);
-       ret = splice_write(pipe, out, ppos, len, flags);
-       file_end_write(out);
-       return ret;
+       return splice_write(pipe, out, ppos, len, flags);
 }
 
 /*
@@ -1307,6 +1293,16 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
        };
        long ret;
 
+       if (unlikely(!(out->f_mode & FMODE_WRITE)))
+               return -EBADF;
+
+       if (unlikely(out->f_flags & O_APPEND))
+               return -EINVAL;
+
+       ret = rw_verify_area(WRITE, out, opos, len);
+       if (unlikely(ret < 0))
+               return ret;
+
        ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
        if (ret > 0)
                *ppos = sd.pos;
@@ -1362,7 +1358,19 @@ static long do_splice(struct file *in, loff_t __user *off_in,
                        offset = out->f_pos;
                }
 
+               if (unlikely(!(out->f_mode & FMODE_WRITE)))
+                       return -EBADF;
+
+               if (unlikely(out->f_flags & O_APPEND))
+                       return -EINVAL;
+
+               ret = rw_verify_area(WRITE, out, &offset, len);
+               if (unlikely(ret < 0))
+                       return ret;
+
+               file_start_write(out);
                ret = do_splice_from(ipipe, out, &offset, len, flags);
+               file_end_write(out);
 
                if (!off_out)
                        out->f_pos = offset;
index 1c0d5f264767df5ebc7bf0dc77a0267b097a4052..731b2bbcaab37f7e8d4da84dcc9e9600d3b4e969 100644 (file)
@@ -27,8 +27,7 @@ static int add_nondir(struct dentry *dentry, struct inode *inode)
        return err;
 }
 
-static int sysv_hash(const struct dentry *dentry, const struct inode *inode,
-               struct qstr *qstr)
+static int sysv_hash(const struct dentry *dentry, struct qstr *qstr)
 {
        /* Truncate the name in place, avoids having to define a compare
           function. */
index 102c072c6bbfed3d76541b2c3766d89c9272d2ca..5f6fc17d6bc5c0694fa357b739a290e608da9588 100644 (file)
@@ -594,6 +594,29 @@ static int udf_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        return 0;
 }
 
+static int udf_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       struct inode *inode;
+       struct udf_inode_info *iinfo;
+       int err;
+
+       inode = udf_new_inode(dir, mode, &err);
+       if (!inode)
+               return err;
+
+       iinfo = UDF_I(inode);
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+               inode->i_data.a_ops = &udf_adinicb_aops;
+       else
+               inode->i_data.a_ops = &udf_aops;
+       inode->i_op = &udf_file_inode_operations;
+       inode->i_fop = &udf_file_operations;
+       mark_inode_dirty(inode);
+
+       d_tmpfile(dentry, inode);
+       return 0;
+}
+
 static int udf_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
                     dev_t rdev)
 {
@@ -1311,6 +1334,7 @@ const struct inode_operations udf_dir_inode_operations = {
        .rmdir                          = udf_rmdir,
        .mknod                          = udf_mknod,
        .rename                         = udf_rename,
+       .tmpfile                        = udf_tmpfile,
 };
 const struct inode_operations udf_symlink_inode_operations = {
        .readlink       = generic_readlink,
index 0ad2b95fca12fbd215b9eb63f84b2bd7c21b6609..de3dc98f4e8f76067c1e7d0ee4631a8638d87988 100644 (file)
@@ -1268,8 +1268,7 @@ xfs_seek_data(
        }
 
 out:
-       if (offset != file->f_pos)
-               file->f_pos = offset;
+       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out_unlock:
        xfs_iunlock_map_shared(ip, lock);
@@ -1377,8 +1376,7 @@ out:
         * situation in particular.
         */
        offset = min_t(loff_t, offset, isize);
-       if (offset != file->f_pos)
-               file->f_pos = offset;
+       offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
 
 out_unlock:
        xfs_iunlock_map_shared(ip, lock);
index 14ceff788c40b75cc7e7240db5bb07587d6ec783..1c16f821434f9c2ffee4ea793605800fa99a56b4 100644 (file)
  *
  *****************************************************************************/
 
-#define ACPI_DEBUGGER_MAX_ARGS          8      /* Must be max method args + 1 */
-#define ACPI_DB_LINE_BUFFER_SIZE       512
+#define ACPI_DEBUGGER_MAX_ARGS          ACPI_METHOD_NUM_ARGS + 4       /* Max command line arguments */
+#define ACPI_DB_LINE_BUFFER_SIZE        512
 
 #define ACPI_DEBUGGER_COMMAND_PROMPT    '-'
 #define ACPI_DEBUGGER_EXECUTE_PROMPT    '%'
index 4f52ea795c7ac2e5e39ff97703ad71ebe705351f..4607b027a6577111d3179d07cc292e25ba8de493 100644 (file)
  * This is the non-debug case -- make everything go away,
  * leaving no executable debug code!
  */
-#define ACPI_FUNCTION_NAME(a)
 #define ACPI_DEBUG_PRINT(pl)
 #define ACPI_DEBUG_PRINT_RAW(pl)
 #define ACPI_DEBUG_EXEC(a)
 #define ACPI_DEBUG_ONLY_MEMBERS(a)
+#define ACPI_FUNCTION_NAME(a)
 #define ACPI_FUNCTION_TRACE(a)
 #define ACPI_FUNCTION_TRACE_PTR(a, b)
 #define ACPI_FUNCTION_TRACE_U32(a, b)
 #define ACPI_FUNCTION_TRACE_STR(a, b)
-#define ACPI_FUNCTION_EXIT
-#define ACPI_FUNCTION_STATUS_EXIT(s)
-#define ACPI_FUNCTION_VALUE_EXIT(s)
 #define ACPI_FUNCTION_ENTRY()
 #define ACPI_DUMP_STACK_ENTRY(a)
 #define ACPI_DUMP_OPERANDS(a, b, c)
 #define ACPI_DUMP_ENTRY(a, b)
-#define ACPI_DUMP_TABLES(a, b)
 #define ACPI_DUMP_PATHNAME(a, b, c, d)
 #define ACPI_DUMP_BUFFER(a, b)
-#define ACPI_DEBUG_PRINT(pl)
-#define ACPI_DEBUG_PRINT_RAW(pl)
 #define ACPI_IS_DEBUG_ENABLED(level, component) 0
 
 /* Return macros must have a return statement at the minimum */
index c13c919ab99e9803b2ebe18d36eb93ab98bf6076..56e6b68c8d2fcb36fae154ebe6bb687f9e74760d 100644 (file)
@@ -63,13 +63,6 @@ acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld
 #define ACPI_BUS_FILE_ROOT     "acpi"
 extern struct proc_dir_entry *acpi_root_dir;
 
-enum acpi_bus_removal_type {
-       ACPI_BUS_REMOVAL_NORMAL = 0,
-       ACPI_BUS_REMOVAL_EJECT,
-       ACPI_BUS_REMOVAL_SUPRISE,
-       ACPI_BUS_REMOVAL_TYPE_COUNT
-};
-
 enum acpi_bus_device_type {
        ACPI_BUS_TYPE_DEVICE = 0,
        ACPI_BUS_TYPE_POWER,
@@ -163,12 +156,10 @@ struct acpi_device_flags {
        u32 dynamic_status:1;
        u32 removable:1;
        u32 ejectable:1;
-       u32 suprise_removal_ok:1;
        u32 power_manageable:1;
-       u32 performance_manageable:1;
        u32 eject_pending:1;
        u32 match_driver:1;
-       u32 reserved:24;
+       u32 reserved:26;
 };
 
 /* File System */
@@ -286,6 +277,7 @@ struct acpi_device_physical_node {
        u8 node_id;
        struct list_head node;
        struct device *dev;
+       bool put_online:1;
 };
 
 /* set maximum of physical nodes to 32 for expansibility */
@@ -310,7 +302,6 @@ struct acpi_device {
        struct acpi_driver *driver;
        void *driver_data;
        struct device dev;
-       enum acpi_bus_removal_type removal_type;        /* indicate for different removal type */
        u8 physical_node_count;
        struct list_head physical_node_list;
        struct mutex physical_node_lock;
@@ -443,7 +434,6 @@ int register_acpi_bus_type(struct acpi_bus_type *);
 int unregister_acpi_bus_type(struct acpi_bus_type *);
 
 struct acpi_pci_root {
-       struct list_head node;
        struct acpi_device * device;
        struct pci_bus *bus;
        u16 segment;
@@ -468,8 +458,6 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
                                 acpi_notify_handler handler, void *context);
 acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
                                    acpi_notify_handler handler);
-int acpi_device_power_state(struct device *dev, struct acpi_device *adev,
-                           u32 target_state, int d_max_in, int *d_min_p);
 int acpi_pm_device_sleep_state(struct device *, int *, int);
 void acpi_dev_pm_add_dependent(acpi_handle handle, struct device *depdev);
 void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev);
@@ -485,23 +473,13 @@ static inline acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
 {
        return AE_SUPPORT;
 }
-static inline int __acpi_device_power_state(int m, int *p)
+static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m)
 {
        if (p)
                *p = ACPI_STATE_D0;
+
        return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3) ? m : ACPI_STATE_D0;
 }
-static inline int acpi_device_power_state(struct device *dev,
-                                         struct acpi_device *adev,
-                                         u32 target_state, int d_max_in,
-                                         int *d_min_p)
-{
-       return __acpi_device_power_state(d_max_in, d_min_p);
-}
-static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m)
-{
-       return __acpi_device_power_state(m, p);
-}
 static inline void acpi_dev_pm_add_dependent(acpi_handle handle,
                                             struct device *depdev) {}
 static inline void acpi_dev_pm_remove_dependent(acpi_handle handle,
index 454881e6450a4493eabf6fa5de03fd005fccc761..1b09300810e647dc71fbd7b490cd081ef7c0862d 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20130328
+#define ACPI_CA_VERSION                 0x20130517
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
@@ -80,6 +80,7 @@ extern bool acpi_gbl_enable_aml_debug_object;
 extern u8 acpi_gbl_copy_dsdt_locally;
 extern u8 acpi_gbl_truncate_io_addresses;
 extern u8 acpi_gbl_disable_auto_repair;
+extern u8 acpi_gbl_disable_ssdt_table_load;
 
 /*
  * Hardware-reduced prototypes. All interfaces that use these macros will
index ea69367fdd3bbafaf1775da248c7cc998c47fba8..66096d06925e417d70d6b8974a00a035d05ef1d8 100644 (file)
@@ -6,6 +6,10 @@
 #include <linux/thermal.h>
 #include <asm/acpi.h>
 
+#define ACPI_PROCESSOR_CLASS           "processor"
+#define ACPI_PROCESSOR_DEVICE_NAME     "Processor"
+#define ACPI_PROCESSOR_DEVICE_HID      "ACPI0007"
+
 #define ACPI_PROCESSOR_BUSY_METRIC     10
 
 #define ACPI_PROCESSOR_MAX_POWER       8
@@ -207,6 +211,7 @@ struct acpi_processor {
        struct acpi_processor_throttling throttling;
        struct acpi_processor_limit limit;
        struct thermal_cooling_device *cdev;
+       struct device *dev; /* Processor device. */
 };
 
 struct acpi_processor_errata {
index f104af7cf4375f045af902af4315834ae41460c2..d4f9fb4e53dfa7ea2709bc63f5c98f7c72e64cf0 100644 (file)
@@ -28,17 +28,15 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
  *                                 from 1 to a 0 value
  *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 1
  *
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns.
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
  */
 static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count)
 {
        if (unlikely(atomic_dec_return(count) < 0))
-               return fail_fn(count);
+               return -1;
        return 0;
 }
 
index e1bbbc72b6a257adc7b5c1ad0dc95b9d615e0872..61069ed334e2208a31b2d15c4973bea9844db57a 100644 (file)
@@ -11,7 +11,7 @@
 #define _ASM_GENERIC_MUTEX_NULL_H
 
 #define __mutex_fastpath_lock(count, fail_fn)          fail_fn(count)
-#define __mutex_fastpath_lock_retval(count, fail_fn)   fail_fn(count)
+#define __mutex_fastpath_lock_retval(count)            (-1)
 #define __mutex_fastpath_unlock(count, fail_fn)                fail_fn(count)
 #define __mutex_fastpath_trylock(count, fail_fn)       fail_fn(count)
 #define __mutex_slowpath_needs_to_unlock()             1
index c04e0db8a2d6df273472a04bfb882aecdc0d54ce..f169ec064785beea6c8ce4f1bee1d193a9faf079 100644 (file)
@@ -39,18 +39,16 @@ __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
  *                                 from 1 to a 0 value
  *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 1
  *
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if it
- * wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns
+ * Change the count from 1 to a value lower than 1. This function returns 0
+ * if the fastpath succeeds, or -1 otherwise.
  */
 static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
+__mutex_fastpath_lock_retval(atomic_t *count)
 {
        if (unlikely(atomic_xchg(count, 0) != 1))
                if (likely(atomic_xchg(count, -1) != 1))
-                       return fail_fn(count);
+                       return -1;
        return 0;
 }
 
index b1836987d5063f390622458683e79c4ca84b11ef..a7126d28f4cf8786c51aeb5edfd2e6cc351785f7 100644 (file)
@@ -396,6 +396,28 @@ static inline void ptep_modify_prot_commit(struct mm_struct *mm,
 #define arch_start_context_switch(prev)        do {} while (0)
 #endif
 
+#ifndef CONFIG_HAVE_ARCH_SOFT_DIRTY
+static inline int pte_soft_dirty(pte_t pte)
+{
+       return 0;
+}
+
+static inline int pmd_soft_dirty(pmd_t pmd)
+{
+       return 0;
+}
+
+static inline pte_t pte_mksoft_dirty(pte_t pte)
+{
+       return pte;
+}
+
+static inline pmd_t pmd_mksoft_dirty(pmd_t pmd)
+{
+       return pmd;
+}
+#endif
+
 #ifndef __HAVE_PFNMAP_TRACKING
 /*
  * Interfaces that can be used by architecture code to keep track of
index c1a1216e29ced8ad92dac7c089991e7bf97bd2c3..f1a24b5c3b906ef91804bca4f6f56b4158d93aca 100644 (file)
@@ -3,6 +3,26 @@
 
 /* References to section boundaries */
 
+/*
+ * Usage guidelines:
+ * _text, _data: architecture specific, don't use them in arch-independent code
+ * [_stext, _etext]: contains .text.* sections, may also contain .rodata.*
+ *                   and/or .init.* sections
+ * [_sdata, _edata]: contains .data.* sections, may also contain .rodata.*
+ *                   and/or .init.* sections.
+ * [__start_rodata, __end_rodata]: contains .rodata.* sections
+ * [__init_begin, __init_end]: contains .init.* sections, but .init.text.*
+ *                   may be out of this range on some architectures.
+ * [_sinittext, _einittext]: contains .init.text.* sections
+ * [__bss_start, __bss_stop]: contains BSS sections
+ *
+ * Following global variables are optional and may be unavailable on some
+ * architectures and/or kernel configurations.
+ *     _text, _data
+ *     __kprobes_text_start, __kprobes_text_end
+ *     __entry_text_start, __entry_text_end
+ *     __ctors_start, __ctors_end
+ */
 extern char _text[], _stext[], _etext[];
 extern char _data[], _sdata[], _edata[];
 extern char __bss_start[], __bss_stop[];
@@ -12,7 +32,6 @@ extern char _end[];
 extern char __per_cpu_load[], __per_cpu_start[], __per_cpu_end[];
 extern char __kprobes_text_start[], __kprobes_text_end[];
 extern char __entry_text_start[], __entry_text_end[];
-extern char __initdata_begin[], __initdata_end[];
 extern char __start_rodata[], __end_rodata[];
 
 /* Start and end of .ctors section - used for constructor calls. */
index c184aa8ec8cd5c81f189ff9350e52e6e27e5b2a6..dc1269c74a52077b389b30d72523a1530a336eee 100644 (file)
@@ -163,7 +163,7 @@ static inline __must_check long __copy_to_user(void __user *to,
 
 #define put_user(x, ptr)                                       \
 ({                                                             \
-       might_sleep();                                          \
+       might_fault();                                          \
        access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)) ?            \
                __put_user(x, ptr) :                            \
                -EFAULT;                                        \
@@ -225,7 +225,7 @@ extern int __put_user_bad(void) __attribute__((noreturn));
 
 #define get_user(x, ptr)                                       \
 ({                                                             \
-       might_sleep();                                          \
+       might_fault();                                          \
        access_ok(VERIFY_READ, ptr, sizeof(*ptr)) ?             \
                __get_user(x, ptr) :                            \
                -EFAULT;                                        \
@@ -255,7 +255,7 @@ extern int __get_user_bad(void) __attribute__((noreturn));
 static inline long copy_from_user(void *to,
                const void __user * from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (access_ok(VERIFY_READ, from, n))
                return __copy_from_user(to, from, n);
        else
@@ -265,7 +265,7 @@ static inline long copy_from_user(void *to,
 static inline long copy_to_user(void __user *to,
                const void *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (access_ok(VERIFY_WRITE, to, n))
                return __copy_to_user(to, from, n);
        else
@@ -336,7 +336,7 @@ __clear_user(void __user *to, unsigned long n)
 static inline __must_check unsigned long
 clear_user(void __user *to, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (!access_ok(VERIFY_WRITE, to, n))
                return n;
 
index 4f2737208c4275063702dbf6009cec6b600c4744..c74d88baea60edd077a22be9c909790fe51fb60a 100644 (file)
                VMLINUX_SYMBOL(__end_builtin_fw) = .;                   \
        }                                                               \
                                                                        \
-       /* RapidIO route ops */                                         \
-       .rio_ops        : AT(ADDR(.rio_ops) - LOAD_OFFSET) {            \
-               VMLINUX_SYMBOL(__start_rio_switch_ops) = .;             \
-               *(.rio_switch_ops)                                      \
-               VMLINUX_SYMBOL(__end_rio_switch_ops) = .;               \
-       }                                                               \
-                                                                       \
        TRACEDATA                                                       \
                                                                        \
        /* Kernel symbol table: Normal symbols */                       \
index e6c9c4cc9b23415fad39dfd142a6ce3bd44f4b7c..c463ce990c48b9a6f5742a45ac741b91371aae4f 100644 (file)
@@ -32,7 +32,7 @@
 #ifdef CONFIG_ARM_ARCH_TIMER
 
 extern u32 arch_timer_get_rate(void);
-extern u64 (*arch_timer_read_counter)(void);
+extern u64 arch_timer_read_counter(void);
 extern struct timecounter *arch_timer_get_timecounter(void);
 
 #else
diff --git a/include/dt-bindings/pinctrl/rockchip.h b/include/dt-bindings/pinctrl/rockchip.h
new file mode 100644 (file)
index 0000000..cd5788b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Header providing constants for Rockchip pinctrl bindings.
+ *
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.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 __DT_BINDINGS_ROCKCHIP_PINCTRL_H__
+#define __DT_BINDINGS_ROCKCHIP_PINCTRL_H__
+
+#define RK_GPIO0       0
+#define RK_GPIO1       1
+#define RK_GPIO2       2
+#define RK_GPIO3       3
+#define RK_GPIO4       4
+#define RK_GPIO6       6
+
+#define RK_FUNC_GPIO   0
+#define RK_FUNC_1      1
+#define RK_FUNC_2      2
+
+#endif
similarity index 92%
rename from arch/arm/include/asm/kvm_arch_timer.h
rename to include/kvm/arm_arch_timer.h
index 68cb9e1dfb81b50329a03627c05c26db67bc4441..6d9aeddc09bffe4f9068f8e415551c2855233b40 100644 (file)
@@ -61,6 +61,8 @@ struct arch_timer_cpu {
 #ifdef CONFIG_KVM_ARM_TIMER
 int kvm_timer_hyp_init(void);
 int kvm_timer_init(struct kvm *kvm);
+void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
+                         const struct kvm_irq_level *irq);
 void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
 void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu);
 void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu);
@@ -76,6 +78,8 @@ static inline int kvm_timer_init(struct kvm *kvm)
        return 0;
 }
 
+static inline void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
+                                       const struct kvm_irq_level *irq) {}
 static inline void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) {}
 static inline void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) {}
 static inline void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) {}
index 17b5b596764100ae14400437b86e84b0c068291f..353ba256f3681e4f6ddd8b18b9feba61b1d98cec 100644 (file)
@@ -352,8 +352,7 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
 
 /* Enable _OST when all relevant hotplug operations are enabled */
 #if defined(CONFIG_ACPI_HOTPLUG_CPU) &&                        \
-       (defined(CONFIG_ACPI_HOTPLUG_MEMORY) ||         \
-        defined(CONFIG_ACPI_HOTPLUG_MEMORY_MODULE)) && \
+       defined(CONFIG_ACPI_HOTPLUG_MEMORY) &&          \
        defined(CONFIG_ACPI_CONTAINER)
 #define ACPI_HOTPLUG_OST
 #endif
index 737f90ab4b6235abd340b1c47d9308591c138e8b..4dbaa7081530ac7f770bbb7ce5f5211372469ae8 100644 (file)
@@ -7,6 +7,10 @@
 #ifndef _AER_H_
 #define _AER_H_
 
+#define AER_NONFATAL                   0
+#define AER_FATAL                      1
+#define AER_CORRECTABLE                        2
+
 struct aer_header_log_regs {
        unsigned int dw0;
        unsigned int dw1;
@@ -31,9 +35,9 @@ struct aer_capability_regs {
 
 #if defined(CONFIG_PCIEAER)
 /* pci-e port driver needs this function to enable aer */
-extern int pci_enable_pcie_error_reporting(struct pci_dev *dev);
-extern int pci_disable_pcie_error_reporting(struct pci_dev *dev);
-extern int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
+int pci_enable_pcie_error_reporting(struct pci_dev *dev);
+int pci_disable_pcie_error_reporting(struct pci_dev *dev);
+int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
 #else
 static inline int pci_enable_pcie_error_reporting(struct pci_dev *dev)
 {
@@ -49,11 +53,11 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
 }
 #endif
 
-extern void cper_print_aer(struct pci_dev *dev,
-                          int cper_severity, struct aer_capability_regs *aer);
-extern int cper_severity_to_aer(int cper_severity);
-extern void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
-                             int severity,
-                             struct aer_capability_regs *aer_regs);
+void cper_print_aer(struct pci_dev *dev, int cper_severity,
+                   struct aer_capability_regs *aer);
+int cper_severity_to_aer(int cper_severity);
+void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
+                      int severity,
+                      struct aer_capability_regs *aer_regs);
 #endif //_AER_H_
 
index a1c486a88e8856bc572f1c481764833d0987fa16..179b38ffd351323c89c91e90f5ef370e04ebddc7 100644 (file)
@@ -182,10 +182,6 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
             unsigned int src_offset, size_t len,
             struct async_submit_ctl *submit);
 
-struct dma_async_tx_descriptor *
-async_memset(struct page *dest, int val, unsigned int offset,
-            size_t len, struct async_submit_ctl *submit);
-
 struct dma_async_tx_descriptor *async_trigger_callback(struct async_submit_ctl *submit);
 
 struct dma_async_tx_descriptor *
index da9a0825e00718dc182978a6e3d783cbbb6948cd..53b77949c79d4c84b6595614206857e2b6796b1f 100644 (file)
@@ -114,7 +114,13 @@ static inline void backlight_update_status(struct backlight_device *bd)
 extern struct backlight_device *backlight_device_register(const char *name,
        struct device *dev, void *devdata, const struct backlight_ops *ops,
        const struct backlight_properties *props);
+extern struct backlight_device *devm_backlight_device_register(
+       struct device *dev, const char *name, struct device *parent,
+       void *devdata, const struct backlight_ops *ops,
+       const struct backlight_properties *props);
 extern void backlight_device_unregister(struct backlight_device *bd);
+extern void devm_backlight_device_unregister(struct device *dev,
+                                       struct backlight_device *bd);
 extern void backlight_force_update(struct backlight_device *bd,
                                   enum backlight_update_reason reason);
 
index 5f0b0e1f7c08abab8c8701751fe0948667a12149..f1f07d31a3af15fbf34934f502feb54d469e3d26 100644 (file)
@@ -44,8 +44,8 @@ extern unsigned long init_bootmem_node(pg_data_t *pgdat,
                                       unsigned long endpfn);
 extern unsigned long init_bootmem(unsigned long addr, unsigned long memend);
 
-extern unsigned long free_all_bootmem_node(pg_data_t *pgdat);
 extern unsigned long free_all_bootmem(void);
+extern void reset_all_zones_managed_pages(void);
 
 extern void free_bootmem_node(pg_data_t *pgdat,
                              unsigned long addr,
index f5a3b838ddb00639aa1c6669ff60206e1f146507..91fa9a94ae9226f1bdb96864f9c768bd2ea3d3b0 100644 (file)
@@ -139,6 +139,9 @@ BUFFER_FNS(Prio, prio)
        })
 #define page_has_buffers(page) PagePrivate(page)
 
+void buffer_check_dirty_writeback(struct page *page,
+                                    bool *dirty, bool *writeback);
+
 /*
  * Declarations
  */
index 8bda1294c035b24912a3da178ebc2c8e1cd5f827..fd097ecfcd9747849365a0590f91c64f0f7a4479 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/workqueue.h>
 #include <linux/xattr.h>
 #include <linux/fs.h>
+#include <linux/percpu-refcount.h>
 
 #ifdef CONFIG_CGROUPS
 
@@ -72,13 +73,8 @@ struct cgroup_subsys_state {
         */
        struct cgroup *cgroup;
 
-       /*
-        * State maintained by the cgroup system to allow subsystems
-        * to be "busy". Should be accessed via css_get(),
-        * css_tryget() and css_put().
-        */
-
-       atomic_t refcnt;
+       /* reference count - access via css_[try]get() and css_put() */
+       struct percpu_ref refcnt;
 
        unsigned long flags;
        /* ID for this css, if possible */
@@ -94,56 +90,52 @@ enum {
        CSS_ONLINE      = (1 << 1), /* between ->css_online() and ->css_offline() */
 };
 
-/* Caller must verify that the css is not for root cgroup */
-static inline void __css_get(struct cgroup_subsys_state *css, int count)
-{
-       atomic_add(count, &css->refcnt);
-}
-
-/*
- * Call css_get() to hold a reference on the css; it can be used
- * for a reference obtained via:
- * - an existing ref-counted reference to the css
- * - task->cgroups for a locked task
+/**
+ * css_get - obtain a reference on the specified css
+ * @css: target css
+ *
+ * The caller must already have a reference.
  */
-
 static inline void css_get(struct cgroup_subsys_state *css)
 {
        /* We don't need to reference count the root state */
        if (!(css->flags & CSS_ROOT))
-               __css_get(css, 1);
+               percpu_ref_get(&css->refcnt);
 }
 
-/*
- * Call css_tryget() to take a reference on a css if your existing
- * (known-valid) reference isn't already ref-counted. Returns false if
- * the css has been destroyed.
+/**
+ * css_tryget - try to obtain a reference on the specified css
+ * @css: target css
+ *
+ * Obtain a reference on @css if it's alive.  The caller naturally needs to
+ * ensure that @css is accessible but doesn't have to be holding a
+ * reference on it - IOW, RCU protected access is good enough for this
+ * function.  Returns %true if a reference count was successfully obtained;
+ * %false otherwise.
  */
-
-extern bool __css_tryget(struct cgroup_subsys_state *css);
 static inline bool css_tryget(struct cgroup_subsys_state *css)
 {
        if (css->flags & CSS_ROOT)
                return true;
-       return __css_tryget(css);
+       return percpu_ref_tryget(&css->refcnt);
 }
 
-/*
- * css_put() should be called to release a reference taken by
- * css_get() or css_tryget()
+/**
+ * css_put - put a css reference
+ * @css: target css
+ *
+ * Put a reference obtained via css_get() and css_tryget().
  */
-
-extern void __css_put(struct cgroup_subsys_state *css);
 static inline void css_put(struct cgroup_subsys_state *css)
 {
        if (!(css->flags & CSS_ROOT))
-               __css_put(css);
+               percpu_ref_put(&css->refcnt);
 }
 
 /* bits in struct cgroup flags field */
 enum {
        /* Control Group is dead */
-       CGRP_REMOVED,
+       CGRP_DEAD,
        /*
         * Control Group has previously had a child cgroup or a task,
         * but no longer (only if CGRP_NOTIFY_ON_RELEASE is set)
@@ -169,12 +161,6 @@ struct cgroup_name {
 struct cgroup {
        unsigned long flags;            /* "unsigned long" so bitops work */
 
-       /*
-        * count users of this cgroup. >0 means busy, but doesn't
-        * necessarily indicate the number of tasks in the cgroup
-        */
-       atomic_t count;
-
        int id;                         /* ida allocated in-hierarchy ID */
 
        /*
@@ -188,6 +174,14 @@ struct cgroup {
        struct cgroup *parent;          /* my parent */
        struct dentry *dentry;          /* cgroup fs entry, RCU protected */
 
+       /*
+        * Monotonically increasing unique serial number which defines a
+        * uniform order among all cgroups.  It's guaranteed that all
+        * ->children lists are in the ascending order of ->serial_nr.
+        * It's used to allow interrupting and resuming iterations.
+        */
+       u64 serial_nr;
+
        /*
         * This is a copy of dentry->d_name, and it's needed because
         * we can't use dentry->d_name in cgroup_path().
@@ -207,13 +201,10 @@ struct cgroup {
        struct cgroupfs_root *root;
 
        /*
-        * List of cg_cgroup_links pointing at css_sets with
-        * tasks in this cgroup. Protected by css_set_lock
+        * List of cgrp_cset_links pointing at css_sets with tasks in this
+        * cgroup.  Protected by css_set_lock.
         */
-       struct list_head css_sets;
-
-       struct list_head allcg_node;    /* cgroupfs_root->allcg_list */
-       struct list_head cft_q_node;    /* used during cftype add/rm */
+       struct list_head cset_links;
 
        /*
         * Linked list running through all cgroups that can
@@ -229,9 +220,10 @@ struct cgroup {
        struct list_head pidlists;
        struct mutex pidlist_mutex;
 
-       /* For RCU-protected deletion */
+       /* For css percpu_ref killing and RCU-protected deletion */
        struct rcu_head rcu_head;
-       struct work_struct free_work;
+       struct work_struct destroy_work;
+       atomic_t css_kill_cnt;
 
        /* List of events which userspace want to receive */
        struct list_head event_list;
@@ -269,18 +261,33 @@ enum {
         *
         * - Remount is disallowed.
         *
-        * - memcg: use_hierarchy is on by default and the cgroup file for
-        *   the flag is not created.
+        * - rename(2) is disallowed.
         *
-        * The followings are planned changes.
+        * - "tasks" is removed.  Everything should be at process
+        *   granularity.  Use "cgroup.procs" instead.
         *
-        * - release_agent will be disallowed once replacement notification
-        *   mechanism is implemented.
+        * - "release_agent" and "notify_on_release" are removed.
+        *   Replacement notification mechanism will be implemented.
+        *
+        * - cpuset: tasks will be kept in empty cpusets when hotplug happens
+        *   and take masks of ancestors with non-empty cpus/mems, instead of
+        *   being moved to an ancestor.
+        *
+        * - cpuset: a task can be moved into an empty cpuset, and again it
+        *   takes masks of ancestors.
+        *
+        * - memcg: use_hierarchy is on by default and the cgroup file for
+        *   the flag is not created.
         */
        CGRP_ROOT_SANE_BEHAVIOR = (1 << 0),
 
        CGRP_ROOT_NOPREFIX      = (1 << 1), /* mounted subsystems have no named prefix */
        CGRP_ROOT_XATTR         = (1 << 2), /* supports extended attributes */
+
+       /* mount options live below bit 16 */
+       CGRP_ROOT_OPTION_MASK   = (1 << 16) - 1,
+
+       CGRP_ROOT_SUBSYS_BOUND  = (1 << 16), /* subsystems finished binding */
 };
 
 /*
@@ -291,18 +298,12 @@ enum {
 struct cgroupfs_root {
        struct super_block *sb;
 
-       /*
-        * The bitmask of subsystems intended to be attached to this
-        * hierarchy
-        */
+       /* The bitmask of subsystems attached to this hierarchy */
        unsigned long subsys_mask;
 
        /* Unique id for this hierarchy. */
        int hierarchy_id;
 
-       /* The bitmask of subsystems currently attached to this hierarchy */
-       unsigned long actual_subsys_mask;
-
        /* A list running through the attached subsystems */
        struct list_head subsys_list;
 
@@ -315,9 +316,6 @@ struct cgroupfs_root {
        /* A list running through the active hierarchies */
        struct list_head root_list;
 
-       /* All cgroups on this root, cgroup_mutex protected */
-       struct list_head allcg_list;
-
        /* Hierarchy-specific flags */
        unsigned long flags;
 
@@ -357,11 +355,10 @@ struct css_set {
        struct list_head tasks;
 
        /*
-        * List of cg_cgroup_link objects on link chains from
-        * cgroups referenced from this css_set. Protected by
-        * css_set_lock
+        * List of cgrp_cset_links pointing at cgroups referenced from this
+        * css_set.  Protected by css_set_lock.
         */
-       struct list_head cg_links;
+       struct list_head cgrp_links;
 
        /*
         * Set of subsystem states, one for each subsystem. This array
@@ -394,9 +391,11 @@ struct cgroup_map_cb {
  */
 
 /* cftype->flags */
-#define CFTYPE_ONLY_ON_ROOT    (1U << 0)       /* only create on root cg */
-#define CFTYPE_NOT_ON_ROOT     (1U << 1)       /* don't create on root cg */
-#define CFTYPE_INSANE          (1U << 2)       /* don't create if sane_behavior */
+enum {
+       CFTYPE_ONLY_ON_ROOT     = (1 << 0),     /* only create on root cg */
+       CFTYPE_NOT_ON_ROOT      = (1 << 1),     /* don't create on root cg */
+       CFTYPE_INSANE           = (1 << 2),     /* don't create if sane_behavior */
+};
 
 #define MAX_CFTYPE_NAME                64
 
@@ -442,13 +441,13 @@ struct cftype {
         * entry. The key/value pairs (and their ordering) should not
         * change between reboots.
         */
-       int (*read_map)(struct cgroup *cont, struct cftype *cft,
+       int (*read_map)(struct cgroup *cgrp, struct cftype *cft,
                        struct cgroup_map_cb *cb);
        /*
         * read_seq_string() is used for outputting a simple sequence
         * using seqfile.
         */
-       int (*read_seq_string)(struct cgroup *cont, struct cftype *cft,
+       int (*read_seq_string)(struct cgroup *cgrp, struct cftype *cft,
                               struct seq_file *m);
 
        ssize_t (*write)(struct cgroup *cgrp, struct cftype *cft,
@@ -538,10 +537,11 @@ static inline const char *cgroup_name(const struct cgroup *cgrp)
 int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
 int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
 
-int cgroup_is_removed(const struct cgroup *cgrp);
 bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor);
 
 int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen);
+int task_cgroup_path_from_hierarchy(struct task_struct *task, int hierarchy_id,
+                                   char *buf, size_t buflen);
 
 int cgroup_task_count(const struct cgroup *cgrp);
 
@@ -646,22 +646,60 @@ static inline struct cgroup_subsys_state *cgroup_subsys_state(
        return cgrp->subsys[subsys_id];
 }
 
-/*
- * function to get the cgroup_subsys_state which allows for extra
- * rcu_dereference_check() conditions, such as locks used during the
- * cgroup_subsys::attach() methods.
+/**
+ * task_css_set_check - obtain a task's css_set with extra access conditions
+ * @task: the task to obtain css_set for
+ * @__c: extra condition expression to be passed to rcu_dereference_check()
+ *
+ * A task's css_set is RCU protected, initialized and exited while holding
+ * task_lock(), and can only be modified while holding both cgroup_mutex
+ * and task_lock() while the task is alive.  This macro verifies that the
+ * caller is inside proper critical section and returns @task's css_set.
+ *
+ * The caller can also specify additional allowed conditions via @__c, such
+ * as locks used during the cgroup_subsys::attach() methods.
  */
 #ifdef CONFIG_PROVE_RCU
 extern struct mutex cgroup_mutex;
-#define task_subsys_state_check(task, subsys_id, __c)                  \
-       rcu_dereference_check((task)->cgroups->subsys[(subsys_id)],     \
-                             lockdep_is_held(&(task)->alloc_lock) ||   \
-                             lockdep_is_held(&cgroup_mutex) || (__c))
+#define task_css_set_check(task, __c)                                  \
+       rcu_dereference_check((task)->cgroups,                          \
+               lockdep_is_held(&(task)->alloc_lock) ||                 \
+               lockdep_is_held(&cgroup_mutex) || (__c))
 #else
-#define task_subsys_state_check(task, subsys_id, __c)                  \
-       rcu_dereference((task)->cgroups->subsys[(subsys_id)])
+#define task_css_set_check(task, __c)                                  \
+       rcu_dereference((task)->cgroups)
 #endif
 
+/**
+ * task_subsys_state_check - obtain css for (task, subsys) w/ extra access conds
+ * @task: the target task
+ * @subsys_id: the target subsystem ID
+ * @__c: extra condition expression to be passed to rcu_dereference_check()
+ *
+ * Return the cgroup_subsys_state for the (@task, @subsys_id) pair.  The
+ * synchronization rules are the same as task_css_set_check().
+ */
+#define task_subsys_state_check(task, subsys_id, __c)                  \
+       task_css_set_check((task), (__c))->subsys[(subsys_id)]
+
+/**
+ * task_css_set - obtain a task's css_set
+ * @task: the task to obtain css_set for
+ *
+ * See task_css_set_check().
+ */
+static inline struct css_set *task_css_set(struct task_struct *task)
+{
+       return task_css_set_check(task, false);
+}
+
+/**
+ * task_subsys_state - obtain css for (task, subsys)
+ * @task: the target task
+ * @subsys_id: the target subsystem ID
+ *
+ * See task_subsys_state_check().
+ */
 static inline struct cgroup_subsys_state *
 task_subsys_state(struct task_struct *task, int subsys_id)
 {
@@ -674,12 +712,14 @@ static inline struct cgroup* task_cgroup(struct task_struct *task,
        return task_subsys_state(task, subsys_id)->cgroup;
 }
 
+struct cgroup *cgroup_next_sibling(struct cgroup *pos);
+
 /**
  * cgroup_for_each_child - iterate through children of a cgroup
  * @pos: the cgroup * to use as the loop cursor
- * @cgroup: cgroup whose children to walk
+ * @cgrp: cgroup whose children to walk
  *
- * Walk @cgroup's children.  Must be called under rcu_read_lock().  A child
+ * Walk @cgrp's children.  Must be called under rcu_read_lock().  A child
  * cgroup which hasn't finished ->css_online() or already has finished
  * ->css_offline() may show up during traversal and it's each subsystem's
  * responsibility to verify that each @pos is alive.
@@ -687,9 +727,15 @@ static inline struct cgroup* task_cgroup(struct task_struct *task,
  * If a subsystem synchronizes against the parent in its ->css_online() and
  * before starting iterating, a cgroup which finished ->css_online() is
  * guaranteed to be visible in the future iterations.
+ *
+ * It is allowed to temporarily drop RCU read lock during iteration.  The
+ * caller is responsible for ensuring that @pos remains accessible until
+ * the start of the next iteration by, for example, bumping the css refcnt.
  */
-#define cgroup_for_each_child(pos, cgroup)                             \
-       list_for_each_entry_rcu(pos, &(cgroup)->children, sibling)
+#define cgroup_for_each_child(pos, cgrp)                               \
+       for ((pos) = list_first_or_null_rcu(&(cgrp)->children,          \
+                                           struct cgroup, sibling);    \
+            (pos); (pos) = cgroup_next_sibling((pos)))
 
 struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
                                          struct cgroup *cgroup);
@@ -748,6 +794,10 @@ struct cgroup *cgroup_rightmost_descendant(struct cgroup *pos);
  * Alternatively, a subsystem may choose to use a single global lock to
  * synchronize ->css_online() and ->css_offline() against tree-walking
  * operations.
+ *
+ * It is allowed to temporarily drop RCU read lock during iteration.  The
+ * caller is responsible for ensuring that @pos remains accessible until
+ * the start of the next iteration by, for example, bumping the css refcnt.
  */
 #define cgroup_for_each_descendant_pre(pos, cgroup)                    \
        for (pos = cgroup_next_descendant_pre(NULL, (cgroup)); (pos);   \
@@ -771,7 +821,7 @@ struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
 
 /* A cgroup_iter should be treated as an opaque object */
 struct cgroup_iter {
-       struct list_head *cg_link;
+       struct list_head *cset_link;
        struct list_head *task;
 };
 
@@ -827,7 +877,6 @@ bool css_is_ancestor(struct cgroup_subsys_state *cg,
 
 /* Get id and depth of css */
 unsigned short css_id(struct cgroup_subsys_state *css);
-unsigned short css_depth(struct cgroup_subsys_state *css);
 struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id);
 
 #else /* !CONFIG_CGROUPS */
@@ -838,8 +887,6 @@ static inline void cgroup_fork(struct task_struct *p) {}
 static inline void cgroup_post_fork(struct task_struct *p) {}
 static inline void cgroup_exit(struct task_struct *p, int callbacks) {}
 
-static inline void cgroup_lock(void) {}
-static inline void cgroup_unlock(void) {}
 static inline int cgroupstats_build(struct cgroupstats *stats,
                                        struct dentry *dentry)
 {
index 11860985fecb90d156238d7f719f26540ea006b9..1ec14a73217654308fa20bd18e3ec913d668274f 100644 (file)
@@ -210,6 +210,10 @@ void of_fixed_clk_setup(struct device_node *np);
  * CLK_GATE_SET_TO_DISABLE - by default this clock sets the bit at bit_idx to
  *     enable the clock.  Setting this flag does the opposite: setting the bit
  *     disable the clock and clearing it enables the clock
+ * CLK_GATE_HIWORD_MASK - The gate settings are only in lower 16-bit
+ *   of this register, and mask of gate bits are in higher 16-bit of this
+ *   register.  While setting the gate bits, higher 16-bit should also be
+ *   updated to indicate changing gate bits.
  */
 struct clk_gate {
        struct clk_hw hw;
@@ -220,6 +224,7 @@ struct clk_gate {
 };
 
 #define CLK_GATE_SET_TO_DISABLE                BIT(0)
+#define CLK_GATE_HIWORD_MASK           BIT(1)
 
 extern const struct clk_ops clk_gate_ops;
 struct clk *clk_register_gate(struct device *dev, const char *name,
@@ -257,6 +262,10 @@ struct clk_div_table {
  *     Some hardware implementations gracefully handle this case and allow a
  *     zero divisor by not modifying their input clock
  *     (divide by one / bypass).
+ * CLK_DIVIDER_HIWORD_MASK - The divider settings are only in lower 16-bit
+ *   of this register, and mask of divider bits are in higher 16-bit of this
+ *   register.  While setting the divider bits, higher 16-bit should also be
+ *   updated to indicate changing divider bits.
  */
 struct clk_divider {
        struct clk_hw   hw;
@@ -271,6 +280,7 @@ struct clk_divider {
 #define CLK_DIVIDER_ONE_BASED          BIT(0)
 #define CLK_DIVIDER_POWER_OF_TWO       BIT(1)
 #define CLK_DIVIDER_ALLOW_ZERO         BIT(2)
+#define CLK_DIVIDER_HIWORD_MASK                BIT(3)
 
 extern const struct clk_ops clk_divider_ops;
 struct clk *clk_register_divider(struct device *dev, const char *name,
@@ -299,6 +309,10 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
  * Flags:
  * CLK_MUX_INDEX_ONE - register index starts at 1, not 0
  * CLK_MUX_INDEX_BIT - register index is a single bit (power of two)
+ * CLK_MUX_HIWORD_MASK - The mux settings are only in lower 16-bit of this
+ *   register, and mask of mux bits are in higher 16-bit of this register.
+ *   While setting the mux bits, higher 16-bit should also be updated to
+ *   indicate changing mux bits.
  */
 struct clk_mux {
        struct clk_hw   hw;
@@ -312,6 +326,7 @@ struct clk_mux {
 
 #define CLK_MUX_INDEX_ONE              BIT(0)
 #define CLK_MUX_INDEX_BIT              BIT(1)
+#define CLK_MUX_HIWORD_MASK            BIT(2)
 
 extern const struct clk_ops clk_mux_ops;
 
@@ -423,6 +438,17 @@ struct of_device_id;
 
 typedef void (*of_clk_init_cb_t)(struct device_node *);
 
+struct clk_onecell_data {
+       struct clk **clks;
+       unsigned int clk_num;
+};
+
+#define CLK_OF_DECLARE(name, compat, fn)                       \
+       static const struct of_device_id __clk_of_table_##name  \
+               __used __section(__clk_of_table)                \
+               = { .compatible = compat, .data = fn };
+
+#ifdef CONFIG_OF
 int of_clk_add_provider(struct device_node *np,
                        struct clk *(*clk_src_get)(struct of_phandle_args *args,
                                                   void *data),
@@ -430,19 +456,39 @@ int of_clk_add_provider(struct device_node *np,
 void of_clk_del_provider(struct device_node *np);
 struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
                                  void *data);
-struct clk_onecell_data {
-       struct clk **clks;
-       unsigned int clk_num;
-};
 struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
 const char *of_clk_get_parent_name(struct device_node *np, int index);
 
 void of_clk_init(const struct of_device_id *matches);
 
-#define CLK_OF_DECLARE(name, compat, fn)                       \
-       static const struct of_device_id __clk_of_table_##name  \
-               __used __section(__clk_of_table)                \
-               = { .compatible = compat, .data = fn };
+#else /* !CONFIG_OF */
 
+static inline int of_clk_add_provider(struct device_node *np,
+                       struct clk *(*clk_src_get)(struct of_phandle_args *args,
+                                                  void *data),
+                       void *data)
+{
+       return 0;
+}
+#define of_clk_del_provider(np) \
+       { while (0); }
+static inline struct clk *of_clk_src_simple_get(
+       struct of_phandle_args *clkspec, void *data)
+{
+       return ERR_PTR(-ENOENT);
+}
+static inline struct clk *of_clk_src_onecell_get(
+       struct of_phandle_args *clkspec, void *data)
+{
+       return ERR_PTR(-ENOENT);
+}
+static inline const char *of_clk_get_parent_name(struct device_node *np,
+                                                int index)
+{
+       return NULL;
+}
+#define of_clk_init(matches) \
+       { while (0); }
+#endif /* CONFIG_OF */
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
index 642789baec741cf6574d661587091c75d864b946..23a0ceee831fc4ca2e5a93abfaa951ce3fff0048 100644 (file)
@@ -120,9 +120,13 @@ static inline void tegra_cpu_clock_resume(void)
 }
 #endif
 
+#ifdef CONFIG_ARCH_TEGRA
 void tegra_periph_reset_deassert(struct clk *c);
 void tegra_periph_reset_assert(struct clk *c);
-void tegra_clocks_init(void);
+#else
+static inline void tegra_periph_reset_deassert(struct clk *c) {}
+static inline void tegra_periph_reset_assert(struct clk *c) {}
+#endif
 void tegra_clocks_apply_init_table(void);
 
 #endif /* __LINUX_CLK_TEGRA_H_ */
index 33f0280fd533574fe7739bfe4413bb85791bafcd..3cd574d5b19eb39770f9e22e79690426b05fe21d 100644 (file)
@@ -5,7 +5,7 @@
  * (C) Copyright 2001 Linus Torvalds
  *
  * Atomic wait-for-completion handler data structures.
- * See kernel/sched.c for details.
+ * See kernel/sched/core.c for details.
  */
 
 #include <linux/wait.h>
index 037d36ae63e52d521def4ef34efeaf327479bcec..4d7390bc172731a88ebbc28d7bd9f76ac3713794 100644 (file)
@@ -1,8 +1,8 @@
 /*
- *  linux/include/linux/cpufreq.h
+ * linux/include/linux/cpufreq.h
  *
- *  Copyright (C) 2001 Russell King
- *            (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2001 Russell King
+ *           (C) 2002 - 2003 Dominik Brodowski <linux@brodo.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
@@ -26,7 +26,6 @@
 /* Print length for names. Extra 1 space for accomodating '\n' in prints */
 #define CPUFREQ_NAME_PLEN (CPUFREQ_NAME_LEN + 1)
 
-
 /*********************************************************************
  *                     CPUFREQ NOTIFIER INTERFACE                    *
  *********************************************************************/
@@ -71,6 +70,10 @@ struct cpufreq_governor;
 
 /* /sys/devices/system/cpu/cpufreq: entry point for global variables */
 extern struct kobject *cpufreq_global_kobject;
+int cpufreq_get_global_kobject(void);
+void cpufreq_put_global_kobject(void);
+int cpufreq_sysfs_create_file(const struct attribute *attr);
+void cpufreq_sysfs_remove_file(const struct attribute *attr);
 
 #define CPUFREQ_ETERNAL                        (-1)
 struct cpufreq_cpuinfo {
@@ -107,6 +110,7 @@ struct cpufreq_policy {
        unsigned int            policy; /* see above */
        struct cpufreq_governor *governor; /* see below */
        void                    *governor_data;
+       bool                    governor_enabled; /* governor start/stop flag */
 
        struct work_struct      update; /* if update_policy() needs to be
                                         * called, but you're in IRQ context */
@@ -115,6 +119,7 @@ struct cpufreq_policy {
 
        struct kobject          kobj;
        struct completion       kobj_unregister;
+       bool                    transition_ongoing; /* Tracks transition status */
 };
 
 #define CPUFREQ_ADJUST                 (0)
@@ -148,17 +153,18 @@ struct cpufreq_freqs {
        u8 flags;               /* flags of cpufreq_driver, see below. */
 };
 
-
 /**
- * cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch safe)
+ * cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch
+ * safe)
  * @old:   old value
  * @div:   divisor
  * @mult:  multiplier
  *
  *
- *    new = old * mult / div
+ * new = old * mult / div
  */
-static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mult)
+static inline unsigned long cpufreq_scale(unsigned long old, u_int div,
+               u_int mult)
 {
 #if BITS_PER_LONG == 32
 
@@ -211,14 +217,12 @@ extern int __cpufreq_driver_target(struct cpufreq_policy *policy,
                                   unsigned int target_freq,
                                   unsigned int relation);
 
-
 extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy,
                                   unsigned int cpu);
 
 int cpufreq_register_governor(struct cpufreq_governor *governor);
 void cpufreq_unregister_governor(struct cpufreq_governor *governor);
 
-
 /*********************************************************************
  *                      CPUFREQ DRIVER INTERFACE                     *
  *********************************************************************/
@@ -229,7 +233,7 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor);
 struct freq_attr;
 
 struct cpufreq_driver {
-       struct module           *owner;
+       struct module           *owner;
        char                    name[CPUFREQ_NAME_LEN];
        u8                      flags;
        /*
@@ -277,11 +281,11 @@ struct cpufreq_driver {
 int cpufreq_register_driver(struct cpufreq_driver *driver_data);
 int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
 
-
 void cpufreq_notify_transition(struct cpufreq_policy *policy,
                struct cpufreq_freqs *freqs, unsigned int state);
 
-static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max)
+static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy,
+               unsigned int min, unsigned int max)
 {
        if (policy->min < min)
                policy->min = min;
@@ -337,12 +341,16 @@ const char *cpufreq_get_current_driver(void);
 /*********************************************************************
  *                        CPUFREQ 2.6. INTERFACE                     *
  *********************************************************************/
+u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy);
 int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
 int cpufreq_update_policy(unsigned int cpu);
 bool have_governor_per_policy(void);
+struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy);
 
 #ifdef CONFIG_CPU_FREQ
-/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
+/*
+ * query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it
+ */
 unsigned int cpufreq_get(unsigned int cpu);
 #else
 static inline unsigned int cpufreq_get(unsigned int cpu)
@@ -351,7 +359,9 @@ static inline unsigned int cpufreq_get(unsigned int cpu)
 }
 #endif
 
-/* query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it */
+/*
+ * query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it
+ */
 #ifdef CONFIG_CPU_FREQ
 unsigned int cpufreq_quick_get(unsigned int cpu);
 unsigned int cpufreq_quick_get_max(unsigned int cpu);
@@ -366,16 +376,14 @@ static inline unsigned int cpufreq_quick_get_max(unsigned int cpu)
 }
 #endif
 
-
 /*********************************************************************
  *                       CPUFREQ DEFAULT GOVERNOR                    *
  *********************************************************************/
 
-
 /*
 Performance governor is fallback governor if any other gov failed to
 auto load due latency restrictions
-*/
* Performance governor is fallback governor if any other gov failed to auto
* load due latency restrictions
+ */
 #ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
 extern struct cpufreq_governor cpufreq_gov_performance;
 #endif
@@ -395,7 +403,6 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
 #define CPUFREQ_DEFAULT_GOVERNOR       (&cpufreq_gov_conservative)
 #endif
 
-
 /*********************************************************************
  *                     FREQUENCY TABLE HELPERS                       *
  *********************************************************************/
@@ -404,7 +411,7 @@ extern struct cpufreq_governor cpufreq_gov_conservative;
 #define CPUFREQ_TABLE_END     ~1
 
 struct cpufreq_frequency_table {
-       unsigned int    index;     /* any */
+       unsigned int    driver_data; /* driver specific data, not used by core */
        unsigned int    frequency; /* kHz - doesn't need to be in ascending
                                    * order */
 };
@@ -432,4 +439,7 @@ void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
 void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
 
 void cpufreq_frequency_table_put_attr(unsigned int cpu);
+
+ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
+
 #endif /* _LINUX_CPUFREQ_H */
index 8f0406230a0a4890b4247e60215795c11e0a30d3..0bc4b74668e95f561e6cad07d038f6822f86faa0 100644 (file)
@@ -111,6 +111,9 @@ struct cpuidle_driver {
        struct cpuidle_state    states[CPUIDLE_STATE_MAX];
        int                     state_count;
        int                     safe_state_index;
+
+       /* the driver handles the cpus in cpumask */
+       struct cpumask       *cpumask;
 };
 
 #ifdef CONFIG_CPU_IDLE
@@ -135,9 +138,6 @@ extern void cpuidle_disable_device(struct cpuidle_device *dev);
 extern int cpuidle_play_dead(void);
 
 extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev);
-extern int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu);
-extern void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu);
-
 #else
 static inline void disable_cpuidle(void) { }
 static inline int cpuidle_idle_call(void) { return -ENODEV; }
index 1a6bb81f0fe5a13d93c799cfbcd4062d0e288c28..f42dbe1454793870dba2d4afd456f51bc2c8b2a5 100644 (file)
@@ -146,10 +146,8 @@ enum dentry_d_lock_class
 struct dentry_operations {
        int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_weak_revalidate)(struct dentry *, unsigned int);
-       int (*d_hash)(const struct dentry *, const struct inode *,
-                       struct qstr *);
-       int (*d_compare)(const struct dentry *, const struct inode *,
-                       const struct dentry *, const struct inode *,
+       int (*d_hash)(const struct dentry *, struct qstr *);
+       int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
        void (*d_release)(struct dentry *);
@@ -246,6 +244,8 @@ extern struct dentry * d_make_root(struct inode *);
 /* <clickety>-<click> the ramfs-type tree */
 extern void d_genocide(struct dentry *);
 
+extern void d_tmpfile(struct dentry *, struct inode *);
+
 extern struct dentry *d_find_alias(struct inode *);
 extern void d_prune_aliases(struct inode *);
 
@@ -300,8 +300,7 @@ extern struct dentry *d_lookup(const struct dentry *, const struct qstr *);
 extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
 extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *);
 extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
-                               const struct qstr *name,
-                               unsigned *seq, struct inode *inode);
+                               const struct qstr *name, unsigned *seq);
 
 /**
  * __d_rcu_to_refcount - take a refcount on dentry if sequence check is ok
index 21ca773f77bf7fd2543b111371279c4ef749722d..822c1354f3a69dae20e7f6cacaf340b40ea9d7c4 100644 (file)
@@ -51,7 +51,7 @@ struct task_struct;
 extern void debug_show_all_locks(void);
 extern void debug_show_held_locks(struct task_struct *task);
 extern void debug_check_no_locks_freed(const void *from, unsigned long len);
-extern void debug_check_no_locks_held(struct task_struct *task);
+extern void debug_check_no_locks_held(void);
 #else
 static inline void debug_show_all_locks(void)
 {
@@ -67,7 +67,7 @@ debug_check_no_locks_freed(const void *from, unsigned long len)
 }
 
 static inline void
-debug_check_no_locks_held(struct task_struct *task)
+debug_check_no_locks_held(void)
 {
 }
 #endif
index fe8c4476f7e4b36f4f7b4a778c73b8cfd77c2336..5f1ab92107e63b1889da7e544189f8b73cc740fb 100644 (file)
@@ -181,6 +181,8 @@ extern struct devfreq *devfreq_add_device(struct device *dev,
                                  const char *governor_name,
                                  void *data);
 extern int devfreq_remove_device(struct devfreq *devfreq);
+
+/* Supposed to be called by PM_SLEEP/PM_RUNTIME callbacks */
 extern int devfreq_suspend_device(struct devfreq *devfreq);
 extern int devfreq_resume_device(struct devfreq *devfreq);
 
index 9d4835a8f8b8df4f3d277b7244c2f1b7abeebe5c..bcf8c0d4cd981b49ff9b545d8942d9810fd1f169 100644 (file)
@@ -71,6 +71,10 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
  *             the specific driver's probe to initial the matched device.
  * @remove:    Called when a device removed from this bus.
  * @shutdown:  Called at shut-down time to quiesce the device.
+ *
+ * @online:    Called to put the device back online (after offlining it).
+ * @offline:   Called to put the device offline for hot-removal. May fail.
+ *
  * @suspend:   Called when a device on this bus wants to go to sleep mode.
  * @resume:    Called to bring a device on this bus out of sleep mode.
  * @pm:                Power management operations of this bus, callback the specific
@@ -105,6 +109,9 @@ struct bus_type {
        int (*remove)(struct device *dev);
        void (*shutdown)(struct device *dev);
 
+       int (*online)(struct device *dev);
+       int (*offline)(struct device *dev);
+
        int (*suspend)(struct device *dev, pm_message_t state);
        int (*resume)(struct device *dev);
 
@@ -652,6 +659,9 @@ struct acpi_dev_node {
  *             device (i.e. the bus driver that discovered the device).
  * @iommu_group: IOMMU group the device belongs to.
  *
+ * @offline_disabled: If set, the device is permanently online.
+ * @offline:   Set after successful invocation of bus type's .offline().
+ *
  * At the lowest level, every device in a Linux system is represented by an
  * instance of struct device. The device structure contains the information
  * that the device model core needs to model the system. Most subsystems,
@@ -723,6 +733,9 @@ struct device {
 
        void    (*release)(struct device *dev);
        struct iommu_group      *iommu_group;
+
+       bool                    offline_disabled:1;
+       bool                    offline:1;
 };
 
 static inline struct device *kobj_to_dev(struct kobject *kobj)
@@ -859,6 +872,15 @@ extern const char *device_get_devnode(struct device *dev,
 extern void *dev_get_drvdata(const struct device *dev);
 extern int dev_set_drvdata(struct device *dev, void *data);
 
+static inline bool device_supports_offline(struct device *dev)
+{
+       return dev->bus && dev->bus->offline && dev->bus->online;
+}
+
+extern void lock_device_hotplug(void);
+extern void unlock_device_hotplug(void);
+extern int device_offline(struct device *dev);
+extern int device_online(struct device *dev);
 /*
  * Root device objects for grouping under /sys/devices
  */
index 96d3e4ab11a91a4ea28d0f864d1cfbee6e249127..cb286b1acdb64f06131a4de019d5d5603c864b50 100644 (file)
@@ -66,7 +66,6 @@ enum dma_transaction_type {
        DMA_PQ,
        DMA_XOR_VAL,
        DMA_PQ_VAL,
-       DMA_MEMSET,
        DMA_INTERRUPT,
        DMA_SG,
        DMA_PRIVATE,
@@ -520,7 +519,6 @@ struct dma_tx_state {
  * @device_prep_dma_xor_val: prepares a xor validation operation
  * @device_prep_dma_pq: prepares a pq operation
  * @device_prep_dma_pq_val: prepares a pqzero_sum operation
- * @device_prep_dma_memset: prepares a memset operation
  * @device_prep_dma_interrupt: prepares an end of chain interrupt operation
  * @device_prep_slave_sg: prepares a slave dma operation
  * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio.
@@ -573,9 +571,6 @@ struct dma_device {
                struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src,
                unsigned int src_cnt, const unsigned char *scf, size_t len,
                enum sum_check_flags *pqres, unsigned long flags);
-       struct dma_async_tx_descriptor *(*device_prep_dma_memset)(
-               struct dma_chan *chan, dma_addr_t dest, int value, size_t len,
-               unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
                struct dma_chan *chan, unsigned long flags);
        struct dma_async_tx_descriptor *(*device_prep_dma_sg)(
index 2bc0ad78d058d29255b5e7c62d1a91ab0bffcf75..21ae6b3c0359df02f27bd4dc9a0265d54c282bb3 100644 (file)
@@ -287,20 +287,20 @@ typedef struct {
 
 typedef struct {
        efi_table_hdr_t hdr;
-       unsigned long get_time;
-       unsigned long set_time;
-       unsigned long get_wakeup_time;
-       unsigned long set_wakeup_time;
-       unsigned long set_virtual_address_map;
-       unsigned long convert_pointer;
-       unsigned long get_variable;
-       unsigned long get_next_variable;
-       unsigned long set_variable;
-       unsigned long get_next_high_mono_count;
-       unsigned long reset_system;
-       unsigned long update_capsule;
-       unsigned long query_capsule_caps;
-       unsigned long query_variable_info;
+       void *get_time;
+       void *set_time;
+       void *get_wakeup_time;
+       void *set_wakeup_time;
+       void *set_virtual_address_map;
+       void *convert_pointer;
+       void *get_variable;
+       void *get_next_variable;
+       void *set_variable;
+       void *get_next_high_mono_count;
+       void *reset_system;
+       void *update_capsule;
+       void *query_capsule_caps;
+       void *query_variable_info;
 } efi_runtime_services_t;
 
 typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc);
index f2edce25a76b64f91701cdbd2c680dce19b90706..221fcfb676c47ba79d6310a0c11017f85fc62fb1 100644 (file)
@@ -24,17 +24,17 @@ static inline void * __must_check ERR_PTR(long error)
        return (void *) error;
 }
 
-static inline long __must_check PTR_ERR(const void *ptr)
+static inline long __must_check PTR_ERR(__force const void *ptr)
 {
        return (long) ptr;
 }
 
-static inline long __must_check IS_ERR(const void *ptr)
+static inline long __must_check IS_ERR(__force const void *ptr)
 {
        return IS_ERR_VALUE((unsigned long)ptr);
 }
 
-static inline long __must_check IS_ERR_OR_NULL(const void *ptr)
+static inline long __must_check IS_ERR_OR_NULL(__force const void *ptr)
 {
        return !ptr || IS_ERR_VALUE((unsigned long)ptr);
 }
@@ -46,13 +46,13 @@ static inline long __must_check IS_ERR_OR_NULL(const void *ptr)
  * Explicitly cast an error-valued pointer to another pointer type in such a
  * way as to make it clear that's what's going on.
  */
-static inline void * __must_check ERR_CAST(const void *ptr)
+static inline void * __must_check ERR_CAST(__force const void *ptr)
 {
        /* cast away the const */
        return (void *) ptr;
 }
 
-static inline int __must_check PTR_RET(const void *ptr)
+static inline int __must_check PTR_RET(__force const void *ptr)
 {
        if (IS_ERR(ptr))
                return PTR_ERR(ptr);
index e70df40d84f6fe83c72f732aa44b454148661b6e..7fd81b8c48971676cd52362f09722dfd2dd28153 100644 (file)
@@ -3,6 +3,7 @@
 #ifndef FREEZER_H_INCLUDED
 #define FREEZER_H_INCLUDED
 
+#include <linux/debug_locks.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/atomic.h>
@@ -46,7 +47,11 @@ extern int freeze_kernel_threads(void);
 extern void thaw_processes(void);
 extern void thaw_kernel_threads(void);
 
-static inline bool try_to_freeze(void)
+/*
+ * DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION
+ * If try_to_freeze causes a lockdep warning it means the caller may deadlock
+ */
+static inline bool try_to_freeze_unsafe(void)
 {
        might_sleep();
        if (likely(!freezing(current)))
@@ -54,6 +59,13 @@ static inline bool try_to_freeze(void)
        return __refrigerator(false);
 }
 
+static inline bool try_to_freeze(void)
+{
+       if (!(current->flags & PF_NOFREEZE))
+               debug_check_no_locks_held();
+       return try_to_freeze_unsafe();
+}
+
 extern bool freeze_task(struct task_struct *p);
 extern bool set_freezable(void);
 
@@ -115,6 +127,14 @@ static inline void freezer_count(void)
        try_to_freeze();
 }
 
+/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
+static inline void freezer_count_unsafe(void)
+{
+       current->flags &= ~PF_FREEZER_SKIP;
+       smp_mb();
+       try_to_freeze_unsafe();
+}
+
 /**
  * freezer_should_skip - whether to skip a task when determining frozen
  *                      state is reached
@@ -139,28 +159,86 @@ static inline bool freezer_should_skip(struct task_struct *p)
 }
 
 /*
- * These macros are intended to be used whenever you want allow a sleeping
+ * These functions are intended to be used whenever you want allow a sleeping
  * task to be frozen. Note that neither return any clear indication of
  * whether a freeze event happened while in this function.
  */
 
 /* Like schedule(), but should not block the freezer. */
-#define freezable_schedule()                                           \
-({                                                                     \
-       freezer_do_not_count();                                         \
-       schedule();                                                     \
-       freezer_count();                                                \
-})
+static inline void freezable_schedule(void)
+{
+       freezer_do_not_count();
+       schedule();
+       freezer_count();
+}
+
+/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
+static inline void freezable_schedule_unsafe(void)
+{
+       freezer_do_not_count();
+       schedule();
+       freezer_count_unsafe();
+}
+
+/*
+ * Like freezable_schedule_timeout(), but should not block the freezer.  Do not
+ * call this with locks held.
+ */
+static inline long freezable_schedule_timeout(long timeout)
+{
+       long __retval;
+       freezer_do_not_count();
+       __retval = schedule_timeout(timeout);
+       freezer_count();
+       return __retval;
+}
+
+/*
+ * Like schedule_timeout_interruptible(), but should not block the freezer.  Do not
+ * call this with locks held.
+ */
+static inline long freezable_schedule_timeout_interruptible(long timeout)
+{
+       long __retval;
+       freezer_do_not_count();
+       __retval = schedule_timeout_interruptible(timeout);
+       freezer_count();
+       return __retval;
+}
 
 /* Like schedule_timeout_killable(), but should not block the freezer. */
-#define freezable_schedule_timeout_killable(timeout)                   \
-({                                                                     \
-       long __retval;                                                  \
-       freezer_do_not_count();                                         \
-       __retval = schedule_timeout_killable(timeout);                  \
-       freezer_count();                                                \
-       __retval;                                                       \
-})
+static inline long freezable_schedule_timeout_killable(long timeout)
+{
+       long __retval;
+       freezer_do_not_count();
+       __retval = schedule_timeout_killable(timeout);
+       freezer_count();
+       return __retval;
+}
+
+/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
+static inline long freezable_schedule_timeout_killable_unsafe(long timeout)
+{
+       long __retval;
+       freezer_do_not_count();
+       __retval = schedule_timeout_killable(timeout);
+       freezer_count_unsafe();
+       return __retval;
+}
+
+/*
+ * Like schedule_hrtimeout_range(), but should not block the freezer.  Do not
+ * call this with locks held.
+ */
+static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
+               unsigned long delta, const enum hrtimer_mode mode)
+{
+       int __retval;
+       freezer_do_not_count();
+       __retval = schedule_hrtimeout_range(expires, delta, mode);
+       freezer_count();
+       return __retval;
+}
 
 /*
  * Freezer-friendly wrappers around wait_event_interruptible(),
@@ -177,33 +255,45 @@ static inline bool freezer_should_skip(struct task_struct *p)
        __retval;                                                       \
 })
 
+/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
+#define wait_event_freezekillable_unsafe(wq, condition)                        \
+({                                                                     \
+       int __retval;                                                   \
+       freezer_do_not_count();                                         \
+       __retval = wait_event_killable(wq, (condition));                \
+       freezer_count_unsafe();                                         \
+       __retval;                                                       \
+})
+
 #define wait_event_freezable(wq, condition)                            \
 ({                                                                     \
        int __retval;                                                   \
-       for (;;) {                                                      \
-               __retval = wait_event_interruptible(wq,                 \
-                               (condition) || freezing(current));      \
-               if (__retval || (condition))                            \
-                       break;                                          \
-               try_to_freeze();                                        \
-       }                                                               \
+       freezer_do_not_count();                                         \
+       __retval = wait_event_interruptible(wq, (condition));           \
+       freezer_count();                                                \
        __retval;                                                       \
 })
 
 #define wait_event_freezable_timeout(wq, condition, timeout)           \
 ({                                                                     \
        long __retval = timeout;                                        \
-       for (;;) {                                                      \
-               __retval = wait_event_interruptible_timeout(wq,         \
-                               (condition) || freezing(current),       \
-                               __retval);                              \
-               if (__retval <= 0 || (condition))                       \
-                       break;                                          \
-               try_to_freeze();                                        \
-       }                                                               \
+       freezer_do_not_count();                                         \
+       __retval = wait_event_interruptible_timeout(wq, (condition),    \
+                               __retval);                              \
+       freezer_count();                                                \
        __retval;                                                       \
 })
 
+#define wait_event_freezable_exclusive(wq, condition)                  \
+({                                                                     \
+       int __retval;                                                   \
+       freezer_do_not_count();                                         \
+       __retval = wait_event_interruptible_exclusive(wq, condition);   \
+       freezer_count();                                                \
+       __retval;                                                       \
+})
+
+
 #else /* !CONFIG_FREEZER */
 static inline bool frozen(struct task_struct *p) { return false; }
 static inline bool freezing(struct task_struct *p) { return false; }
@@ -225,18 +315,37 @@ static inline void set_freezable(void) {}
 
 #define freezable_schedule()  schedule()
 
+#define freezable_schedule_unsafe()  schedule()
+
+#define freezable_schedule_timeout(timeout)  schedule_timeout(timeout)
+
+#define freezable_schedule_timeout_interruptible(timeout)              \
+       schedule_timeout_interruptible(timeout)
+
 #define freezable_schedule_timeout_killable(timeout)                   \
        schedule_timeout_killable(timeout)
 
+#define freezable_schedule_timeout_killable_unsafe(timeout)            \
+       schedule_timeout_killable(timeout)
+
+#define freezable_schedule_hrtimeout_range(expires, delta, mode)       \
+       schedule_hrtimeout_range(expires, delta, mode)
+
 #define wait_event_freezable(wq, condition)                            \
                wait_event_interruptible(wq, condition)
 
 #define wait_event_freezable_timeout(wq, condition, timeout)           \
                wait_event_interruptible_timeout(wq, condition, timeout)
 
+#define wait_event_freezable_exclusive(wq, condition)                  \
+               wait_event_interruptible_exclusive(wq, condition)
+
 #define wait_event_freezekillable(wq, condition)               \
                wait_event_killable(wq, condition)
 
+#define wait_event_freezekillable_unsafe(wq, condition)                        \
+               wait_event_killable(wq, condition)
+
 #endif /* !CONFIG_FREEZER */
 
 #endif /* FREEZER_H_INCLUDED */
index f8a5240541b77e17df8bf17fa4c10399cdb7fbd2..99be011e00dea1eeb6f2b48f7cc81035dd0acf82 100644 (file)
@@ -380,6 +380,7 @@ struct address_space_operations {
        int (*launder_page) (struct page *);
        int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
                                        unsigned long);
+       void (*is_dirty_writeback) (struct page *, bool *, bool *);
        int (*error_remove_page)(struct address_space *, struct page *);
 
        /* swapfile support */
@@ -908,6 +909,7 @@ struct file_lock_operations {
 
 struct lock_manager_operations {
        int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
+       unsigned long (*lm_owner_key)(struct file_lock *);
        void (*lm_notify)(struct file_lock *);  /* unblock callback */
        int (*lm_grant)(struct file_lock *, struct file_lock *, int);
        void (*lm_break)(struct file_lock *);
@@ -926,9 +928,27 @@ int locks_in_grace(struct net *);
 /* that will die - we need it for nfs_lock_info */
 #include <linux/nfs_fs_i.h>
 
+/*
+ * struct file_lock represents a generic "file lock". It's used to represent
+ * POSIX byte range locks, BSD (flock) locks, and leases. It's important to
+ * note that the same struct is used to represent both a request for a lock and
+ * the lock itself, but the same object is never used for both.
+ *
+ * FIXME: should we create a separate "struct lock_request" to help distinguish
+ * these two uses?
+ *
+ * The i_flock list is ordered by:
+ *
+ * 1) lock type -- FL_LEASEs first, then FL_FLOCK, and finally FL_POSIX
+ * 2) lock owner
+ * 3) lock range start
+ * 4) lock range end
+ *
+ * Obviously, the last two criteria only matter for POSIX locks.
+ */
 struct file_lock {
        struct file_lock *fl_next;      /* singly linked list for this inode  */
-       struct list_head fl_link;       /* doubly linked list of all locks */
+       struct hlist_node fl_link;      /* node in global lists */
        struct list_head fl_block;      /* circular list of blocked processes */
        fl_owner_t fl_owner;
        unsigned int fl_flags;
@@ -994,7 +1014,7 @@ extern void locks_release_private(struct file_lock *);
 extern void posix_test_lock(struct file *, struct file_lock *);
 extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
 extern int posix_lock_file_wait(struct file *, struct file_lock *);
-extern int posix_unblock_lock(struct file *, struct file_lock *);
+extern int posix_unblock_lock(struct file_lock *);
 extern int vfs_test_lock(struct file *, struct file_lock *);
 extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
 extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
@@ -1006,9 +1026,6 @@ extern int vfs_setlease(struct file *, long, struct file_lock **);
 extern int lease_modify(struct file_lock **, int);
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
 extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
-extern void locks_delete_block(struct file_lock *waiter);
-extern void lock_flocks(void);
-extern void unlock_flocks(void);
 #else /* !CONFIG_FILE_LOCKING */
 static inline int fcntl_getlk(struct file *file, struct flock __user *user)
 {
@@ -1084,8 +1101,7 @@ static inline int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
        return -ENOLCK;
 }
 
-static inline int posix_unblock_lock(struct file *filp,
-                                    struct file_lock *waiter)
+static inline int posix_unblock_lock(struct file_lock *waiter)
 {
        return -ENOENT;
 }
@@ -1150,19 +1166,6 @@ static inline int lock_may_write(struct inode *inode, loff_t start,
 {
        return 1;
 }
-
-static inline void locks_delete_block(struct file_lock *waiter)
-{
-}
-
-static inline void lock_flocks(void)
-{
-}
-
-static inline void unlock_flocks(void)
-{
-}
-
 #endif /* !CONFIG_FILE_LOCKING */
 
 
@@ -1580,6 +1583,7 @@ struct inode_operations {
        int (*atomic_open)(struct inode *, struct dentry *,
                           struct file *, unsigned open_flag,
                           umode_t create_mode, int *opened);
+       int (*tmpfile) (struct inode *, struct dentry *, umode_t);
 } ____cacheline_aligned;
 
 ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
@@ -1743,6 +1747,7 @@ struct super_operations {
 #define I_REFERENCED           (1 << 8)
 #define __I_DIO_WAKEUP         9
 #define I_DIO_WAKEUP           (1 << I_DIO_WAKEUP)
+#define I_LINKABLE             (1 << 10)
 
 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
 
@@ -1896,7 +1901,6 @@ extern int current_umask(void);
 extern struct kobject *fs_kobj;
 
 #define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
-extern int rw_verify_area(int, struct file *, loff_t *, size_t);
 
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
@@ -2309,7 +2313,6 @@ extern struct file * open_exec(const char *);
 /* fs/dcache.c -- generic fs support functions */
 extern int is_subdir(struct dentry *, struct dentry *);
 extern int path_is_under(struct path *, struct path *);
-extern ino_t find_inode_number(struct dentry *, struct qstr *);
 
 #include <linux/err.h>
 
@@ -2424,9 +2427,12 @@ extern void
 file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
 extern loff_t noop_llseek(struct file *file, loff_t offset, int whence);
 extern loff_t no_llseek(struct file *file, loff_t offset, int whence);
+extern loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize);
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int whence);
 extern loff_t generic_file_llseek_size(struct file *file, loff_t offset,
                int whence, loff_t maxsize, loff_t eof);
+extern loff_t fixed_size_llseek(struct file *file, loff_t offset,
+               int whence, loff_t size);
 extern int generic_file_open(struct inode * inode, struct file * filp);
 extern int nonseekable_open(struct inode * inode, struct file * filp);
 
index a78680a92dba3a8a2ad88fca6ef5416e2504312b..1c804b057fb1095dd00038cdd55580d08e773407 100644 (file)
@@ -38,7 +38,7 @@ static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u3
 static inline int fsnotify_perm(struct file *file, int mask)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = path->dentry->d_inode;
+       struct inode *inode = file_inode(file);
        __u32 fsnotify_mask = 0;
        int ret;
 
@@ -192,7 +192,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
 static inline void fsnotify_access(struct file *file)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = path->dentry->d_inode;
+       struct inode *inode = file_inode(file);
        __u32 mask = FS_ACCESS;
 
        if (S_ISDIR(inode->i_mode))
@@ -210,7 +210,7 @@ static inline void fsnotify_access(struct file *file)
 static inline void fsnotify_modify(struct file *file)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = path->dentry->d_inode;
+       struct inode *inode = file_inode(file);
        __u32 mask = FS_MODIFY;
 
        if (S_ISDIR(inode->i_mode))
@@ -228,7 +228,7 @@ static inline void fsnotify_modify(struct file *file)
 static inline void fsnotify_open(struct file *file)
 {
        struct path *path = &file->f_path;
-       struct inode *inode = path->dentry->d_inode;
+       struct inode *inode = file_inode(file);
        __u32 mask = FS_OPEN;
 
        if (S_ISDIR(inode->i_mode))
index c1d6555d2567468f86a6c1b6d745d927f1a25815..05bcc0903766f50718be8fd4c04c41a2dee549d3 100644 (file)
@@ -128,7 +128,7 @@ extern void synchronize_irq(unsigned int irq);
 # define synchronize_irq(irq)  barrier()
 #endif
 
-#if defined(CONFIG_TINY_RCU) || defined(CONFIG_TINY_PREEMPT_RCU)
+#if defined(CONFIG_TINY_RCU)
 
 static inline void rcu_nmi_enter(void)
 {
index 528454c2caa91b17cbb5761de006418909de2046..26ee56c80dc7c525d15e664bcc1a3f2dd3fdd221 100644 (file)
@@ -123,7 +123,7 @@ extern void __split_huge_page_pmd(struct vm_area_struct *vma,
        } while (0)
 extern void split_huge_page_pmd_mm(struct mm_struct *mm, unsigned long address,
                pmd_t *pmd);
-#if HPAGE_PMD_ORDER > MAX_ORDER
+#if HPAGE_PMD_ORDER >= MAX_ORDER
 #error "hugepages can't be allocated by the buddy allocator"
 #endif
 extern int hugepage_madvise(struct vm_area_struct *vma,
index 6b4890fa57e7191574da1efe41eec956077d72ae..c2b1801a160bccafd6d52a3cd77ca1effc2dfd89 100644 (file)
@@ -55,7 +55,6 @@ void __unmap_hugepage_range_final(struct mmu_gather *tlb,
 void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
                                unsigned long start, unsigned long end,
                                struct page *ref_page);
-int hugetlb_prefault(struct address_space *, struct vm_area_struct *);
 void hugetlb_report_meminfo(struct seq_file *);
 int hugetlb_report_node_meminfo(int, char *);
 void hugetlb_show_meminfo(void);
@@ -69,6 +68,10 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);
 int dequeue_hwpoisoned_huge_page(struct page *page);
 void copy_huge_page(struct page *dst, struct page *src);
 
+#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
+pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud);
+#endif
+
 extern unsigned long hugepages_treat_as_movable;
 extern const unsigned long hugetlb_zero, hugetlb_infinity;
 extern int sysctl_hugetlb_shm_group;
@@ -110,7 +113,6 @@ static inline unsigned long hugetlb_total_pages(void)
 #define follow_hugetlb_page(m,v,p,vs,a,b,i,w)  ({ BUG(); 0; })
 #define follow_huge_addr(mm, addr, write)      ERR_PTR(-EINVAL)
 #define copy_hugetlb_page_range(src, dst, vma) ({ BUG(); 0; })
-#define hugetlb_prefault(mapping, vma)         ({ BUG(); 0; })
 static inline void hugetlb_report_meminfo(struct seq_file *m)
 {
 }
@@ -358,6 +360,17 @@ static inline int hstate_index(struct hstate *h)
        return h - hstates;
 }
 
+pgoff_t __basepage_index(struct page *page);
+
+/* Return page->index in PAGE_SIZE units */
+static inline pgoff_t basepage_index(struct page *page)
+{
+       if (!PageCompound(page))
+               return page->index;
+
+       return __basepage_index(page);
+}
+
 #else  /* CONFIG_HUGETLB_PAGE */
 struct hstate {};
 #define alloc_huge_page_node(h, nid) NULL
@@ -378,6 +391,11 @@ static inline unsigned int pages_per_huge_page(struct hstate *h)
 }
 #define hstate_index_to_shift(index) 0
 #define hstate_index(h) 0
+
+static inline pgoff_t basepage_index(struct page *page)
+{
+       return page->index;
+}
 #endif /* CONFIG_HUGETLB_PAGE */
 
 #endif /* _LINUX_HUGETLB_H */
index bc4e06611958ce476c749b79b63b747a97390ea1..f04d3ba335cb3ec778bd9820dc13dad29c2a8e72 100644 (file)
@@ -119,6 +119,7 @@ struct irq_domain;
 
 /**
  * struct irq_data - per irq and irq chip data passed down to chip functions
+ * @mask:              precomputed bitmask for accessing the chip registers
  * @irq:               interrupt number
  * @hwirq:             hardware interrupt number, local to the interrupt domain
  * @node:              node index useful for balancing
@@ -138,6 +139,7 @@ struct irq_domain;
  * irq_data.
  */
 struct irq_data {
+       u32                     mask;
        unsigned int            irq;
        unsigned long           hwirq;
        unsigned int            node;
@@ -294,6 +296,7 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
  * @irq_suspend:       function called from core code on suspend once per chip
  * @irq_resume:                function called from core code on resume once per chip
  * @irq_pm_shutdown:   function called from core code on shutdown once per chip
+ * @irq_calc_mask:     Optional function to set irq_data.mask for special cases
  * @irq_print_chip:    optional to print special chip info in show_interrupts
  * @flags:             chip specific flags
  */
@@ -325,6 +328,8 @@ struct irq_chip {
        void            (*irq_resume)(struct irq_data *data);
        void            (*irq_pm_shutdown)(struct irq_data *data);
 
+       void            (*irq_calc_mask)(struct irq_data *data);
+
        void            (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
 
        unsigned long   flags;
@@ -579,6 +584,12 @@ static inline struct msi_desc *irq_data_get_msi(struct irq_data *d)
        return d->msi_desc;
 }
 
+static inline u32 irq_get_trigger_type(unsigned int irq)
+{
+       struct irq_data *d = irq_get_irq_data(irq);
+       return d ? irqd_get_trigger_type(d) : 0;
+}
+
 int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
                struct module *owner);
 
@@ -644,6 +655,8 @@ struct irq_chip_regs {
  * @regs:              Register offsets for this chip
  * @handler:           Flow handler associated with this chip
  * @type:              Chip can handle these flow types
+ * @mask_cache_priv:   Cached mask register private to the chip type
+ * @mask_cache:                Pointer to cached mask register
  *
  * A irq_generic_chip can have several instances of irq_chip_type when
  * it requires different functions and register offsets for different
@@ -654,6 +667,8 @@ struct irq_chip_type {
        struct irq_chip_regs    regs;
        irq_flow_handler_t      handler;
        u32                     type;
+       u32                     mask_cache_priv;
+       u32                     *mask_cache;
 };
 
 /**
@@ -662,13 +677,16 @@ struct irq_chip_type {
  * @reg_base:          Register base address (virtual)
  * @irq_base:          Interrupt base nr for this chip
  * @irq_cnt:           Number of interrupts handled by this chip
- * @mask_cache:                Cached mask register
+ * @mask_cache:                Cached mask register shared between all chip types
  * @type_cache:                Cached type register
  * @polarity_cache:    Cached polarity register
  * @wake_enabled:      Interrupt can wakeup from suspend
  * @wake_active:       Interrupt is marked as an wakeup from suspend source
  * @num_ct:            Number of available irq_chip_type instances (usually 1)
  * @private:           Private data for non generic chip callbacks
+ * @installed:         bitfield to denote installed interrupts
+ * @unused:            bitfield to denote unused interrupts
+ * @domain:            irq domain pointer
  * @list:              List head for keeping track of instances
  * @chip_types:                Array of interrupt irq_chip_types
  *
@@ -690,6 +708,9 @@ struct irq_chip_generic {
        u32                     wake_active;
        unsigned int            num_ct;
        void                    *private;
+       unsigned long           installed;
+       unsigned long           unused;
+       struct irq_domain       *domain;
        struct list_head        list;
        struct irq_chip_type    chip_types[0];
 };
@@ -700,10 +721,32 @@ struct irq_chip_generic {
  * @IRQ_GC_INIT_NESTED_LOCK:   Set the lock class of the irqs to nested for
  *                             irq chips which need to call irq_set_wake() on
  *                             the parent irq. Usually GPIO implementations
+ * @IRQ_GC_MASK_CACHE_PER_TYPE:        Mask cache is chip type private
+ * @IRQ_GC_NO_MASK:            Do not calculate irq_data->mask
  */
 enum irq_gc_flags {
        IRQ_GC_INIT_MASK_CACHE          = 1 << 0,
        IRQ_GC_INIT_NESTED_LOCK         = 1 << 1,
+       IRQ_GC_MASK_CACHE_PER_TYPE      = 1 << 2,
+       IRQ_GC_NO_MASK                  = 1 << 3,
+};
+
+/*
+ * struct irq_domain_chip_generic - Generic irq chip data structure for irq domains
+ * @irqs_per_chip:     Number of interrupts per chip
+ * @num_chips:         Number of chips
+ * @irq_flags_to_set:  IRQ* flags to set on irq setup
+ * @irq_flags_to_clear:        IRQ* flags to clear on irq setup
+ * @gc_flags:          Generic chip specific setup flags
+ * @gc:                        Array of pointers to generic interrupt chips
+ */
+struct irq_domain_chip_generic {
+       unsigned int            irqs_per_chip;
+       unsigned int            num_chips;
+       unsigned int            irq_flags_to_clear;
+       unsigned int            irq_flags_to_set;
+       enum irq_gc_flags       gc_flags;
+       struct irq_chip_generic *gc[0];
 };
 
 /* Generic chip callback functions */
@@ -729,6 +772,14 @@ int irq_setup_alt_chip(struct irq_data *d, unsigned int type);
 void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
                             unsigned int clr, unsigned int set);
 
+struct irq_chip_generic *irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq);
+int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
+                                  int num_ct, const char *name,
+                                  irq_flow_handler_t handler,
+                                  unsigned int clr, unsigned int set,
+                                  enum irq_gc_flags flags);
+
+
 static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d)
 {
        return container_of(d->chip, struct irq_chip_type, chip);
index 0d5b17bf5e5131dfd03dc176a8c7fa4f9cbec9b1..ba2c708adcff7da4b277ae9038c2779229831a8e 100644 (file)
@@ -66,6 +66,10 @@ struct irq_domain_ops {
                     unsigned long *out_hwirq, unsigned int *out_type);
 };
 
+extern struct irq_domain_ops irq_generic_chip_ops;
+
+struct irq_domain_chip_generic;
+
 /**
  * struct irq_domain - Hardware interrupt number translation object
  * @link: Element in global irq_domain list.
@@ -109,8 +113,16 @@ struct irq_domain {
 
        /* Optional device node pointer */
        struct device_node *of_node;
+       /* Optional pointer to generic interrupt chips */
+       struct irq_domain_chip_generic *gc;
 };
 
+#define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs.
+                                * ie. legacy 8259, gets irqs 1..15 */
+#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
+#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
+#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
+
 #ifdef CONFIG_IRQ_DOMAIN
 struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
                                         unsigned int size,
index 3afb969441d15582969917b429e3e1a2b58fbb70..7e6b97e77fb9e7b8bc1ae999f0ef0c167e1a10bb 100644 (file)
@@ -193,13 +193,10 @@ extern int _cond_resched(void);
                (__x < 0) ? -__x : __x;         \
        })
 
-#ifdef CONFIG_PROVE_LOCKING
+#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP)
 void might_fault(void);
 #else
-static inline void might_fault(void)
-{
-       might_sleep();
-}
+static inline void might_fault(void) { }
 #endif
 
 extern struct atomic_notifier_head panic_notifier_list;
index 8db53cfaccdb64fdbd18d29935e698d101bf5bf1..a63d83ebd151918b84fa6bb6ddc594e4dcd0c907 100644 (file)
@@ -125,6 +125,7 @@ static inline bool is_error_page(struct page *page)
 #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_USERSPACE_IRQ_SOURCE_ID            0
 #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID       1
@@ -145,7 +146,8 @@ struct kvm_io_range {
 #define NR_IOBUS_DEVS 1000
 
 struct kvm_io_bus {
-       int                   dev_count;
+       int dev_count;
+       int ioeventfd_count;
        struct kvm_io_range range[];
 };
 
index e00c3b0ebc6bd7303afdb0ffa448a31c0d000911..504f6246f38f38feb59d3eb0faee7a4e663379b7 100644 (file)
@@ -112,7 +112,12 @@ static inline void lcd_set_power(struct lcd_device *ld, int power)
 
 extern struct lcd_device *lcd_device_register(const char *name,
        struct device *parent, void *devdata, struct lcd_ops *ops);
+extern struct lcd_device *devm_lcd_device_register(struct device *dev,
+       const char *name, struct device *parent,
+       void *devdata, struct lcd_ops *ops);
 extern void lcd_device_unregister(struct lcd_device *ld);
+extern void devm_lcd_device_unregister(struct device *dev,
+       struct lcd_device *ld);
 
 #define to_lcd_device(obj) container_of(obj, struct lcd_device, dev)
 
index eae7a053dc5141d062a80bb4055449520bac61cf..4ea55bb45debf3a1e8ad6d8120e81b763069adc1 100644 (file)
@@ -399,6 +399,7 @@ enum {
        ATA_HORKAGE_BROKEN_FPDMA_AA     = (1 << 15),    /* skip AA */
        ATA_HORKAGE_DUMP_ID     = (1 << 16),    /* dump IDENTIFY data */
        ATA_HORKAGE_MAX_SEC_LBA48 = (1 << 17),  /* Set max sects to 65535 */
+       ATA_HORKAGE_ATAPI_DMADIR = (1 << 18),   /* device requires dmadir */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
@@ -746,6 +747,7 @@ struct ata_port {
        /* Flags that change dynamically, protected by ap->lock */
        unsigned int            pflags; /* ATA_PFLAG_xxx */
        unsigned int            print_id; /* user visible unique port ID */
+       unsigned int            local_port_no; /* host local port num */
        unsigned int            port_no; /* 0 based port no. inside the host */
 
 #ifdef CONFIG_ATA_SFF
@@ -908,6 +910,9 @@ struct ata_port_operations {
        ssize_t (*sw_activity_show)(struct ata_device *dev, char *buf);
        ssize_t (*sw_activity_store)(struct ata_device *dev,
                                     enum sw_activity val);
+       ssize_t (*transmit_led_message)(struct ata_port *ap, u32 state,
+                                       ssize_t size);
+
        /*
         * Obsolete
         */
index d6183f06d8c182951fac67c17a2c05d2ce9f20fa..7b4d9d79570b6a4d0914f08bab3b8b208d665bb4 100644 (file)
@@ -77,7 +77,8 @@ extern void mem_cgroup_uncharge_cache_page(struct page *page);
 
 bool __mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
                                  struct mem_cgroup *memcg);
-int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg);
+bool task_in_mem_cgroup(struct task_struct *task,
+                       const struct mem_cgroup *memcg);
 
 extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
 extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
@@ -273,10 +274,10 @@ static inline bool mm_match_cgroup(struct mm_struct *mm,
        return true;
 }
 
-static inline int task_in_mem_cgroup(struct task_struct *task,
-                                    const struct mem_cgroup *memcg)
+static inline bool task_in_mem_cgroup(struct task_struct *task,
+                                     const struct mem_cgroup *memcg)
 {
-       return 1;
+       return true;
 }
 
 static inline struct cgroup_subsys_state
index 3e622c6109255650896ce67e141403ec1d36479e..dd38e62b84d2824ecf1e412cdd7fbb908dac675f 100644 (file)
@@ -234,6 +234,8 @@ static inline void unlock_memory_hotplug(void) {}
 
 extern int is_mem_section_removable(unsigned long pfn, unsigned long nr_pages);
 extern void try_offline_node(int nid);
+extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
+extern void remove_memory(int nid, u64 start, u64 size);
 
 #else
 static inline int is_mem_section_removable(unsigned long pfn,
@@ -243,15 +245,23 @@ static inline int is_mem_section_removable(unsigned long pfn,
 }
 
 static inline void try_offline_node(int nid) {}
+
+static inline int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
+{
+       return -EINVAL;
+}
+
+static inline void remove_memory(int nid, u64 start, u64 size) {}
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
+extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
+               void *arg, int (*func)(struct memory_block *, void *));
 extern int mem_online_node(int nid);
 extern int add_memory(int nid, u64 start, u64 size);
 extern int arch_add_memory(int nid, u64 start, u64 size);
 extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
-extern int offline_memory_block(struct memory_block *mem);
 extern bool is_memblock_offlined(struct memory_block *mem);
-extern int remove_memory(int nid, u64 start, u64 size);
+extern void remove_memory(int nid, u64 start, u64 size);
 extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
                                                                int nr_pages);
 extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms);
index 990bc93f46e103f47d42f48108fcf523f19160ff..adba89d9c6601b54eff0d5faffc3e521e71fbb41 100644 (file)
@@ -278,8 +278,8 @@ struct ab8500_sysctrl_platform_data {
 
 #define AB9540_SYSCLK12CONFCTRL_PLL26TO38ENA BIT(0)
 #define AB9540_SYSCLK12CONFCTRL_SYSCLK12USBMUXSEL BIT(1)
-#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_MASK 0x0C
-#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_SHIFT 2
+#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL0 BIT(2)
+#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL1 BIT(3)
 #define AB9540_SYSCLK12CONFCTRL_SYSCLK12BUFMUX BIT(4)
 #define AB9540_SYSCLK12CONFCTRL_SYSCLK12PLLMUX BIT(5)
 #define AB9540_SYSCLK12CONFCTRL_SYSCLK2MUXVALID BIT(6)
index cc281368dc555f17d486b84fe1a3087f328bb880..f797bb9b8b56838458fe108c343bd4c5d6bde7f5 100644 (file)
@@ -95,6 +95,8 @@ struct arizona {
 
        struct arizona_pdata pdata;
 
+       unsigned int external_dcvdd:1;
+
        int irq;
        struct irq_domain *virq;
        struct regmap_irq_chip_data *aod_irq_chip;
index 80dead1f710014564bf07319945025e40faca17e..12a5c135c746d9c69be4199a022f4d3519920f08 100644 (file)
@@ -77,7 +77,7 @@ struct arizona_micbias {
        int mV;                    /** Regulated voltage */
        unsigned int ext_cap:1;    /** External capacitor fitted */
        unsigned int discharge:1;  /** Actively discharge */
-       unsigned int fast_start:1; /** Enable aggressive startup ramp rate */
+       unsigned int soft_start:1; /** Disable aggressive startup ramp rate */
        unsigned int bypass:1;     /** Use bypass mode */
 };
 
index 715b6ba3d52a2c949a359f0a440a5defa7bc3b59..4706d3d46e56f1e4bd630bc0dcbb50e8111d4af8 100644 (file)
 #define ARIZONA_DAC_DIGITAL_VOLUME_6R            0x43D
 #define ARIZONA_DAC_VOLUME_LIMIT_6R              0x43E
 #define ARIZONA_NOISE_GATE_SELECT_6R             0x43F
+#define ARIZONA_DRE_ENABLE                       0x440
+#define ARIZONA_DRE_CONTROL_2                    0x442
+#define ARIZONA_DRE_CONTROL_3                    0x443
 #define ARIZONA_DAC_AEC_CONTROL_1                0x450
 #define ARIZONA_NOISE_GATE_CONTROL               0x458
 #define ARIZONA_PDM_SPK1_CTRL_1                  0x490
 #define ARIZONA_DSP2_CLOCKING_1                  0x1201
 #define ARIZONA_DSP2_STATUS_1                    0x1204
 #define ARIZONA_DSP2_STATUS_2                    0x1205
+#define ARIZONA_DSP2_STATUS_3                    0x1206
 #define ARIZONA_DSP2_SCRATCH_0                   0x1240
 #define ARIZONA_DSP2_SCRATCH_1                   0x1241
 #define ARIZONA_DSP2_SCRATCH_2                   0x1242
 #define ARIZONA_DSP3_CLOCKING_1                  0x1301
 #define ARIZONA_DSP3_STATUS_1                    0x1304
 #define ARIZONA_DSP3_STATUS_2                    0x1305
+#define ARIZONA_DSP3_STATUS_3                    0x1306
 #define ARIZONA_DSP3_SCRATCH_0                   0x1340
 #define ARIZONA_DSP3_SCRATCH_1                   0x1341
 #define ARIZONA_DSP3_SCRATCH_2                   0x1342
 #define ARIZONA_DSP4_CLOCKING_1                  0x1401
 #define ARIZONA_DSP4_STATUS_1                    0x1404
 #define ARIZONA_DSP4_STATUS_2                    0x1405
+#define ARIZONA_DSP4_STATUS_3                    0x1406
 #define ARIZONA_DSP4_SCRATCH_0                   0x1440
 #define ARIZONA_DSP4_SCRATCH_1                   0x1441
 #define ARIZONA_DSP4_SCRATCH_2                   0x1442
 #define ARIZONA_OUT6R_NGATE_SRC_SHIFT                 0  /* OUT6R_NGATE_SRC - [11:0] */
 #define ARIZONA_OUT6R_NGATE_SRC_WIDTH                12  /* OUT6R_NGATE_SRC - [11:0] */
 
+/*
+ * R1088 (0x440) - DRE Enable
+ */
+#define ARIZONA_DRE3L_ENA                        0x0010  /* DRE3L_ENA */
+#define ARIZONA_DRE3L_ENA_MASK                   0x0010  /* DRE3L_ENA */
+#define ARIZONA_DRE3L_ENA_SHIFT                       4  /* DRE3L_ENA */
+#define ARIZONA_DRE3L_ENA_WIDTH                       1  /* DRE3L_ENA */
+#define ARIZONA_DRE2R_ENA                        0x0008  /* DRE2R_ENA */
+#define ARIZONA_DRE2R_ENA_MASK                   0x0008  /* DRE2R_ENA */
+#define ARIZONA_DRE2R_ENA_SHIFT                       3  /* DRE2R_ENA */
+#define ARIZONA_DRE2R_ENA_WIDTH                       1  /* DRE2R_ENA */
+#define ARIZONA_DRE2L_ENA                        0x0004  /* DRE2L_ENA */
+#define ARIZONA_DRE2L_ENA_MASK                   0x0004  /* DRE2L_ENA */
+#define ARIZONA_DRE2L_ENA_SHIFT                       2  /* DRE2L_ENA */
+#define ARIZONA_DRE2L_ENA_WIDTH                       1  /* DRE2L_ENA */
+#define ARIZONA_DRE1R_ENA                        0x0002  /* DRE1R_ENA */
+#define ARIZONA_DRE1R_ENA_MASK                   0x0002  /* DRE1R_ENA */
+#define ARIZONA_DRE1R_ENA_SHIFT                       1  /* DRE1R_ENA */
+#define ARIZONA_DRE1R_ENA_WIDTH                       1  /* DRE1R_ENA */
+#define ARIZONA_DRE1L_ENA                        0x0001  /* DRE1L_ENA */
+#define ARIZONA_DRE1L_ENA_MASK                   0x0001  /* DRE1L_ENA */
+#define ARIZONA_DRE1L_ENA_SHIFT                       0  /* DRE1L_ENA */
+#define ARIZONA_DRE1L_ENA_WIDTH                       1  /* DRE1L_ENA */
+
+/*
+ * R1090 (0x442) - DRE Control 2
+ */
+#define ARIZONA_DRE_T_LOW_MASK                   0x3F00  /* DRE_T_LOW - [13:8] */
+#define ARIZONA_DRE_T_LOW_SHIFT                       8  /* DRE_T_LOW - [13:8] */
+#define ARIZONA_DRE_T_LOW_WIDTH                       6  /* DRE_T_LOW - [13:8] */
+
+/*
+ * R1091 (0x443) - DRE Control 3
+ */
+#define ARIZONA_DRE_GAIN_SHIFT_MASK              0xC000  /* DRE_GAIN_SHIFT - [15:14] */
+#define ARIZONA_DRE_GAIN_SHIFT_SHIFT                 14  /* DRE_GAIN_SHIFT - [15:14] */
+#define ARIZONA_DRE_GAIN_SHIFT_WIDTH                  2  /* DRE_GAIN_SHIFT - [15:14] */
+#define ARIZONA_DRE_LOW_LEVEL_ABS_MASK           0x000F  /* LOW_LEVEL_ABS - [3:0] */
+#define ARIZONA_DRE_LOW_LEVEL_ABS_SHIFT               0  /* LOW_LEVEL_ABS - [3:0] */
+#define ARIZONA_DRE_LOW_LEVEL_ABS_WIDTH               4  /* LOW_LEVEL_ABS - [3:0] */
+
 /*
  * R1104 (0x450) - DAC AEC Control 1
  */
index 689e6a0d9c998bfd845e92264fe779fa3b457692..ca0790fba2f5d60abbe975fa3547c363c525f443 100644 (file)
@@ -134,6 +134,11 @@ enum prcmu_clock {
        PRCMU_SIACLK,
        PRCMU_SVACLK,
        PRCMU_ACLK,
+       PRCMU_HVACLK, /* Ux540 only */
+       PRCMU_G1CLK, /* Ux540 only */
+       PRCMU_SDMMCHCLK,
+       PRCMU_CAMCLK,
+       PRCMU_BML8580CLK,
        PRCMU_NUM_REG_CLOCKS,
        PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
        PRCMU_CDCLK,
@@ -148,6 +153,13 @@ enum prcmu_clock {
        PRCMU_DSI0ESCCLK,
        PRCMU_DSI1ESCCLK,
        PRCMU_DSI2ESCCLK,
+       /* LCD DSI PLL - Ux540 only */
+       PRCMU_PLLDSI_LCD,
+       PRCMU_DSI0CLK_LCD,
+       PRCMU_DSI1CLK_LCD,
+       PRCMU_DSI0ESCCLK_LCD,
+       PRCMU_DSI1ESCCLK_LCD,
+       PRCMU_DSI2ESCCLK_LCD,
 };
 
 /**
index 1aa4f13cdfa6a4f2b0ceec56a689600f8d53626c..244fb0d51589ffc9d92ed440bed1cb8f56084ae0 100644 (file)
@@ -85,6 +85,19 @@ enum max77693_pmic_reg {
        MAX77693_PMIC_REG_END,
 };
 
+/* MAX77693 CHG_CNFG_00 register */
+#define CHG_CNFG_00_CHG_MASK           0x1
+#define CHG_CNFG_00_BUCK_MASK          0x4
+
+/* MAX77693 CHG_CNFG_09 Register */
+#define CHG_CNFG_09_CHGIN_ILIM_MASK    0x7F
+
+/* MAX77693 CHG_CTRL Register */
+#define SAFEOUT_CTRL_SAFEOUT1_MASK     0x3
+#define SAFEOUT_CTRL_SAFEOUT2_MASK     0xC
+#define SAFEOUT_CTRL_ENSAFEOUT1_MASK   0x40
+#define SAFEOUT_CTRL_ENSAFEOUT2_MASK   0x80
+
 /* Slave addr = 0x4A: MUIC */
 enum max77693_muic_reg {
        MAX77693_MUIC_REG_ID            = 0x00,
index 3109a6c5c9489ff0d4b4615c081d823e88c2238a..676f0f388992410fe0b7ac918a08bfe992d1ca91 100644 (file)
 #ifndef __LINUX_MFD_MAX77693_H
 #define __LINUX_MFD_MAX77693_H
 
+/* MAX77686 regulator IDs */
+enum max77693_regulators {
+       MAX77693_ESAFEOUT1 = 0,
+       MAX77693_ESAFEOUT2,
+       MAX77693_CHARGER,
+       MAX77693_REG_MAX,
+};
+
+struct max77693_regulator_data {
+       int id;
+       struct regulator_init_data *initdata;
+       struct device_node *of_node;
+};
+
 struct max77693_reg_data {
        u8 addr;
        u8 data;
@@ -52,6 +66,10 @@ struct max77693_muic_platform_data {
 struct max77693_platform_data {
        int wakeup;
 
+       /* regulator data */
+       struct max77693_regulator_data *regulators;
+       int num_regulators;
+
        /* muic data */
        struct max77693_muic_platform_data *muic_data;
 };
index bf070755982e3c62dfdd841601d0241ad7100864..41ed59276c002fc77b598ed60fb5fc68501e72c6 100644 (file)
@@ -78,20 +78,30 @@ struct mc13xxx_regulator_platform_data {
        struct mc13xxx_regulator_init_data *regulators;
 };
 
+enum {
+       /* MC13783 LED IDs */
+       MC13783_LED_MD,
+       MC13783_LED_AD,
+       MC13783_LED_KP,
+       MC13783_LED_R1,
+       MC13783_LED_G1,
+       MC13783_LED_B1,
+       MC13783_LED_R2,
+       MC13783_LED_G2,
+       MC13783_LED_B2,
+       MC13783_LED_R3,
+       MC13783_LED_G3,
+       MC13783_LED_B3,
+       /* MC13892 LED IDs */
+       MC13892_LED_MD,
+       MC13892_LED_AD,
+       MC13892_LED_KP,
+       MC13892_LED_R,
+       MC13892_LED_G,
+       MC13892_LED_B,
+};
+
 struct mc13xxx_led_platform_data {
-#define MC13783_LED_MD         0
-#define MC13783_LED_AD         1
-#define MC13783_LED_KP         2
-#define MC13783_LED_R1         3
-#define MC13783_LED_G1         4
-#define MC13783_LED_B1         5
-#define MC13783_LED_R2         6
-#define MC13783_LED_G2         7
-#define MC13783_LED_B2         8
-#define MC13783_LED_R3         9
-#define MC13783_LED_G3         10
-#define MC13783_LED_B3         11
-#define MC13783_LED_MAX MC13783_LED_B3
        int id;
        const char *name;
        const char *default_trigger;
@@ -100,46 +110,36 @@ struct mc13xxx_led_platform_data {
        char max_current;
 };
 
+#define MAX_LED_CONTROL_REGS   6
+
 struct mc13xxx_leds_platform_data {
-       int num_leds;
        struct mc13xxx_led_platform_data *led;
+       int num_leds;
 
-#define MC13783_LED_TRIODE_MD  (1 << 0)
-#define MC13783_LED_TRIODE_AD  (1 << 1)
-#define MC13783_LED_TRIODE_KP  (1 << 2)
-#define MC13783_LED_BOOST_EN   (1 << 3)
-#define MC13783_LED_TC1HALF    (1 << 4)
-#define MC13783_LED_SLEWLIMTC  (1 << 5)
-#define MC13783_LED_SLEWLIMBL  (1 << 6)
-#define MC13783_LED_TRIODE_TC1 (1 << 7)
-#define MC13783_LED_TRIODE_TC2 (1 << 8)
-#define MC13783_LED_TRIODE_TC3 (1 << 9)
-       int flags;
-
-#define MC13783_LED_AB_DISABLED                0
-#define MC13783_LED_AB_MD1             1
-#define MC13783_LED_AB_MD12            2
-#define MC13783_LED_AB_MD123           3
-#define MC13783_LED_AB_MD1234          4
-#define MC13783_LED_AB_MD1234_AD1      5
-#define MC13783_LED_AB_MD1234_AD12     6
-#define MC13783_LED_AB_MD1_AD          7
-       char abmode;
-
-#define MC13783_LED_ABREF_200MV        0
-#define MC13783_LED_ABREF_400MV        1
-#define MC13783_LED_ABREF_600MV        2
-#define MC13783_LED_ABREF_800MV        3
-       char abref;
-
-#define MC13783_LED_PERIOD_10MS                0
-#define MC13783_LED_PERIOD_100MS       1
-#define MC13783_LED_PERIOD_500MS       2
-#define MC13783_LED_PERIOD_2S          3
-       char bl_period;
-       char tc1_period;
-       char tc2_period;
-       char tc3_period;
+/* LED Control 0 */
+#define MC13783_LED_C0_ENABLE          (1 << 0)
+#define MC13783_LED_C0_TRIODE_MD       (1 << 7)
+#define MC13783_LED_C0_TRIODE_AD       (1 << 8)
+#define MC13783_LED_C0_TRIODE_KP       (1 << 9)
+#define MC13783_LED_C0_BOOST           (1 << 10)
+#define MC13783_LED_C0_ABMODE(x)       (((x) & 0x7) << 11)
+#define MC13783_LED_C0_ABREF(x)                (((x) & 0x3) << 14)
+/* LED Control 1 */
+#define MC13783_LED_C1_TC1HALF         (1 << 18)
+#define MC13783_LED_C1_SLEWLIM         (1 << 23)
+/* LED Control 2 */
+#define MC13783_LED_C2_PERIOD(x)       (((x) & 0x3) << 21)
+#define MC13783_LED_C2_SLEWLIM         (1 << 23)
+/* LED Control 3 */
+#define MC13783_LED_C3_PERIOD(x)       (((x) & 0x3) << 21)
+#define MC13783_LED_C3_TRIODE_TC1      (1 << 23)
+/* LED Control 4 */
+#define MC13783_LED_C4_PERIOD(x)       (((x) & 0x3) << 21)
+#define MC13783_LED_C4_TRIODE_TC2      (1 << 23)
+/* LED Control 5 */
+#define MC13783_LED_C5_PERIOD(x)       (((x) & 0x3) << 21)
+#define MC13783_LED_C5_TRIODE_TC3      (1 << 23)
+       u32 led_control[MAX_LED_CONTROL_REGS];
 };
 
 struct mc13xxx_buttons_platform_data {
index 94ac944d12f087b4cf1f21c58a5ace991bebe3de..7e7fbce7a30874ddca4c06bc37359042902c983b 100644 (file)
 
 #define TWL6040_HSDACENA               (1 << 0)
 #define TWL6040_HSDACMODE              (1 << 1)
+#define TWL6040_HSDRVENA               (1 << 2)
 #define TWL6040_HSDRVMODE              (1 << 3)
 
+/* HFLCTL/R (0x14/0x16) fields */
+
+#define TWL6040_HFDACENA               (1 << 0)
+#define TWL6040_HFPGAENA               (1 << 1)
+#define TWL6040_HFDRVENA               (1 << 4)
+
 /* VIBCTLL/R (0x18/0x1A) fields */
 
 #define TWL6040_VIBENA                 (1 << 0)
index 68e77659488950f69df451b04b065eee72c9d144..b5046f6313a91936a54d937eb24f5728ee585567 100644 (file)
@@ -182,6 +182,11 @@ struct wm8994_pdata {
         */
        int micdet_delay;
 
+       /* Delay between microphone detect completing and reporting on
+        * insert (specified in ms)
+        */
+       int mic_id_delay;
+
        /* IRQ for microphone detection if brought out directly as a
         * signal.
         */
index 053548961c15df6c81b1e6128e056f2806806cbc..db8cef3d5321606111933d28b02e257038e1e430 100644 (file)
 /*
  * R772 (0x304) - AIF1ADC LRCLK
  */
+#define WM8958_AIF1_LRCLK_INV                   0x1000  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_MASK              0x1000  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_SHIFT                 12  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_WIDTH                  1  /* AIF1_LRCLK_INV */
 #define WM8994_AIF1ADC_LRCLK_DIR                0x0800  /* AIF1ADC_LRCLK_DIR */
 #define WM8994_AIF1ADC_LRCLK_DIR_MASK           0x0800  /* AIF1ADC_LRCLK_DIR */
 #define WM8994_AIF1ADC_LRCLK_DIR_SHIFT              11  /* AIF1ADC_LRCLK_DIR */
 /*
  * R773 (0x305) - AIF1DAC LRCLK
  */
+#define WM8958_AIF1_LRCLK_INV                   0x1000  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_MASK              0x1000  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_SHIFT                 12  /* AIF1_LRCLK_INV */
+#define WM8958_AIF1_LRCLK_INV_WIDTH                  1  /* AIF1_LRCLK_INV */
 #define WM8994_AIF1DAC_LRCLK_DIR                0x0800  /* AIF1DAC_LRCLK_DIR */
 #define WM8994_AIF1DAC_LRCLK_DIR_MASK           0x0800  /* AIF1DAC_LRCLK_DIR */
 #define WM8994_AIF1DAC_LRCLK_DIR_SHIFT              11  /* AIF1DAC_LRCLK_DIR */
index 66d881f1d57665b5791d3a5a357c8cbff3d4c9a0..b87681adf0bada78cec851382c7719a1c5e66945 100644 (file)
@@ -25,11 +25,17 @@ struct file_ra_state;
 struct user_struct;
 struct writeback_control;
 
-#ifndef CONFIG_DISCONTIGMEM          /* Don't use mapnrs, do it properly */
+#ifndef CONFIG_NEED_MULTIPLE_NODES     /* Don't use mapnrs, do it properly */
 extern unsigned long max_mapnr;
+
+static inline void set_max_mapnr(unsigned long limit)
+{
+       max_mapnr = limit;
+}
+#else
+static inline void set_max_mapnr(unsigned long limit) { }
 #endif
 
-extern unsigned long num_physpages;
 extern unsigned long totalram_pages;
 extern void * high_memory;
 extern int page_cluster;
@@ -52,6 +58,9 @@ extern unsigned long sysctl_admin_reserve_kbytes;
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE)
 
+/* test whether an address (unsigned long or pointer) is aligned to PAGE_SIZE */
+#define PAGE_ALIGNED(addr)     IS_ALIGNED((unsigned long)addr, PAGE_SIZE)
+
 /*
  * Linux kernel virtual memory manager primitives.
  * The idea being to have a "virtual" mm in the same way
@@ -1305,11 +1314,12 @@ extern void free_initmem(void);
 /*
  * Free reserved pages within range [PAGE_ALIGN(start), end & PAGE_MASK)
  * into the buddy system. The freed pages will be poisoned with pattern
- * "poison" if it's non-zero.
+ * "poison" if it's within range [0, UCHAR_MAX].
  * Return pages freed into the buddy system.
  */
-extern unsigned long free_reserved_area(unsigned long start, unsigned long end,
+extern unsigned long free_reserved_area(void *start, void *end,
                                        int poison, char *s);
+
 #ifdef CONFIG_HIGHMEM
 /*
  * Free a highmem page into the buddy system, adjusting totalhigh_pages
@@ -1318,10 +1328,8 @@ extern unsigned long free_reserved_area(unsigned long start, unsigned long end,
 extern void free_highmem_page(struct page *page);
 #endif
 
-static inline void adjust_managed_page_count(struct page *page, long count)
-{
-       totalram_pages += count;
-}
+extern void adjust_managed_page_count(struct page *page, long count);
+extern void mem_init_print_info(const char *str);
 
 /* Free the reserved page into the buddy system, so it gets managed. */
 static inline void __free_reserved_page(struct page *page)
@@ -1345,18 +1353,29 @@ static inline void mark_page_reserved(struct page *page)
 
 /*
  * Default method to free all the __init memory into the buddy system.
- * The freed pages will be poisoned with pattern "poison" if it is
- * non-zero. Return pages freed into the buddy system.
+ * The freed pages will be poisoned with pattern "poison" if it's within
+ * range [0, UCHAR_MAX].
+ * Return pages freed into the buddy system.
  */
 static inline unsigned long free_initmem_default(int poison)
 {
        extern char __init_begin[], __init_end[];
 
-       return free_reserved_area(PAGE_ALIGN((unsigned long)&__init_begin) ,
-                                 ((unsigned long)&__init_end) & PAGE_MASK,
+       return free_reserved_area(&__init_begin, &__init_end,
                                  poison, "unused kernel");
 }
 
+static inline unsigned long get_num_physpages(void)
+{
+       int nid;
+       unsigned long phys_pages = 0;
+
+       for_each_online_node(nid)
+               phys_pages += node_present_pages(nid);
+
+       return phys_pages;
+}
+
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
 /*
  * With CONFIG_HAVE_MEMBLOCK_NODE_MAP set, an architecture may initialise its
index 9aa863da287fedf383f3c507c287aa220cbd6a86..92dc257251e45a04b75445d049922688cac7fbe9 100644 (file)
@@ -11,11 +11,17 @@ extern int sysctl_overcommit_memory;
 extern int sysctl_overcommit_ratio;
 extern struct percpu_counter vm_committed_as;
 
+#ifdef CONFIG_SMP
+extern s32 vm_committed_as_batch;
+#else
+#define vm_committed_as_batch 0
+#endif
+
 unsigned long vm_memory_committed(void);
 
 static inline void vm_acct_memory(long pages)
 {
-       percpu_counter_add(&vm_committed_as, pages);
+       __percpu_counter_add(&vm_committed_as, pages, vm_committed_as_batch);
 }
 
 static inline void vm_unacct_memory(long pages)
index 5c76737d836b1edc218bfba700fb26c09e62408a..ae19af5ec02c0c4dd6fe149d4d97f9ca8a37cb71 100644 (file)
@@ -474,10 +474,16 @@ struct zone {
         * frequently read in proximity to zone->lock.  It's good to
         * give them a chance of being in the same cacheline.
         *
-        * Write access to present_pages and managed_pages at runtime should
-        * be protected by lock_memory_hotplug()/unlock_memory_hotplug().
-        * Any reader who can't tolerant drift of present_pages and
-        * managed_pages should hold memory hotplug lock to get a stable value.
+        * Write access to present_pages at runtime should be protected by
+        * lock_memory_hotplug()/unlock_memory_hotplug().  Any reader who can't
+        * tolerant drift of present_pages should hold memory hotplug lock to
+        * get a stable value.
+        *
+        * Read access to managed_pages should be safe because it's unsigned
+        * long. Write access to zone->managed_pages and totalram_pages are
+        * protected by managed_page_count_lock at runtime. Idealy only
+        * adjust_managed_page_count() should be used instead of directly
+        * touching zone->managed_pages and totalram_pages.
         */
        unsigned long           spanned_pages;
        unsigned long           present_pages;
@@ -495,6 +501,13 @@ typedef enum {
        ZONE_CONGESTED,                 /* zone has many dirty pages backed by
                                         * a congested BDI
                                         */
+       ZONE_TAIL_LRU_DIRTY,            /* reclaim scanning has recently found
+                                        * many dirty file pages at the tail
+                                        * of the LRU.
+                                        */
+       ZONE_WRITEBACK,                 /* reclaim scanning has recently found
+                                        * many pages under writeback
+                                        */
 } zone_flags_t;
 
 static inline void zone_set_flag(struct zone *zone, zone_flags_t flag)
@@ -517,6 +530,16 @@ static inline int zone_is_reclaim_congested(const struct zone *zone)
        return test_bit(ZONE_CONGESTED, &zone->flags);
 }
 
+static inline int zone_is_reclaim_dirty(const struct zone *zone)
+{
+       return test_bit(ZONE_TAIL_LRU_DIRTY, &zone->flags);
+}
+
+static inline int zone_is_reclaim_writeback(const struct zone *zone)
+{
+       return test_bit(ZONE_WRITEBACK, &zone->flags);
+}
+
 static inline int zone_is_reclaim_locked(const struct zone *zone)
 {
        return test_bit(ZONE_RECLAIM_LOCKED, &zone->flags);
@@ -716,7 +739,10 @@ typedef struct pglist_data {
         * or node_spanned_pages stay constant.  Holding this will also
         * guarantee that any pfn_valid() stays that way.
         *
-        * Nests above zone->lock and zone->size_seqlock.
+        * pgdat_resize_lock() and pgdat_resize_unlock() are provided to
+        * manipulate node_size_lock without checking for CONFIG_MEMORY_HOTPLUG.
+        *
+        * Nests above zone->lock and zone->span_seqlock
         */
        spinlock_t node_size_lock;
 #endif
@@ -1111,6 +1137,10 @@ struct mem_section {
        struct page_cgroup *page_cgroup;
        unsigned long pad;
 #endif
+       /*
+        * WARNING: mem_section must be a power-of-2 in size for the
+        * calculation and use of SECTION_ROOT_MASK to make sense.
+        */
 };
 
 #ifdef CONFIG_SPARSEMEM_EXTREME
index b508016fb76d3b912101695059044318d56150f4..b62d4af6c667c27bbbd3620fde9813c9d6b529b8 100644 (file)
@@ -456,7 +456,8 @@ enum dmi_field {
 };
 
 struct dmi_strmatch {
-       unsigned char slot;
+       unsigned char slot:7;
+       unsigned char exact_match:1;
        char substr[79];
 };
 
@@ -474,7 +475,8 @@ struct dmi_system_id {
  */
 #define dmi_device_id dmi_system_id
 
-#define DMI_MATCH(a, b)        { a, b }
+#define DMI_MATCH(a, b)        { .slot = a, .substr = b }
+#define DMI_EXACT_MATCH(a, b)  { .slot = a, .substr = b, .exact_match = 1 }
 
 #define PLATFORM_NAME_SIZE     20
 #define PLATFORM_MODULE_PREFIX "platform:"
@@ -577,4 +579,23 @@ struct mei_cl_device_id {
        kernel_ulong_t driver_info;
 };
 
+/* RapidIO */
+
+#define RIO_ANY_ID     0xffff
+
+/**
+ * struct rio_device_id - RIO device identifier
+ * @did: RapidIO device ID
+ * @vid: RapidIO vendor ID
+ * @asm_did: RapidIO assembly device ID
+ * @asm_vid: RapidIO assembly vendor ID
+ *
+ * Identifies a RapidIO device based on both the device/vendor IDs and
+ * the assembly device/vendor IDs.
+ */
+struct rio_device_id {
+       __u16 did, vid;
+       __u16 asm_did, asm_vid;
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index 20c2d6dd5d259f6467baf0939e6837ed85e936b3..ee66f3a12fb6ca3f1cd067a5b9c0350767bc11e2 100644 (file)
@@ -35,6 +35,7 @@ struct msi_desc {
 
        u32 masked;                     /* mask bits */
        unsigned int irq;
+       unsigned int nvec_used;         /* number of messages */
        struct list_head list;
 
        union {
index 731d77d6e155de48fed65db977d2e83843465c06..4ac8b1977b73c53cc915b8f7ee29d87bdba8c23a 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/linkage.h>
 #include <linux/lockdep.h>
+#include <linux/debug_locks.h>
 
 /*
  * Mutexes - debugging helpers:
index 433da8a1a42642ce33596b536f2dcaad4427b3ac..3793ed7feeeb1de4f0eec721da5bf008b92f786d 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef __LINUX_MUTEX_H
 #define __LINUX_MUTEX_H
 
+#include <asm/current.h>
 #include <linux/list.h>
 #include <linux/spinlock_types.h>
 #include <linux/linkage.h>
@@ -77,6 +78,40 @@ struct mutex_waiter {
 #endif
 };
 
+struct ww_class {
+       atomic_long_t stamp;
+       struct lock_class_key acquire_key;
+       struct lock_class_key mutex_key;
+       const char *acquire_name;
+       const char *mutex_name;
+};
+
+struct ww_acquire_ctx {
+       struct task_struct *task;
+       unsigned long stamp;
+       unsigned acquired;
+#ifdef CONFIG_DEBUG_MUTEXES
+       unsigned done_acquire;
+       struct ww_class *ww_class;
+       struct ww_mutex *contending_lock;
+#endif
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct lockdep_map dep_map;
+#endif
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+       unsigned deadlock_inject_interval;
+       unsigned deadlock_inject_countdown;
+#endif
+};
+
+struct ww_mutex {
+       struct mutex base;
+       struct ww_acquire_ctx *ctx;
+#ifdef CONFIG_DEBUG_MUTEXES
+       struct ww_class *ww_class;
+#endif
+};
+
 #ifdef CONFIG_DEBUG_MUTEXES
 # include <linux/mutex-debug.h>
 #else
@@ -101,8 +136,11 @@ static inline void mutex_destroy(struct mutex *lock) {}
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # define __DEP_MAP_MUTEX_INITIALIZER(lockname) \
                , .dep_map = { .name = #lockname }
+# define __WW_CLASS_MUTEX_INITIALIZER(lockname, ww_class) \
+               , .ww_class = &ww_class
 #else
 # define __DEP_MAP_MUTEX_INITIALIZER(lockname)
+# define __WW_CLASS_MUTEX_INITIALIZER(lockname, ww_class)
 #endif
 
 #define __MUTEX_INITIALIZER(lockname) \
@@ -112,12 +150,48 @@ static inline void mutex_destroy(struct mutex *lock) {}
                __DEBUG_MUTEX_INITIALIZER(lockname) \
                __DEP_MAP_MUTEX_INITIALIZER(lockname) }
 
+#define __WW_CLASS_INITIALIZER(ww_class) \
+               { .stamp = ATOMIC_LONG_INIT(0) \
+               , .acquire_name = #ww_class "_acquire" \
+               , .mutex_name = #ww_class "_mutex" }
+
+#define __WW_MUTEX_INITIALIZER(lockname, class) \
+               { .base = { \__MUTEX_INITIALIZER(lockname) } \
+               __WW_CLASS_MUTEX_INITIALIZER(lockname, class) }
+
 #define DEFINE_MUTEX(mutexname) \
        struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
+#define DEFINE_WW_CLASS(classname) \
+       struct ww_class classname = __WW_CLASS_INITIALIZER(classname)
+
+#define DEFINE_WW_MUTEX(mutexname, ww_class) \
+       struct ww_mutex mutexname = __WW_MUTEX_INITIALIZER(mutexname, ww_class)
+
+
 extern void __mutex_init(struct mutex *lock, const char *name,
                         struct lock_class_key *key);
 
+/**
+ * ww_mutex_init - initialize the w/w mutex
+ * @lock: the mutex to be initialized
+ * @ww_class: the w/w class the mutex should belong to
+ *
+ * Initialize the w/w mutex to unlocked state and associate it with the given
+ * class.
+ *
+ * It is not allowed to initialize an already locked mutex.
+ */
+static inline void ww_mutex_init(struct ww_mutex *lock,
+                                struct ww_class *ww_class)
+{
+       __mutex_init(&lock->base, ww_class->mutex_name, &ww_class->mutex_key);
+       lock->ctx = NULL;
+#ifdef CONFIG_DEBUG_MUTEXES
+       lock->ww_class = ww_class;
+#endif
+}
+
 /**
  * mutex_is_locked - is the mutex locked
  * @lock: the mutex to be queried
@@ -136,6 +210,7 @@ static inline int mutex_is_locked(struct mutex *lock)
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
 extern void _mutex_lock_nest_lock(struct mutex *lock, struct lockdep_map *nest_lock);
+
 extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock,
                                        unsigned int subclass);
 extern int __must_check mutex_lock_killable_nested(struct mutex *lock,
@@ -147,7 +222,7 @@ extern int __must_check mutex_lock_killable_nested(struct mutex *lock,
 
 #define mutex_lock_nest_lock(lock, nest_lock)                          \
 do {                                                                   \
-       typecheck(struct lockdep_map *, &(nest_lock)->dep_map);         \
+       typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \
        _mutex_lock_nest_lock(lock, &(nest_lock)->dep_map);             \
 } while (0)
 
@@ -170,6 +245,292 @@ extern int __must_check mutex_lock_killable(struct mutex *lock);
  */
 extern int mutex_trylock(struct mutex *lock);
 extern void mutex_unlock(struct mutex *lock);
+
+/**
+ * ww_acquire_init - initialize a w/w acquire context
+ * @ctx: w/w acquire context to initialize
+ * @ww_class: w/w class of the context
+ *
+ * Initializes an context to acquire multiple mutexes of the given w/w class.
+ *
+ * Context-based w/w mutex acquiring can be done in any order whatsoever within
+ * a given lock class. Deadlocks will be detected and handled with the
+ * wait/wound logic.
+ *
+ * Mixing of context-based w/w mutex acquiring and single w/w mutex locking can
+ * result in undetected deadlocks and is so forbidden. Mixing different contexts
+ * for the same w/w class when acquiring mutexes can also result in undetected
+ * deadlocks, and is hence also forbidden. Both types of abuse will be caught by
+ * enabling CONFIG_PROVE_LOCKING.
+ *
+ * Nesting of acquire contexts for _different_ w/w classes is possible, subject
+ * to the usual locking rules between different lock classes.
+ *
+ * An acquire context must be released with ww_acquire_fini by the same task
+ * before the memory is freed. It is recommended to allocate the context itself
+ * on the stack.
+ */
+static inline void ww_acquire_init(struct ww_acquire_ctx *ctx,
+                                  struct ww_class *ww_class)
+{
+       ctx->task = current;
+       ctx->stamp = atomic_long_inc_return(&ww_class->stamp);
+       ctx->acquired = 0;
+#ifdef CONFIG_DEBUG_MUTEXES
+       ctx->ww_class = ww_class;
+       ctx->done_acquire = 0;
+       ctx->contending_lock = NULL;
+#endif
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       debug_check_no_locks_freed((void *)ctx, sizeof(*ctx));
+       lockdep_init_map(&ctx->dep_map, ww_class->acquire_name,
+                        &ww_class->acquire_key, 0);
+       mutex_acquire(&ctx->dep_map, 0, 0, _RET_IP_);
+#endif
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+       ctx->deadlock_inject_interval = 1;
+       ctx->deadlock_inject_countdown = ctx->stamp & 0xf;
+#endif
+}
+
+/**
+ * ww_acquire_done - marks the end of the acquire phase
+ * @ctx: the acquire context
+ *
+ * Marks the end of the acquire phase, any further w/w mutex lock calls using
+ * this context are forbidden.
+ *
+ * Calling this function is optional, it is just useful to document w/w mutex
+ * code and clearly designated the acquire phase from actually using the locked
+ * data structures.
+ */
+static inline void ww_acquire_done(struct ww_acquire_ctx *ctx)
+{
+#ifdef CONFIG_DEBUG_MUTEXES
+       lockdep_assert_held(ctx);
+
+       DEBUG_LOCKS_WARN_ON(ctx->done_acquire);
+       ctx->done_acquire = 1;
+#endif
+}
+
+/**
+ * ww_acquire_fini - releases a w/w acquire context
+ * @ctx: the acquire context to free
+ *
+ * Releases a w/w acquire context. This must be called _after_ all acquired w/w
+ * mutexes have been released with ww_mutex_unlock.
+ */
+static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx)
+{
+#ifdef CONFIG_DEBUG_MUTEXES
+       mutex_release(&ctx->dep_map, 0, _THIS_IP_);
+
+       DEBUG_LOCKS_WARN_ON(ctx->acquired);
+       if (!config_enabled(CONFIG_PROVE_LOCKING))
+               /*
+                * lockdep will normally handle this,
+                * but fail without anyway
+                */
+               ctx->done_acquire = 1;
+
+       if (!config_enabled(CONFIG_DEBUG_LOCK_ALLOC))
+               /* ensure ww_acquire_fini will still fail if called twice */
+               ctx->acquired = ~0U;
+#endif
+}
+
+extern int __must_check __ww_mutex_lock(struct ww_mutex *lock,
+                                       struct ww_acquire_ctx *ctx);
+extern int __must_check __ww_mutex_lock_interruptible(struct ww_mutex *lock,
+                                                     struct ww_acquire_ctx *ctx);
+
+/**
+ * ww_mutex_lock - acquire the w/w mutex
+ * @lock: the mutex to be acquired
+ * @ctx: w/w acquire context, or NULL to acquire only a single lock.
+ *
+ * Lock the w/w mutex exclusively for this task.
+ *
+ * Deadlocks within a given w/w class of locks are detected and handled with the
+ * wait/wound algorithm. If the lock isn't immediately avaiable this function
+ * will either sleep until it is (wait case). Or it selects the current context
+ * for backing off by returning -EDEADLK (wound case). Trying to acquire the
+ * same lock with the same context twice is also detected and signalled by
+ * returning -EALREADY. Returns 0 if the mutex was successfully acquired.
+ *
+ * In the wound case the caller must release all currently held w/w mutexes for
+ * the given context and then wait for this contending lock to be available by
+ * calling ww_mutex_lock_slow. Alternatively callers can opt to not acquire this
+ * lock and proceed with trying to acquire further w/w mutexes (e.g. when
+ * scanning through lru lists trying to free resources).
+ *
+ * The mutex must later on be released by the same task that
+ * acquired it. The task may not exit without first unlocking the mutex. Also,
+ * kernel memory where the mutex resides must not be freed with the mutex still
+ * locked. The mutex must first be initialized (or statically defined) before it
+ * can be locked. memset()-ing the mutex to 0 is not allowed. The mutex must be
+ * of the same w/w lock class as was used to initialize the acquire context.
+ *
+ * A mutex acquired with this function must be released with ww_mutex_unlock.
+ */
+static inline int ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+       if (ctx)
+               return __ww_mutex_lock(lock, ctx);
+       else {
+               mutex_lock(&lock->base);
+               return 0;
+       }
+}
+
+/**
+ * ww_mutex_lock_interruptible - acquire the w/w mutex, interruptible
+ * @lock: the mutex to be acquired
+ * @ctx: w/w acquire context
+ *
+ * Lock the w/w mutex exclusively for this task.
+ *
+ * Deadlocks within a given w/w class of locks are detected and handled with the
+ * wait/wound algorithm. If the lock isn't immediately avaiable this function
+ * will either sleep until it is (wait case). Or it selects the current context
+ * for backing off by returning -EDEADLK (wound case). Trying to acquire the
+ * same lock with the same context twice is also detected and signalled by
+ * returning -EALREADY. Returns 0 if the mutex was successfully acquired. If a
+ * signal arrives while waiting for the lock then this function returns -EINTR.
+ *
+ * In the wound case the caller must release all currently held w/w mutexes for
+ * the given context and then wait for this contending lock to be available by
+ * calling ww_mutex_lock_slow_interruptible. Alternatively callers can opt to
+ * not acquire this lock and proceed with trying to acquire further w/w mutexes
+ * (e.g. when scanning through lru lists trying to free resources).
+ *
+ * The mutex must later on be released by the same task that
+ * acquired it. The task may not exit without first unlocking the mutex. Also,
+ * kernel memory where the mutex resides must not be freed with the mutex still
+ * locked. The mutex must first be initialized (or statically defined) before it
+ * can be locked. memset()-ing the mutex to 0 is not allowed. The mutex must be
+ * of the same w/w lock class as was used to initialize the acquire context.
+ *
+ * A mutex acquired with this function must be released with ww_mutex_unlock.
+ */
+static inline int __must_check ww_mutex_lock_interruptible(struct ww_mutex *lock,
+                                                          struct ww_acquire_ctx *ctx)
+{
+       if (ctx)
+               return __ww_mutex_lock_interruptible(lock, ctx);
+       else
+               return mutex_lock_interruptible(&lock->base);
+}
+
+/**
+ * ww_mutex_lock_slow - slowpath acquiring of the w/w mutex
+ * @lock: the mutex to be acquired
+ * @ctx: w/w acquire context
+ *
+ * Acquires a w/w mutex with the given context after a wound case. This function
+ * will sleep until the lock becomes available.
+ *
+ * The caller must have released all w/w mutexes already acquired with the
+ * context and then call this function on the contended lock.
+ *
+ * Afterwards the caller may continue to (re)acquire the other w/w mutexes it
+ * needs with ww_mutex_lock. Note that the -EALREADY return code from
+ * ww_mutex_lock can be used to avoid locking this contended mutex twice.
+ *
+ * It is forbidden to call this function with any other w/w mutexes associated
+ * with the context held. It is forbidden to call this on anything else than the
+ * contending mutex.
+ *
+ * Note that the slowpath lock acquiring can also be done by calling
+ * ww_mutex_lock directly. This function here is simply to help w/w mutex
+ * locking code readability by clearly denoting the slowpath.
+ */
+static inline void
+ww_mutex_lock_slow(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+       int ret;
+#ifdef CONFIG_DEBUG_MUTEXES
+       DEBUG_LOCKS_WARN_ON(!ctx->contending_lock);
+#endif
+       ret = ww_mutex_lock(lock, ctx);
+       (void)ret;
+}
+
+/**
+ * ww_mutex_lock_slow_interruptible - slowpath acquiring of the w/w mutex,
+ *                                   interruptible
+ * @lock: the mutex to be acquired
+ * @ctx: w/w acquire context
+ *
+ * Acquires a w/w mutex with the given context after a wound case. This function
+ * will sleep until the lock becomes available and returns 0 when the lock has
+ * been acquired. If a signal arrives while waiting for the lock then this
+ * function returns -EINTR.
+ *
+ * The caller must have released all w/w mutexes already acquired with the
+ * context and then call this function on the contended lock.
+ *
+ * Afterwards the caller may continue to (re)acquire the other w/w mutexes it
+ * needs with ww_mutex_lock. Note that the -EALREADY return code from
+ * ww_mutex_lock can be used to avoid locking this contended mutex twice.
+ *
+ * It is forbidden to call this function with any other w/w mutexes associated
+ * with the given context held. It is forbidden to call this on anything else
+ * than the contending mutex.
+ *
+ * Note that the slowpath lock acquiring can also be done by calling
+ * ww_mutex_lock_interruptible directly. This function here is simply to help
+ * w/w mutex locking code readability by clearly denoting the slowpath.
+ */
+static inline int __must_check
+ww_mutex_lock_slow_interruptible(struct ww_mutex *lock,
+                                struct ww_acquire_ctx *ctx)
+{
+#ifdef CONFIG_DEBUG_MUTEXES
+       DEBUG_LOCKS_WARN_ON(!ctx->contending_lock);
+#endif
+       return ww_mutex_lock_interruptible(lock, ctx);
+}
+
+extern void ww_mutex_unlock(struct ww_mutex *lock);
+
+/**
+ * ww_mutex_trylock - tries to acquire the w/w mutex without acquire context
+ * @lock: mutex to lock
+ *
+ * Trylocks a mutex without acquire context, so no deadlock detection is
+ * possible. Returns 1 if the mutex has been acquired successfully, 0 otherwise.
+ */
+static inline int __must_check ww_mutex_trylock(struct ww_mutex *lock)
+{
+       return mutex_trylock(&lock->base);
+}
+
+/***
+ * ww_mutex_destroy - mark a w/w mutex unusable
+ * @lock: the mutex to be destroyed
+ *
+ * This function marks the mutex uninitialized, and any subsequent
+ * use of the mutex is forbidden. The mutex must not be locked when
+ * this function is called.
+ */
+static inline void ww_mutex_destroy(struct ww_mutex *lock)
+{
+       mutex_destroy(&lock->base);
+}
+
+/**
+ * ww_mutex_is_locked - is the w/w mutex locked
+ * @lock: the mutex to be queried
+ *
+ * Returns 1 if the mutex is locked, 0 if unlocked.
+ */
+static inline bool ww_mutex_is_locked(struct ww_mutex *lock)
+{
+       return mutex_is_locked(&lock->base);
+}
+
 extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
 
 #ifndef CONFIG_HAVE_ARCH_MUTEX_CPU_RELAX
index 4871170a04a0b24b33e2a5221577fb22565d363b..ae4981ebd18eaacacafb0cf34b040f67c2c3b729 100644 (file)
@@ -41,6 +41,7 @@ struct nbd_device {
        u64 bytesize;
        pid_t pid; /* pid of nbd-client, if attached */
        int xmit_timeout;
+       int disconnect; /* a disconnect has been requested by user */
 };
 
 #endif
index be655e4a2a75b23e056c1631e5219fd52dd6c6f8..2ee8cd2466b595179a41641511fac87fa4c9a8ff 100644 (file)
@@ -80,10 +80,4 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
                                                        PB_migrate_skip)
 #endif /* CONFIG_COMPACTION */
 
-#define get_pageblock_flags(page) \
-                       get_pageblock_flags_group(page, 0, PB_migrate_end)
-#define set_pageblock_flags(page, flags) \
-                       set_pageblock_flags_group(page, flags,  \
-                                                 0, PB_migrate_end)
-
 #endif /* PAGEBLOCK_FLAGS_H */
index 2aa12b8499c0446930ec46149d43e2c9bb8fe81d..e4dbfab377296765e6190d7d6f1ead9bf53245ec 100644 (file)
@@ -21,7 +21,7 @@ struct pagevec {
 };
 
 void __pagevec_release(struct pagevec *pvec);
-void __pagevec_lru_add(struct pagevec *pvec, enum lru_list lru);
+void __pagevec_lru_add(struct pagevec *pvec);
 unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
                pgoff_t start, unsigned nr_pages);
 unsigned pagevec_lookup_tag(struct pagevec *pvec,
@@ -64,36 +64,4 @@ static inline void pagevec_release(struct pagevec *pvec)
                __pagevec_release(pvec);
 }
 
-static inline void __pagevec_lru_add_anon(struct pagevec *pvec)
-{
-       __pagevec_lru_add(pvec, LRU_INACTIVE_ANON);
-}
-
-static inline void __pagevec_lru_add_active_anon(struct pagevec *pvec)
-{
-       __pagevec_lru_add(pvec, LRU_ACTIVE_ANON);
-}
-
-static inline void __pagevec_lru_add_file(struct pagevec *pvec)
-{
-       __pagevec_lru_add(pvec, LRU_INACTIVE_FILE);
-}
-
-static inline void __pagevec_lru_add_active_file(struct pagevec *pvec)
-{
-       __pagevec_lru_add(pvec, LRU_ACTIVE_FILE);
-}
-
-static inline void pagevec_lru_add_file(struct pagevec *pvec)
-{
-       if (pagevec_count(pvec))
-               __pagevec_lru_add_file(pvec);
-}
-
-static inline void pagevec_lru_add_anon(struct pagevec *pvec)
-{
-       if (pagevec_count(pvec))
-               __pagevec_lru_add_anon(pvec);
-}
-
 #endif /* _LINUX_PAGEVEC_H */
index 3a24e4ff32481898f5009c2a162c9a7f33d0222e..0fd1f1582fa1cdf359b33f3cddeaa60026f492ac 100644 (file)
@@ -364,7 +364,8 @@ static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
        return dev;
 }
 
-struct pci_dev *alloc_pci_dev(void);
+struct pci_dev *pci_alloc_dev(struct pci_bus *bus);
+struct pci_dev * __deprecated alloc_pci_dev(void);
 
 #define        to_pci_dev(n) container_of(n, struct pci_dev, dev)
 #define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
@@ -1018,6 +1019,8 @@ int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *);
 void pci_release_selected_regions(struct pci_dev *, int);
 
 /* drivers/pci/bus.c */
+struct pci_bus *pci_bus_get(struct pci_bus *bus);
+void pci_bus_put(struct pci_bus *bus);
 void pci_add_resource(struct list_head *resources, struct resource *res);
 void pci_add_resource_offset(struct list_head *resources, struct resource *res,
                             resource_size_t offset);
@@ -1643,6 +1646,7 @@ void pcibios_set_master(struct pci_dev *dev);
 int pcibios_set_pcie_reset_state(struct pci_dev *dev,
                                 enum pcie_reset_state state);
 int pcibios_add_device(struct pci_dev *dev);
+void pcibios_release_device(struct pci_dev *dev);
 
 #ifdef CONFIG_PCI_MMCONFIG
 void __init pci_mmcfg_early_init(void);
index c12916248469f577795d28e96c4f86be747fbf5b..3bed2e89611bf2d6a5d41fe2c38ebbb98d4dc7f4 100644 (file)
 #define PCI_DEVICE_ID_AMD_8131_BRIDGE  0x7450
 #define PCI_DEVICE_ID_AMD_8131_APIC    0x7451
 #define PCI_DEVICE_ID_AMD_8132_BRIDGE  0x7458
-#define PCI_DEVICE_ID_AMD_HUDSON2_SMBUS        0x780b
 #define PCI_DEVICE_ID_AMD_CS5535_IDE    0x208F
 #define PCI_DEVICE_ID_AMD_CS5536_ISA    0x2090
 #define PCI_DEVICE_ID_AMD_CS5536_FLASH  0x2091
 #define PCI_DEVICE_ID_AMD_CS5536_IDE    0x209A
 #define PCI_DEVICE_ID_AMD_LX_VIDEO  0x2081
 #define PCI_DEVICE_ID_AMD_LX_AES    0x2082
-#define PCI_DEVICE_ID_AMD_HUDSON2_IDE          0x780c
 #define PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE     0x7800
+#define PCI_DEVICE_ID_AMD_HUDSON2_SMBUS                0x780b
+#define PCI_DEVICE_ID_AMD_HUDSON2_IDE          0x780c
 
 #define PCI_VENDOR_ID_TRIDENT          0x1023
 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX        0x2000
 
 #define PCI_VENDOR_ID_ASMEDIA          0x1b21
 
+#define PCI_VENDOR_ID_CIRCUITCO                0x1cc8
+#define PCI_SUBSYSTEM_ID_CIRCUITCO_MINNOWBOARD 0x0001
+
 #define PCI_VENDOR_ID_TEKRAM           0x1de1
 #define PCI_DEVICE_ID_TEKRAM_DC290     0xdc29
 
diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h
new file mode 100644 (file)
index 0000000..95961f0
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Percpu refcounts:
+ * (C) 2012 Google, Inc.
+ * Author: Kent Overstreet <koverstreet@google.com>
+ *
+ * This implements a refcount with similar semantics to atomic_t - atomic_inc(),
+ * atomic_dec_and_test() - but percpu.
+ *
+ * There's one important difference between percpu refs and normal atomic_t
+ * refcounts; you have to keep track of your initial refcount, and then when you
+ * start shutting down you call percpu_ref_kill() _before_ dropping the initial
+ * refcount.
+ *
+ * The refcount will have a range of 0 to ((1U << 31) - 1), i.e. one bit less
+ * than an atomic_t - this is because of the way shutdown works, see
+ * percpu_ref_kill()/PCPU_COUNT_BIAS.
+ *
+ * Before you call percpu_ref_kill(), percpu_ref_put() does not check for the
+ * refcount hitting 0 - it can't, if it was in percpu mode. percpu_ref_kill()
+ * puts the ref back in single atomic_t mode, collecting the per cpu refs and
+ * issuing the appropriate barriers, and then marks the ref as shutting down so
+ * that percpu_ref_put() will check for the ref hitting 0.  After it returns,
+ * it's safe to drop the initial ref.
+ *
+ * USAGE:
+ *
+ * See fs/aio.c for some example usage; it's used there for struct kioctx, which
+ * is created when userspaces calls io_setup(), and destroyed when userspace
+ * calls io_destroy() or the process exits.
+ *
+ * In the aio code, kill_ioctx() is called when we wish to destroy a kioctx; it
+ * calls percpu_ref_kill(), then hlist_del_rcu() and sychronize_rcu() to remove
+ * the kioctx from the proccess's list of kioctxs - after that, there can't be
+ * any new users of the kioctx (from lookup_ioctx()) and it's then safe to drop
+ * the initial ref with percpu_ref_put().
+ *
+ * Code that does a two stage shutdown like this often needs some kind of
+ * explicit synchronization to ensure the initial refcount can only be dropped
+ * once - percpu_ref_kill() does this for you, it returns true once and false if
+ * someone else already called it. The aio code uses it this way, but it's not
+ * necessary if the code has some other mechanism to synchronize teardown.
+ * around.
+ */
+
+#ifndef _LINUX_PERCPU_REFCOUNT_H
+#define _LINUX_PERCPU_REFCOUNT_H
+
+#include <linux/atomic.h>
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <linux/rcupdate.h>
+
+struct percpu_ref;
+typedef void (percpu_ref_func_t)(struct percpu_ref *);
+
+struct percpu_ref {
+       atomic_t                count;
+       /*
+        * The low bit of the pointer indicates whether the ref is in percpu
+        * mode; if set, then get/put will manipulate the atomic_t (this is a
+        * hack because we need to keep the pointer around for
+        * percpu_ref_kill_rcu())
+        */
+       unsigned __percpu       *pcpu_count;
+       percpu_ref_func_t       *release;
+       percpu_ref_func_t       *confirm_kill;
+       struct rcu_head         rcu;
+};
+
+int __must_check percpu_ref_init(struct percpu_ref *ref,
+                                percpu_ref_func_t *release);
+void percpu_ref_cancel_init(struct percpu_ref *ref);
+void percpu_ref_kill_and_confirm(struct percpu_ref *ref,
+                                percpu_ref_func_t *confirm_kill);
+
+/**
+ * percpu_ref_kill - drop the initial ref
+ * @ref: percpu_ref to kill
+ *
+ * Must be used to drop the initial ref on a percpu refcount; must be called
+ * precisely once before shutdown.
+ *
+ * Puts @ref in non percpu mode, then does a call_rcu() before gathering up the
+ * percpu counters and dropping the initial ref.
+ */
+static inline void percpu_ref_kill(struct percpu_ref *ref)
+{
+       return percpu_ref_kill_and_confirm(ref, NULL);
+}
+
+#define PCPU_STATUS_BITS       2
+#define PCPU_STATUS_MASK       ((1 << PCPU_STATUS_BITS) - 1)
+#define PCPU_REF_PTR           0
+#define PCPU_REF_DEAD          1
+
+#define REF_STATUS(count)      (((unsigned long) count) & PCPU_STATUS_MASK)
+
+/**
+ * percpu_ref_get - increment a percpu refcount
+ * @ref: percpu_ref to get
+ *
+ * Analagous to atomic_inc().
+  */
+static inline void percpu_ref_get(struct percpu_ref *ref)
+{
+       unsigned __percpu *pcpu_count;
+
+       rcu_read_lock_sched();
+
+       pcpu_count = ACCESS_ONCE(ref->pcpu_count);
+
+       if (likely(REF_STATUS(pcpu_count) == PCPU_REF_PTR))
+               __this_cpu_inc(*pcpu_count);
+       else
+               atomic_inc(&ref->count);
+
+       rcu_read_unlock_sched();
+}
+
+/**
+ * percpu_ref_tryget - try to increment a percpu refcount
+ * @ref: percpu_ref to try-get
+ *
+ * Increment a percpu refcount unless it has already been killed.  Returns
+ * %true on success; %false on failure.
+ *
+ * Completion of percpu_ref_kill() in itself doesn't guarantee that tryget
+ * will fail.  For such guarantee, percpu_ref_kill_and_confirm() should be
+ * used.  After the confirm_kill callback is invoked, it's guaranteed that
+ * no new reference will be given out by percpu_ref_tryget().
+ */
+static inline bool percpu_ref_tryget(struct percpu_ref *ref)
+{
+       unsigned __percpu *pcpu_count;
+       int ret = false;
+
+       rcu_read_lock_sched();
+
+       pcpu_count = ACCESS_ONCE(ref->pcpu_count);
+
+       if (likely(REF_STATUS(pcpu_count) == PCPU_REF_PTR)) {
+               __this_cpu_inc(*pcpu_count);
+               ret = true;
+       }
+
+       rcu_read_unlock_sched();
+
+       return ret;
+}
+
+/**
+ * percpu_ref_put - decrement a percpu refcount
+ * @ref: percpu_ref to put
+ *
+ * Decrement the refcount, and if 0, call the release function (which was passed
+ * to percpu_ref_init())
+ */
+static inline void percpu_ref_put(struct percpu_ref *ref)
+{
+       unsigned __percpu *pcpu_count;
+
+       rcu_read_lock_sched();
+
+       pcpu_count = ACCESS_ONCE(ref->pcpu_count);
+
+       if (likely(REF_STATUS(pcpu_count) == PCPU_REF_PTR))
+               __this_cpu_dec(*pcpu_count);
+       else if (unlikely(atomic_dec_and_test(&ref->count)))
+               ref->release(ref);
+
+       rcu_read_unlock_sched();
+}
+
+#endif
index c5b6dbf9c2fcd5c90d0b16d2e4e6e330af3ed0b0..8873f82c7baa2bd1ae165966471fd8cad5f0d57b 100644 (file)
@@ -73,13 +73,18 @@ struct perf_raw_record {
  *
  * support for mispred, predicted is optional. In case it
  * is not supported mispred = predicted = 0.
+ *
+ *     in_tx: running in a hardware transaction
+ *     abort: aborting a hardware transaction
  */
 struct perf_branch_entry {
        __u64   from;
        __u64   to;
        __u64   mispred:1,  /* target mispredicted */
                predicted:1,/* target predicted */
-               reserved:62;
+               in_tx:1,    /* in transaction */
+               abort:1,    /* transaction abort */
+               reserved:60;
 };
 
 /*
@@ -113,6 +118,8 @@ struct hw_perf_event_extra {
        int             idx;    /* index in shared_regs->regs[] */
 };
 
+struct event_constraint;
+
 /**
  * struct hw_perf_event - performance event hardware details:
  */
@@ -131,6 +138,8 @@ struct hw_perf_event {
 
                        struct hw_perf_event_extra extra_reg;
                        struct hw_perf_event_extra branch_reg;
+
+                       struct event_constraint *constraint;
                };
                struct { /* software */
                        struct hrtimer  hrtimer;
@@ -188,12 +197,13 @@ struct pmu {
 
        struct device                   *dev;
        const struct attribute_group    **attr_groups;
-       char                            *name;
+       const char                      *name;
        int                             type;
 
        int * __percpu                  pmu_disable_count;
        struct perf_cpu_context * __percpu pmu_cpu_context;
        int                             task_ctx_nr;
+       int                             hrtimer_interval_ms;
 
        /*
         * Fully disable/enable this PMU, can be used to protect from the PMI
@@ -500,8 +510,9 @@ struct perf_cpu_context {
        struct perf_event_context       *task_ctx;
        int                             active_oncpu;
        int                             exclusive;
+       struct hrtimer                  hrtimer;
+       ktime_t                         hrtimer_interval;
        struct list_head                rotation_list;
-       int                             jiffies_interval;
        struct pmu                      *unique_pmu;
        struct perf_cgroup              *cgrp;
 };
@@ -517,7 +528,7 @@ struct perf_output_handle {
 
 #ifdef CONFIG_PERF_EVENTS
 
-extern int perf_pmu_register(struct pmu *pmu, char *name, int type);
+extern int perf_pmu_register(struct pmu *pmu, const char *name, int type);
 extern void perf_pmu_unregister(struct pmu *pmu);
 
 extern int perf_num_counters(void);
@@ -695,10 +706,17 @@ static inline void perf_callchain_store(struct perf_callchain_entry *entry, u64
 extern int sysctl_perf_event_paranoid;
 extern int sysctl_perf_event_mlock;
 extern int sysctl_perf_event_sample_rate;
+extern int sysctl_perf_cpu_time_max_percent;
+
+extern void perf_sample_event_took(u64 sample_len_ns);
 
 extern int perf_proc_update_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos);
+extern int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp,
+               loff_t *ppos);
+
 
 static inline bool perf_paranoid_tracepoint_raw(void)
 {
@@ -742,6 +760,7 @@ extern unsigned int perf_output_skip(struct perf_output_handle *handle,
                                     unsigned int len);
 extern int perf_swevent_get_recursion_context(void);
 extern void perf_swevent_put_recursion_context(int rctx);
+extern u64 perf_swevent_set_period(struct perf_event *event);
 extern void perf_event_enable(struct perf_event *event);
 extern void perf_event_disable(struct perf_event *event);
 extern int __perf_event_disable(void *info);
@@ -781,6 +800,7 @@ static inline void perf_event_fork(struct task_struct *tsk)         { }
 static inline void perf_event_init(void)                               { }
 static inline int  perf_swevent_get_recursion_context(void)            { return -1; }
 static inline void perf_swevent_put_recursion_context(int rctx)                { }
+static inline u64 perf_swevent_set_period(struct perf_event *event)    { return 0; }
 static inline void perf_event_enable(struct perf_event *event)         { }
 static inline void perf_event_disable(struct perf_event *event)                { }
 static inline int __perf_event_disable(void *info)                     { return -1; }
@@ -802,7 +822,7 @@ static inline void perf_restore_debug_store(void)                   { }
 #define perf_output_put(handle, x) perf_output_copy((handle), &(x), sizeof(x))
 
 /*
- * This has to have a higher priority than migration_notifier in sched.c.
+ * This has to have a higher priority than migration_notifier in sched/core.c.
  */
 #define perf_cpu_notifier(fn)                                          \
 do {                                                                   \
index a089a3c447fc1fbe5c56687b316d258c9a7736cf..23705a53abbaad29347a2724f24e80c7f44e9341 100644 (file)
@@ -86,11 +86,9 @@ extern struct task_struct *get_pid_task(struct pid *pid, enum pid_type);
 extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type);
 
 /*
- * attach_pid() and detach_pid() must be called with the tasklist_lock
- * write-held.
+ * these helpers must be called with the tasklist_lock write-held.
  */
-extern void attach_pid(struct task_struct *task, enum pid_type type,
-                       struct pid *pid);
+extern void attach_pid(struct task_struct *task, enum pid_type);
 extern void detach_pid(struct task_struct *task, enum pid_type);
 extern void change_pid(struct task_struct *task, enum pid_type,
                        struct pid *pid);
index 4aad3cea69ae3034f451a0d67b406483d5d7e9e9..18eccefea06e40a0ea10f77e857105c6feaf4ff9 100644 (file)
@@ -40,6 +40,25 @@ extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
 extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
 extern void devm_pinctrl_put(struct pinctrl *p);
 
+#ifdef CONFIG_PM
+extern int pinctrl_pm_select_default_state(struct device *dev);
+extern int pinctrl_pm_select_sleep_state(struct device *dev);
+extern int pinctrl_pm_select_idle_state(struct device *dev);
+#else
+static inline int pinctrl_pm_select_default_state(struct device *dev)
+{
+       return 0;
+}
+static inline int pinctrl_pm_select_sleep_state(struct device *dev)
+{
+       return 0;
+}
+static inline int pinctrl_pm_select_idle_state(struct device *dev)
+{
+       return 0;
+}
+#endif
+
 #else /* !CONFIG_PINCTRL */
 
 static inline int pinctrl_request_gpio(unsigned gpio)
@@ -92,6 +111,21 @@ static inline void devm_pinctrl_put(struct pinctrl *p)
 {
 }
 
+static inline int pinctrl_pm_select_default_state(struct device *dev)
+{
+       return 0;
+}
+
+static inline int pinctrl_pm_select_sleep_state(struct device *dev)
+{
+       return 0;
+}
+
+static inline int pinctrl_pm_select_idle_state(struct device *dev)
+{
+       return 0;
+}
+
 #endif /* CONFIG_PINCTRL */
 
 static inline struct pinctrl * __must_check pinctrl_get_select(
@@ -158,47 +192,4 @@ static inline struct pinctrl * __must_check devm_pinctrl_get_select_default(
        return devm_pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
 }
 
-#ifdef CONFIG_PINCONF
-
-extern int pin_config_get(const char *dev_name, const char *name,
-                         unsigned long *config);
-extern int pin_config_set(const char *dev_name, const char *name,
-                         unsigned long config);
-extern int pin_config_group_get(const char *dev_name,
-                               const char *pin_group,
-                               unsigned long *config);
-extern int pin_config_group_set(const char *dev_name,
-                               const char *pin_group,
-                               unsigned long config);
-
-#else
-
-static inline int pin_config_get(const char *dev_name, const char *name,
-                                unsigned long *config)
-{
-       return 0;
-}
-
-static inline int pin_config_set(const char *dev_name, const char *name,
-                                unsigned long config)
-{
-       return 0;
-}
-
-static inline int pin_config_group_get(const char *dev_name,
-                                      const char *pin_group,
-                                      unsigned long *config)
-{
-       return 0;
-}
-
-static inline int pin_config_group_set(const char *dev_name,
-                                      const char *pin_group,
-                                      unsigned long config)
-{
-       return 0;
-}
-
-#endif
-
 #endif /* __LINUX_PINCTRL_CONSUMER_H */
index 6e5f8a985ea7ddf6690679c5908b348d863ac735..281cb91ddcf54c3a5275acbbc30abd9f0e9d11b1 100644 (file)
 struct dev_pin_info {
        struct pinctrl *p;
        struct pinctrl_state *default_state;
+#ifdef CONFIG_PM
+       struct pinctrl_state *sleep_state;
+       struct pinctrl_state *idle_state;
+#endif
 };
 
 extern int pinctrl_bind_pins(struct device *dev);
index 6aa238096622441de2125f3a7658fe2777f349a1..bf7e989abcb5f51d94cac4bd999622b7f38d8813 100644 (file)
  *     if for example some other pin is going to drive the signal connected
  *     to it for a while. Pins used for input are usually always high
  *     impedance.
+ * @PIN_CONFIG_BIAS_BUS_HOLD: the pin will be set to weakly latch so that it
+ *     weakly drives the last value on a tristate bus, also known as a "bus
+ *     holder", "bus keeper" or "repeater". This allows another device on the
+ *     bus to change the value by driving the bus high or low and switching to
+ *     tristate. The argument is ignored.
  * @PIN_CONFIG_BIAS_PULL_UP: the pin will be pulled up (usually with high
  *     impedance to VDD). If the argument is != 0 pull-up is enabled,
- *     if it is 0, pull-up is disabled.
+ *     if it is 0, pull-up is total, i.e. the pin is connected to VDD.
  * @PIN_CONFIG_BIAS_PULL_DOWN: the pin will be pulled down (usually with high
  *     impedance to GROUND). If the argument is != 0 pull-down is enabled,
- *     if it is 0, pull-down is disabled.
+ *     if it is 0, pull-down is total, i.e. the pin is connected to GROUND.
+ * @PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: the pin will be pulled up or down based
+ *     on embedded knowledge of the controller hardware, like current mux
+ *     function. The pull direction and possibly strength too will normally
+ *     be decided completely inside the hardware block and not be readable
+ *     from the kernel side.
+ *     If the argument is != 0 pull up/down is enabled, if it is 0, the
+ *     configuration is ignored. The proper way to disable it is to use
+ *     @PIN_CONFIG_BIAS_DISABLE.
  * @PIN_CONFIG_DRIVE_PUSH_PULL: the pin will be driven actively high and
  *     low, this is the most typical case and is typically achieved with two
  *     active transistors on the output. Setting this config will enable
  *     setting pins to this mode.
  * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode,
  *     which means it will wait for signals to settle when reading inputs. The
- *     argument gives the debounce time on a custom format. Setting the
+ *     argument gives the debounce time in usecs. Setting the
  *     argument to zero turns debouncing off.
  * @PIN_CONFIG_POWER_SOURCE: if the pin can select between different power
  *     supplies, the argument to this parameter (on a custom format) tells
  *     the driver which alternative power source to use.
  * @PIN_CONFIG_SLEW_RATE: if the pin can select slew rate, the argument to
- *     this parameter (on a custom format) tells the driver which alternative
- *     slew rate to use.
+ *     this parameter (on a custom format) tells the driver which alternative
+ *     slew rate to use.
  * @PIN_CONFIG_LOW_POWER_MODE: this will configure the pin for low power
  *     operation, if several modes of operation are supported these can be
  *     passed in the argument on a custom form, else just use argument 1
 enum pin_config_param {
        PIN_CONFIG_BIAS_DISABLE,
        PIN_CONFIG_BIAS_HIGH_IMPEDANCE,
+       PIN_CONFIG_BIAS_BUS_HOLD,
        PIN_CONFIG_BIAS_PULL_UP,
        PIN_CONFIG_BIAS_PULL_DOWN,
+       PIN_CONFIG_BIAS_PULL_PIN_DEFAULT,
        PIN_CONFIG_DRIVE_PUSH_PULL,
        PIN_CONFIG_DRIVE_OPEN_DRAIN,
        PIN_CONFIG_DRIVE_OPEN_SOURCE,
index 1ad4f31ef6b8e2074546443465338b8f04b04e69..f6998692bdc931fb6c1935baf5796ed43d0f132c 100644 (file)
@@ -30,7 +30,7 @@ struct seq_file;
  * @pin_config_set: configure an individual pin
  * @pin_config_group_get: get configurations for an entire pin group
  * @pin_config_group_set: configure all pins in a group
- * @pin_config_group_dbg_set: optional debugfs to modify a pin configuration
+ * @pin_config_dbg_parse_modify: optional debugfs to modify a pin configuration
  * @pin_config_dbg_show: optional debugfs display hook that will provide
  *     per-device info for a certain pin in debugfs
  * @pin_config_group_dbg_show: optional debugfs display hook that will provide
index 2c2a9e8d8578310e453776e6668e9b6a915ac2c2..5979147d2bda99587e07cc52e1fc4f0f3fd771f0 100644 (file)
@@ -49,7 +49,8 @@ struct pinctrl_pin_desc {
  * @name: a name for the chip in this range
  * @id: an ID number for the chip in this range
  * @base: base offset of the GPIO range
- * @pin_base: base pin number of the GPIO range
+ * @pin_base: base pin number of the GPIO range if pins == NULL
+ * @pins: enumeration of pins in GPIO range or NULL
  * @npins: number of pins in the GPIO range, including the base number
  * @gc: an optional pointer to a gpio_chip
  */
@@ -59,6 +60,7 @@ struct pinctrl_gpio_range {
        unsigned int id;
        unsigned int base;
        unsigned int pin_base;
+       unsigned const *pins;
        unsigned int npins;
        struct gpio_chip *gc;
 };
index 320d9c39ea0a17fb98d127ebd71a20741cb1754a..9d98f3aaa16c7637b42a8de33530aab4df9137ac 100644 (file)
@@ -12,7 +12,9 @@
 
 void u8500_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
                    u32 clkrst5_base, u32 clkrst6_base);
-void u9540_clk_init(void);
-void u8540_clk_init(void);
+void u9540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
+                   u32 clkrst5_base, u32 clkrst6_base);
+void u8540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
+                   u32 clkrst5_base, u32 clkrst6_base);
 
 #endif /* __CLK_UX500_H */
diff --git a/include/linux/platform_data/g762.h b/include/linux/platform_data/g762.h
new file mode 100644 (file)
index 0000000..d3c5128
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Platform data structure for g762 fan controller driver
+ *
+ * Copyright (C) 2013, Arnaud EBALARD <arno@natisbad.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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __LINUX_PLATFORM_DATA_G762_H__
+#define __LINUX_PLATFORM_DATA_G762_H__
+
+/*
+ * Following structure can be used to set g762 driver platform specific data
+ * during board init. Note that passing a sparse structure is possible but
+ * will result in non-specified attributes to be set to default value, hence
+ * overloading those installed during boot (e.g. by u-boot).
+ */
+
+struct g762_platform_data {
+       u32 fan_startv;
+       u32 fan_gear_mode;
+       u32 pwm_polarity;
+       u32 clk_freq;
+};
+
+#endif /* __LINUX_PLATFORM_DATA_G762_H__ */
index 92dabcaf6499eec2e8226c1b54df136feb80986a..54334393ab926ada9935fa5aba6e1a3756b27a88 100644 (file)
@@ -78,6 +78,23 @@ enum si5351_drive_strength {
        SI5351_DRIVE_8MA = 8,
 };
 
+/**
+ * enum si5351_disable_state - Si5351 clock output disable state
+ * @SI5351_DISABLE_DEFAULT: default, do not change eeprom config
+ * @SI5351_DISABLE_LOW: CLKx is set to a LOW state when disabled
+ * @SI5351_DISABLE_HIGH: CLKx is set to a HIGH state when disabled
+ * @SI5351_DISABLE_FLOATING: CLKx is set to a FLOATING state when
+ *                             disabled
+ * @SI5351_DISABLE_NEVER: CLKx is NEVER disabled
+ */
+enum si5351_disable_state {
+       SI5351_DISABLE_DEFAULT = 0,
+       SI5351_DISABLE_LOW,
+       SI5351_DISABLE_HIGH,
+       SI5351_DISABLE_FLOATING,
+       SI5351_DISABLE_NEVER,
+};
+
 /**
  * struct si5351_clkout_config - Si5351 clock output configuration
  * @clkout: clkout number
@@ -91,6 +108,7 @@ struct si5351_clkout_config {
        enum si5351_multisynth_src multisynth_src;
        enum si5351_clkout_src clkout_src;
        enum si5351_drive_strength drive;
+       enum si5351_disable_state disable_state;
        bool pll_master;
        unsigned long rate;
 };
diff --git a/include/linux/platform_data/ssm2518.h b/include/linux/platform_data/ssm2518.h
new file mode 100644 (file)
index 0000000..9a8e3ea
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * SSM2518 amplifier audio driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_SSM2518_H__
+#define __LINUX_PLATFORM_DATA_SSM2518_H__
+
+/**
+ * struct ssm2518_platform_data - Platform data for the ssm2518 driver
+ * @enable_gpio: GPIO connected to the nSD pin. Set to -1 if the nSD pin is
+ *            hardwired.
+ */
+struct ssm2518_platform_data {
+       int enable_gpio;
+};
+
+#endif
index 7d7e09efff9b9eea0f29ce8fc37cbcdf0268e6f8..6fa7cea25da9afde1ffac4668c30f85d711a0fc0 100644 (file)
@@ -37,7 +37,6 @@ extern void pm_runtime_enable(struct device *dev);
 extern void __pm_runtime_disable(struct device *dev, bool check_resume);
 extern void pm_runtime_allow(struct device *dev);
 extern void pm_runtime_forbid(struct device *dev);
-extern int pm_generic_runtime_idle(struct device *dev);
 extern int pm_generic_runtime_suspend(struct device *dev);
 extern int pm_generic_runtime_resume(struct device *dev);
 extern void pm_runtime_no_callbacks(struct device *dev);
@@ -143,7 +142,6 @@ static inline bool pm_runtime_active(struct device *dev) { return true; }
 static inline bool pm_runtime_status_suspended(struct device *dev) { return false; }
 static inline bool pm_runtime_enabled(struct device *dev) { return false; }
 
-static inline int pm_generic_runtime_idle(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
 static inline void pm_runtime_no_callbacks(struct device *dev) {}
index c0f44c2b006da4ae05e4c55e7ed322fb50c581fd..d8b187c3925ddae170810cd7bf070c2a4b2ffbff 100644 (file)
@@ -299,11 +299,11 @@ void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
 void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data);
 
 /* Smartreflex driver hooks to be called from Smartreflex class driver */
-int sr_enable(struct voltagedomain *voltdm, unsigned long volt);
-void sr_disable(struct voltagedomain *voltdm);
-int sr_configure_errgen(struct voltagedomain *voltdm);
-int sr_disable_errgen(struct voltagedomain *voltdm);
-int sr_configure_minmax(struct voltagedomain *voltdm);
+int sr_enable(struct omap_sr *sr, unsigned long volt);
+void sr_disable(struct omap_sr *sr);
+int sr_configure_errgen(struct omap_sr *sr);
+int sr_disable_errgen(struct omap_sr *sr);
+int sr_configure_minmax(struct omap_sr *sr);
 
 /* API to register the smartreflex class driver with the smartreflex driver */
 int sr_register_class(struct omap_sr_class_data *class_data);
index ddcc7826d9075dba200be0cd96aaef77afb9a74e..4b14bdc911d7854163932672ad376ab615de7be4 100644 (file)
@@ -216,6 +216,7 @@ static inline int rcu_preempt_depth(void)
 #endif /* #else #ifdef CONFIG_PREEMPT_RCU */
 
 /* Internal to kernel */
+extern void rcu_init(void);
 extern void rcu_sched_qs(int cpu);
 extern void rcu_bh_qs(int cpu);
 extern void rcu_check_callbacks(int cpu, int user);
@@ -239,8 +240,6 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev,
                                         struct task_struct *next) { }
 #endif /* CONFIG_RCU_USER_QS */
 
-extern void exit_rcu(void);
-
 /**
  * RCU_NONIDLE - Indicate idle-loop code that needs RCU readers
  * @a: Code that RCU needs to pay attention to.
@@ -277,7 +276,7 @@ void wait_rcu_gp(call_rcu_func_t crf);
 
 #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
 #include <linux/rcutree.h>
-#elif defined(CONFIG_TINY_RCU) || defined(CONFIG_TINY_PREEMPT_RCU)
+#elif defined(CONFIG_TINY_RCU)
 #include <linux/rcutiny.h>
 #else
 #error "Unknown RCU implementation specified to kernel configuration"
index 4e56a9c69a356ca73fcd06cf775f337276f77f2e..e31005ee339ebde022bd7dabace245ee79474d9b 100644 (file)
 
 #include <linux/cache.h>
 
-static inline void rcu_init(void)
-{
-}
-
 static inline void rcu_barrier_bh(void)
 {
        wait_rcu_gp(call_rcu_bh);
@@ -41,8 +37,6 @@ static inline void rcu_barrier_sched(void)
        wait_rcu_gp(call_rcu_sched);
 }
 
-#ifdef CONFIG_TINY_RCU
-
 static inline void synchronize_rcu_expedited(void)
 {
        synchronize_sched();    /* Only one CPU, so pretty fast anyway!!! */
@@ -53,17 +47,6 @@ static inline void rcu_barrier(void)
        rcu_barrier_sched();  /* Only one CPU, so only one list of callbacks! */
 }
 
-#else /* #ifdef CONFIG_TINY_RCU */
-
-void synchronize_rcu_expedited(void);
-
-static inline void rcu_barrier(void)
-{
-       wait_rcu_gp(call_rcu);
-}
-
-#endif /* #else #ifdef CONFIG_TINY_RCU */
-
 static inline void synchronize_rcu_bh(void)
 {
        synchronize_sched();
@@ -85,35 +68,15 @@ static inline void kfree_call_rcu(struct rcu_head *head,
        call_rcu(head, func);
 }
 
-#ifdef CONFIG_TINY_RCU
-
-static inline void rcu_preempt_note_context_switch(void)
-{
-}
-
 static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
 {
        *delta_jiffies = ULONG_MAX;
        return 0;
 }
 
-#else /* #ifdef CONFIG_TINY_RCU */
-
-void rcu_preempt_note_context_switch(void);
-int rcu_preempt_needs_cpu(void);
-
-static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
-{
-       *delta_jiffies = ULONG_MAX;
-       return rcu_preempt_needs_cpu();
-}
-
-#endif /* #else #ifdef CONFIG_TINY_RCU */
-
 static inline void rcu_note_context_switch(int cpu)
 {
        rcu_sched_qs(cpu);
-       rcu_preempt_note_context_switch();
 }
 
 /*
@@ -156,6 +119,10 @@ static inline void rcu_cpu_stall_reset(void)
 {
 }
 
+static inline void exit_rcu(void)
+{
+}
+
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 extern int rcu_scheduler_active __read_mostly;
 extern void rcu_scheduler_starting(void);
index 952b793393045d63b5f0f78c9f459ba4ad81a2f4..226169d1bd2bc07fa465d9c4b4b21cf8131de162 100644 (file)
@@ -30,7 +30,6 @@
 #ifndef __LINUX_RCUTREE_H
 #define __LINUX_RCUTREE_H
 
-extern void rcu_init(void);
 extern void rcu_note_context_switch(int cpu);
 extern int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies);
 extern void rcu_cpu_stall_reset(void);
@@ -86,6 +85,8 @@ extern void rcu_force_quiescent_state(void);
 extern void rcu_bh_force_quiescent_state(void);
 extern void rcu_sched_force_quiescent_state(void);
 
+extern void exit_rcu(void);
+
 extern void rcu_scheduler_starting(void);
 extern int rcu_scheduler_active __read_mostly;
 
index 02d84e24b7c2083ff1a4ddf13a1b2ac7ad663261..75981d0b57dccd4b6a3b5e9833557973f33d9404 100644 (file)
@@ -23,6 +23,7 @@ struct irq_domain;
 struct spi_device;
 struct regmap;
 struct regmap_range_cfg;
+struct regmap_field;
 
 /* An enum of all the supported cache types */
 enum regcache_type {
@@ -394,10 +395,15 @@ bool regmap_can_raw_write(struct regmap *map);
 int regcache_sync(struct regmap *map);
 int regcache_sync_region(struct regmap *map, unsigned int min,
                         unsigned int max);
+int regcache_drop_region(struct regmap *map, unsigned int min,
+                        unsigned int max);
 void regcache_cache_only(struct regmap *map, bool enable);
 void regcache_cache_bypass(struct regmap *map, bool enable);
 void regcache_mark_dirty(struct regmap *map);
 
+bool regmap_check_range_table(struct regmap *map, unsigned int reg,
+                             const struct regmap_access_table *table);
+
 int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
                          int num_regs);
 
@@ -411,6 +417,36 @@ bool regmap_reg_in_ranges(unsigned int reg,
                          const struct regmap_range *ranges,
                          unsigned int nranges);
 
+/**
+ * Description of an register field
+ *
+ * @reg: Offset of the register within the regmap bank
+ * @lsb: lsb of the register field.
+ * @reg: msb of the register field.
+ */
+struct reg_field {
+       unsigned int reg;
+       unsigned int lsb;
+       unsigned int msb;
+};
+
+#define REG_FIELD(_reg, _lsb, _msb) {          \
+                               .reg = _reg,    \
+                               .lsb = _lsb,    \
+                               .msb = _msb,    \
+                               }
+
+struct regmap_field *regmap_field_alloc(struct regmap *regmap,
+               struct reg_field reg_field);
+void regmap_field_free(struct regmap_field *field);
+
+struct regmap_field *devm_regmap_field_alloc(struct device *dev,
+               struct regmap *regmap, struct reg_field reg_field);
+void devm_regmap_field_free(struct device *dev,        struct regmap_field *field);
+
+int regmap_field_read(struct regmap_field *field, unsigned int *val);
+int regmap_field_write(struct regmap_field *field, unsigned int val);
+
 /**
  * Description of an IRQ for the generic regmap irq_chip.
  *
@@ -562,6 +598,13 @@ static inline int regcache_sync_region(struct regmap *map, unsigned int min,
        return -EINVAL;
 }
 
+static inline int regcache_drop_region(struct regmap *map, unsigned int min,
+                                      unsigned int max)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
 static inline void regcache_cache_only(struct regmap *map, bool enable)
 {
        WARN_ONCE(1, "regmap API is disabled");
index 7c5ff0c55773c41b076216d80aa5d26e59fae61e..75307447cef966eb3d168de7542c84181c849d63 100644 (file)
@@ -336,8 +336,4 @@ static inline int ab8500_regulator_debug_exit(struct platform_device *pdev)
 }
 #endif
 
-/* AB8500 external regulator functions. */
-int ab8500_ext_regulator_init(struct platform_device *pdev);
-void ab8500_ext_regulator_exit(struct platform_device *pdev);
-
 #endif
index 145022a830857a5af55d63562c9da980eb2498f9..3a76389c6aaa6989900247712c8ffe33658b33db 100644 (file)
@@ -165,6 +165,7 @@ int regulator_count_voltages(struct regulator *regulator);
 int regulator_list_voltage(struct regulator *regulator, unsigned selector);
 int regulator_is_supported_voltage(struct regulator *regulator,
                                   int min_uV, int max_uV);
+unsigned int regulator_get_linear_step(struct regulator *regulator);
 int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
 int regulator_set_voltage_time(struct regulator *regulator,
                               int old_uV, int new_uV);
index 18e099342e6f82732a93b347b021ca7aa4e2b22d..b71d5738e68345345bc1580abae26b2d8e582048 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/errno.h>
 #include <linux/device.h>
 #include <linux/rio_regs.h>
+#include <linux/mod_devicetable.h>
 #ifdef CONFIG_RAPIDIO_DMA_ENGINE
 #include <linux/dmaengine.h>
 #endif
@@ -91,9 +92,24 @@ union rio_pw_msg;
 /**
  * struct rio_switch - RIO switch info
  * @node: Node in global list of switches
- * @switchid: Switch ID that is unique across a network
  * @route_table: Copy of switch routing table
  * @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0
+ * @ops: pointer to switch-specific operations
+ * @lock: lock to serialize operations updates
+ * @nextdev: Array of per-port pointers to the next attached device
+ */
+struct rio_switch {
+       struct list_head node;
+       u8 *route_table;
+       u32 port_ok;
+       struct rio_switch_ops *ops;
+       spinlock_t lock;
+       struct rio_dev *nextdev[0];
+};
+
+/**
+ * struct rio_switch_ops - Per-switch operations
+ * @owner: The module owner of this structure
  * @add_entry: Callback for switch-specific route add function
  * @get_entry: Callback for switch-specific route get function
  * @clr_table: Callback for switch-specific clear route table function
@@ -101,14 +117,12 @@ union rio_pw_msg;
  * @get_domain: Callback for switch-specific domain get function
  * @em_init: Callback for switch-specific error management init function
  * @em_handle: Callback for switch-specific error management handler function
- * @sw_sysfs: Callback that initializes switch-specific sysfs attributes
- * @nextdev: Array of per-port pointers to the next attached device
+ *
+ * Defines the operations that are necessary to initialize/control
+ * a particular RIO switch device.
  */
-struct rio_switch {
-       struct list_head node;
-       u16 switchid;
-       u8 *route_table;
-       u32 port_ok;
+struct rio_switch_ops {
+       struct module *owner;
        int (*add_entry) (struct rio_mport *mport, u16 destid, u8 hopcount,
                          u16 table, u16 route_destid, u8 route_port);
        int (*get_entry) (struct rio_mport *mport, u16 destid, u8 hopcount,
@@ -121,8 +135,6 @@ struct rio_switch {
                           u8 *sw_domain);
        int (*em_init) (struct rio_dev *dev);
        int (*em_handle) (struct rio_dev *dev, u8 swport);
-       int (*sw_sysfs) (struct rio_dev *dev, int create);
-       struct rio_dev *nextdev[0];
 };
 
 /**
@@ -130,6 +142,7 @@ struct rio_switch {
  * @global_list: Node in list of all RIO devices
  * @net_list: Node in list of RIO devices in a network
  * @net: Network this device is a part of
+ * @do_enum: Enumeration flag
  * @did: Device ID
  * @vid: Vendor ID
  * @device_rev: Device revision
@@ -158,6 +171,7 @@ struct rio_dev {
        struct list_head global_list;   /* node in list of all RIO devices */
        struct list_head net_list;      /* node in per net list */
        struct rio_net *net;    /* RIO net this device resides in */
+       bool do_enum;
        u16 did;
        u16 vid;
        u32 device_rev;
@@ -297,10 +311,6 @@ struct rio_net {
        struct rio_id_table destid_table;  /* destID allocation table */
 };
 
-/* Definitions used by switch sysfs initialization callback */
-#define RIO_SW_SYSFS_CREATE    1       /* Create switch attributes */
-#define RIO_SW_SYSFS_REMOVE    0       /* Remove switch attributes */
-
 /* Low-level architecture-dependent routines */
 
 /**
@@ -385,35 +395,6 @@ struct rio_driver {
 
 #define        to_rio_driver(drv) container_of(drv,struct rio_driver, driver)
 
-/**
- * struct rio_device_id - RIO device identifier
- * @did: RIO device ID
- * @vid: RIO vendor ID
- * @asm_did: RIO assembly device ID
- * @asm_vid: RIO assembly vendor ID
- *
- * Identifies a RIO device based on both the device/vendor IDs and
- * the assembly device/vendor IDs.
- */
-struct rio_device_id {
-       u16 did, vid;
-       u16 asm_did, asm_vid;
-};
-
-/**
- * struct rio_switch_ops - Per-switch operations
- * @vid: RIO vendor ID
- * @did: RIO device ID
- * @init_hook: Callback that performs switch device initialization
- *
- * Defines the operations that are necessary to initialize/control
- * a particular RIO switch device.
- */
-struct rio_switch_ops {
-       u16 vid, did;
-       int (*init_hook) (struct rio_dev *rdev, int do_enum);
-};
-
 union rio_pw_msg {
        struct {
                u32 comptag;    /* Component Tag CSR */
@@ -468,14 +449,29 @@ static inline struct rio_mport *dma_to_mport(struct dma_device *ddev)
 
 /**
  * struct rio_scan - RIO enumeration and discovery operations
+ * @owner: The module owner of this structure
  * @enumerate: Callback to perform RapidIO fabric enumeration.
  * @discover: Callback to perform RapidIO fabric discovery.
  */
 struct rio_scan {
+       struct module *owner;
        int (*enumerate)(struct rio_mport *mport, u32 flags);
        int (*discover)(struct rio_mport *mport, u32 flags);
 };
 
+/**
+ * struct rio_scan_node - list node to register RapidIO enumeration and
+ * discovery methods with RapidIO core.
+ * @mport_id: ID of an mport (net) serviced by this enumerator
+ * @node: node in global list of registered enumerators
+ * @ops: RIO enumeration and discovery operations
+ */
+struct rio_scan_node {
+       int mport_id;
+       struct list_head node;
+       struct rio_scan *ops;
+};
+
 /* Architecture and hardware-specific functions */
 extern int rio_register_mport(struct rio_mport *);
 extern int rio_open_inb_mbox(struct rio_mport *, void *, int, int);
index b66d13d1bdc04199a78665022f676e238960fa74..2543bc163d5434e0f6c42689456e747055da35d7 100644 (file)
@@ -13,8 +13,6 @@
 #ifndef LINUX_RIO_IDS_H
 #define LINUX_RIO_IDS_H
 
-#define RIO_ANY_ID                     0xffff
-
 #define RIO_VID_FREESCALE              0x0002
 #define RIO_DID_MPC8560                        0x0003
 
index 178a8d909f14a3dcdcbc0ce255572975c8b3b221..cdd5407b37e27ea14fdabad7becf8607a7d0e976 100644 (file)
@@ -924,7 +924,7 @@ struct load_weight {
 struct sched_avg {
        /*
         * These sums represent an infinite geometric series and so are bound
-        * above by 1024/(1-y).  Thus we only need a u32 to store them for for all
+        * above by 1024/(1-y).  Thus we only need a u32 to store them for all
         * choices of y < 1-2^(-32)*1024.
         */
        u32 runnable_avg_sum, runnable_avg_period;
@@ -994,12 +994,7 @@ struct sched_entity {
        struct cfs_rq           *my_q;
 #endif
 
-/*
- * Load-tracking only depends on SMP, FAIR_GROUP_SCHED dependency below may be
- * removed when useful for applications beyond shares distribution (e.g.
- * load-balance).
- */
-#if defined(CONFIG_SMP) && defined(CONFIG_FAIR_GROUP_SCHED)
+#ifdef CONFIG_SMP
        /* Per-entity load-tracking */
        struct sched_avg        avg;
 #endif
@@ -1955,8 +1950,6 @@ extern struct task_struct *find_task_by_vpid(pid_t nr);
 extern struct task_struct *find_task_by_pid_ns(pid_t nr,
                struct pid_namespace *ns);
 
-extern void __set_special_pids(struct pid *pid);
-
 /* per-UID process charging. */
 extern struct user_struct * alloc_uid(kuid_t);
 static inline struct user_struct *get_uid(struct user_struct *u)
index 4686491852a70b0665633ee1bce5e44d344b3aa3..40560f41e3d540d7e4a7259faa7fa0e8a5176c57 100644 (file)
@@ -1392,7 +1392,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @ctxlen contains the length of @ctx.
  *
  * @inode_getsecctx:
- *     Returns a string containing all relevant security context information
+ *     On success, returns 0 and fills out @ctx and @ctxlen with the security
+ *     context for the given @inode.
  *
  *     @inode we wish to get the security context of.
  *     @ctx is a pointer in which to place the allocated security context.
index c8488763277f0066bb731f019964f038f4107b57..c181399f2c20e3a7ffedd868c20803c87843e2bf 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/list.h>
 #include <linux/cpumask.h>
 #include <linux/init.h>
-#include <linux/irqflags.h>
 
 extern void cpu_idle(void);
 
@@ -140,17 +139,14 @@ static inline int up_smp_call_function(smp_call_func_t func, void *info)
 }
 #define smp_call_function(func, info, wait) \
                        (up_smp_call_function(func, info))
-
-static inline int on_each_cpu(smp_call_func_t func, void *info, int wait)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       func(info);
-       local_irq_restore(flags);
-       return 0;
-}
-
+#define on_each_cpu(func, info, wait)          \
+       ({                                      \
+               unsigned long __flags;          \
+               local_irq_save(__flags);        \
+               func(info);                     \
+               local_irq_restore(__flags);     \
+               0;                              \
+       })
 /*
  * Note we still need to test the mask even for UP
  * because we actually can get an empty mask from
index 6ff26c8db7b923853527cee3ee1ffff1ca55bdd6..28e440be1c07aafaa4ac62470344b052f9107d8f 100644 (file)
@@ -308,6 +308,9 @@ struct spi_master {
 
        /* bitmask of supported bits_per_word for transfers */
        u32                     bits_per_word_mask;
+#define SPI_BPW_MASK(bits) BIT((bits) - 1)
+#define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0UL : (BIT(bits) - 1))
+#define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1))
 
        /* other constraints relevant to this driver */
        u16                     flags;
index 6f17278810b05f29544b2c2f21ed081b776b577f..333ecdfee0d9f13c0c630b857a4c67c1f503512f 100644 (file)
@@ -11,7 +11,6 @@
  */
 struct xspi_platform_data {
        u16 num_chipselect;
-       bool little_endian;
        u8 bits_per_word;
        struct spi_board_info *devices;
        u8 num_devices;
index e2369c167dbd9e7300ecbf617cbc9d8f291c8dc0..8b3ac0d718ebd7fd80987f6ede10725358102e1d 100644 (file)
@@ -67,7 +67,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
 #else /* DEBUG_SPINLOCK */
 #define arch_spin_is_locked(lock)      ((void)(lock), 0)
-/* for sched.c and kernel_lock.c: */
+/* for sched/core.c and kernel_lock.c: */
 # define arch_spin_lock(lock)          do { barrier(); (void)(lock); } while (0)
 # define arch_spin_lock_flags(lock, flags)     do { barrier(); (void)(lock); } while (0)
 # define arch_spin_unlock(lock)        do { barrier(); (void)(lock); } while (0)
index 04f4121a23ae2b6f5854bf35e7678cd9f93fe991..c114614ed172fdbb02b70fde61d6838f4734bfb4 100644 (file)
@@ -237,47 +237,4 @@ static inline void srcu_read_unlock(struct srcu_struct *sp, int idx)
        __srcu_read_unlock(sp, idx);
 }
 
-/**
- * srcu_read_lock_raw - register a new reader for an SRCU-protected structure.
- * @sp: srcu_struct in which to register the new reader.
- *
- * Enter an SRCU read-side critical section.  Similar to srcu_read_lock(),
- * but avoids the RCU-lockdep checking.  This means that it is legal to
- * use srcu_read_lock_raw() in one context, for example, in an exception
- * handler, and then have the matching srcu_read_unlock_raw() in another
- * context, for example in the task that took the exception.
- *
- * However, the entire SRCU read-side critical section must reside within a
- * single task.  For example, beware of using srcu_read_lock_raw() in
- * a device interrupt handler and srcu_read_unlock() in the interrupted
- * task:  This will not work if interrupts are threaded.
- */
-static inline int srcu_read_lock_raw(struct srcu_struct *sp)
-{
-       unsigned long flags;
-       int ret;
-
-       local_irq_save(flags);
-       ret =  __srcu_read_lock(sp);
-       local_irq_restore(flags);
-       return ret;
-}
-
-/**
- * srcu_read_unlock_raw - unregister reader from an SRCU-protected structure.
- * @sp: srcu_struct in which to unregister the old reader.
- * @idx: return value from corresponding srcu_read_lock_raw().
- *
- * Exit an SRCU read-side critical section without lockdep-RCU checking.
- * See srcu_read_lock_raw() for more details.
- */
-static inline void srcu_read_unlock_raw(struct srcu_struct *sp, int idx)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       __srcu_read_unlock(sp, idx);
-       local_irq_restore(flags);
-}
-
 #endif
index d4e3f16d5e8932c56e059d906add432cf88c8dbc..f73cabf59012f1ead45eee1eb7aa97600b1bb902 100644 (file)
@@ -363,6 +363,7 @@ extern bool pm_wakeup_pending(void);
 extern bool pm_get_wakeup_count(unsigned int *count, bool block);
 extern bool pm_save_wakeup_count(unsigned int count);
 extern void pm_wakep_autosleep_enabled(bool set);
+extern void pm_print_active_wakeup_sources(void);
 
 static inline void lock_system_sleep(void)
 {
index 1701ce4be746502e89b6dfb417547c1ba805d466..d95cde5e257d9d23c71190109ba97d373668ebf9 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/node.h>
 #include <linux/fs.h>
 #include <linux/atomic.h>
+#include <linux/page-flags.h>
 #include <asm/page.h>
 
 struct notifier_block;
@@ -19,10 +20,13 @@ struct bio;
 #define SWAP_FLAG_PREFER       0x8000  /* set if swap priority specified */
 #define SWAP_FLAG_PRIO_MASK    0x7fff
 #define SWAP_FLAG_PRIO_SHIFT   0
-#define SWAP_FLAG_DISCARD      0x10000 /* discard swap cluster after use */
+#define SWAP_FLAG_DISCARD      0x10000 /* enable discard for swap */
+#define SWAP_FLAG_DISCARD_ONCE 0x20000 /* discard swap area at swapon-time */
+#define SWAP_FLAG_DISCARD_PAGES 0x40000 /* discard page-clusters after use */
 
 #define SWAP_FLAGS_VALID       (SWAP_FLAG_PRIO_MASK | SWAP_FLAG_PREFER | \
-                                SWAP_FLAG_DISCARD)
+                                SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE | \
+                                SWAP_FLAG_DISCARD_PAGES)
 
 static inline int current_is_kswapd(void)
 {
@@ -146,14 +150,16 @@ struct swap_extent {
 enum {
        SWP_USED        = (1 << 0),     /* is slot in swap_info[] used? */
        SWP_WRITEOK     = (1 << 1),     /* ok to write to this swap?    */
-       SWP_DISCARDABLE = (1 << 2),     /* swapon+blkdev support discard */
+       SWP_DISCARDABLE = (1 << 2),     /* blkdev support discard */
        SWP_DISCARDING  = (1 << 3),     /* now discarding a free cluster */
        SWP_SOLIDSTATE  = (1 << 4),     /* blkdev seeks are cheap */
        SWP_CONTINUED   = (1 << 5),     /* swap_map has count continuation */
        SWP_BLKDEV      = (1 << 6),     /* its a block device */
        SWP_FILE        = (1 << 7),     /* set after swap_activate success */
+       SWP_AREA_DISCARD = (1 << 8),    /* single-time swap area discards */
+       SWP_PAGE_DISCARD = (1 << 9),    /* freed swap page-cluster discards */
                                        /* add others here before... */
-       SWP_SCANNING    = (1 << 8),     /* refcount in scan_swap_map */
+       SWP_SCANNING    = (1 << 10),    /* refcount in scan_swap_map */
 };
 
 #define SWAP_CLUSTER_MAX 32UL
@@ -233,8 +239,8 @@ extern unsigned long nr_free_pagecache_pages(void);
 
 
 /* linux/mm/swap.c */
-extern void __lru_cache_add(struct page *, enum lru_list lru);
-extern void lru_cache_add_lru(struct page *, enum lru_list lru);
+extern void __lru_cache_add(struct page *);
+extern void lru_cache_add(struct page *);
 extern void lru_add_page_tail(struct page *page, struct page *page_tail,
                         struct lruvec *lruvec, struct list_head *head);
 extern void activate_page(struct page *);
@@ -254,12 +260,14 @@ extern void add_page_to_unevictable_list(struct page *page);
  */
 static inline void lru_cache_add_anon(struct page *page)
 {
-       __lru_cache_add(page, LRU_INACTIVE_ANON);
+       ClearPageActive(page);
+       __lru_cache_add(page);
 }
 
 static inline void lru_cache_add_file(struct page *page)
 {
-       __lru_cache_add(page, LRU_INACTIVE_FILE);
+       ClearPageActive(page);
+       __lru_cache_add(page);
 }
 
 /* linux/mm/vmscan.c */
index fcb627ff8d3eb71ad49ced6763a0ff061b83f62e..9a9051bb1a03be1ad8df3bc407ee9f8895df8a07 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef __LINUX_TPM_H__
 #define __LINUX_TPM_H__
 
+#define TPM_DIGEST_SIZE 20     /* Max TPM v1.2 PCR size */
+
 /*
  * Chip num is this value or a valid tpm idx
  */
index f8e084d0fc772a59bd786871bb6b166e2303a252..ebeab360d851c1ece4952b3f5f4f294aa9673db0 100644 (file)
@@ -378,6 +378,8 @@ static inline void tracepoint_synchronize_unregister(void)
 #define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print)
 #define DEFINE_EVENT(template, name, proto, args)              \
        DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
+#define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg)\
+       DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
 #define DEFINE_EVENT_CONDITION(template, name, proto,          \
index 9ff8645b7e0be05cee6dbbcf7498690425a1f3f4..e94c75ded111e747a288ddd814f8323a6148fece 100644 (file)
@@ -34,13 +34,6 @@ struct virtqueue {
        void *priv;
 };
 
-int virtqueue_add_buf(struct virtqueue *vq,
-                     struct scatterlist sg[],
-                     unsigned int out_num,
-                     unsigned int in_num,
-                     void *data,
-                     gfp_t gfp);
-
 int virtqueue_add_outbuf(struct virtqueue *vq,
                         struct scatterlist sg[], unsigned int num,
                         void *data,
index 7d5773a99f20690dac2bbf60dbcda274b9c20ae8..dd0a2c810529ed09526d25336a7b2a37d969f6ea 100644 (file)
@@ -82,6 +82,10 @@ extern void *vmap(struct page **pages, unsigned int count,
                        unsigned long flags, pgprot_t prot);
 extern void vunmap(const void *addr);
 
+extern int remap_vmalloc_range_partial(struct vm_area_struct *vma,
+                                      unsigned long uaddr, void *kaddr,
+                                      unsigned long size);
+
 extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
                                                        unsigned long pgoff);
 void vmalloc_sync_all(void);
index 623488fdc1f5ee6cf24f3745902c4b95c1f5417d..a0ed78ab54d74b3f60450745fd98c5bf1491e12c 100644 (file)
@@ -303,6 +303,33 @@ enum {
        WQ_CPU_INTENSIVE        = 1 << 5, /* cpu instensive workqueue */
        WQ_SYSFS                = 1 << 6, /* visible in sysfs, see wq_sysfs_register() */
 
+       /*
+        * Per-cpu workqueues are generally preferred because they tend to
+        * show better performance thanks to cache locality.  Per-cpu
+        * workqueues exclude the scheduler from choosing the CPU to
+        * execute the worker threads, which has an unfortunate side effect
+        * of increasing power consumption.
+        *
+        * The scheduler considers a CPU idle if it doesn't have any task
+        * to execute and tries to keep idle cores idle to conserve power;
+        * however, for example, a per-cpu work item scheduled from an
+        * interrupt handler on an idle CPU will force the scheduler to
+        * excute the work item on that CPU breaking the idleness, which in
+        * turn may lead to more scheduling choices which are sub-optimal
+        * in terms of power consumption.
+        *
+        * Workqueues marked with WQ_POWER_EFFICIENT are per-cpu by default
+        * but become unbound if workqueue.power_efficient kernel param is
+        * specified.  Per-cpu workqueues which are identified to
+        * contribute significantly to power-consumption are identified and
+        * marked with this flag and enabling the power_efficient mode
+        * leads to noticeable power saving at the cost of small
+        * performance disadvantage.
+        *
+        * http://thread.gmane.org/gmane.linux.kernel/1480396
+        */
+       WQ_POWER_EFFICIENT      = 1 << 7,
+
        __WQ_DRAINING           = 1 << 16, /* internal: workqueue is draining */
        __WQ_ORDERED            = 1 << 17, /* internal: workqueue is ordered */
 
@@ -333,11 +360,19 @@ enum {
  *
  * system_freezable_wq is equivalent to system_wq except that it's
  * freezable.
+ *
+ * *_power_efficient_wq are inclined towards saving power and converted
+ * into WQ_UNBOUND variants if 'wq_power_efficient' is enabled; otherwise,
+ * they are same as their non-power-efficient counterparts - e.g.
+ * system_power_efficient_wq is identical to system_wq if
+ * 'wq_power_efficient' is disabled.  See WQ_POWER_EFFICIENT for more info.
  */
 extern struct workqueue_struct *system_wq;
 extern struct workqueue_struct *system_long_wq;
 extern struct workqueue_struct *system_unbound_wq;
 extern struct workqueue_struct *system_freezable_wq;
+extern struct workqueue_struct *system_power_efficient_wq;
+extern struct workqueue_struct *system_freezable_power_efficient_wq;
 
 static inline struct workqueue_struct * __deprecated __system_nrt_wq(void)
 {
@@ -410,11 +445,12 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
        alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
 
 #define create_workqueue(name)                                         \
-       alloc_workqueue((name), WQ_MEM_RECLAIM, 1)
+       alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, (name))
 #define create_freezable_workqueue(name)                               \
-       alloc_workqueue((name), WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
+       alloc_workqueue("%s", WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, \
+                       1, (name))
 #define create_singlethread_workqueue(name)                            \
-       alloc_workqueue((name), WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
+       alloc_workqueue("%s", WQ_UNBOUND | WQ_MEM_RECLAIM, 1, (name))
 
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
index 34bc93d80d55eec9370909aad3dde8f4d26521f3..5358892b1b39bd484570425b38bf6920ed45442e 100644 (file)
@@ -233,7 +233,8 @@ snd_ctl_add_slave_uncached(struct snd_kcontrol *master,
 int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl,
                             void (*hook)(void *private_data, int),
                             void *private_data);
-void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kctl);
+void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only);
+#define snd_ctl_sync_vmaster_hook(kctl)        snd_ctl_sync_vmaster(kctl, true)
 
 /*
  * Helper functions for jack-detection controls
index 5bfe5136441c748de80c27992c94d6d60deb96bc..c586617cfa0dffaa2cdce5e548f78fed28e1f63e 100644 (file)
@@ -30,7 +30,7 @@
 
 /* number of supported soundcards */
 #ifdef CONFIG_SND_DYNAMIC_MINORS
-#define SNDRV_CARDS 32
+#define SNDRV_CARDS CONFIG_SND_MAX_CARDS
 #else
 #define SNDRV_CARDS 8          /* don't change - minor numbers */
 #endif
index b48792fe386b5e2ae18fb7be8799bea78f38b8a0..84b10f9a28324951a2a56d1cc89df9d50e0623bb 100644 (file)
@@ -384,7 +384,7 @@ struct snd_pcm_substream {
        unsigned int dma_buf_id;
        size_t dma_max;
        /* -- hardware operations -- */
-       struct snd_pcm_ops *ops;
+       const struct snd_pcm_ops *ops;
        /* -- runtime information -- */
        struct snd_pcm_runtime *runtime;
         /* -- timer section -- */
@@ -871,7 +871,8 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format);
 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames);
 snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsigned, int big_endian);
 
-void snd_pcm_set_ops(struct snd_pcm * pcm, int direction, struct snd_pcm_ops *ops);
+void snd_pcm_set_ops(struct snd_pcm * pcm, int direction,
+                    const struct snd_pcm_ops *ops);
 void snd_pcm_set_sync(struct snd_pcm_substream *substream);
 int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream);
 int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
diff --git a/include/sound/rt5640.h b/include/sound/rt5640.h
new file mode 100644 (file)
index 0000000..27cc75e
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * linux/sound/rt5640.h -- Platform data for RT5640
+ *
+ * Copyright 2011 Realtek Microelectronics
+ *
+ * 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 __LINUX_SND_RT5640_H
+#define __LINUX_SND_RT5640_H
+
+struct rt5640_platform_data {
+       /* IN1 & IN2 can optionally be differential */
+       bool in1_diff;
+       bool in2_diff;
+
+       int ldo1_en; /* GPIO for LDO1_EN */
+};
+
+#endif
index 385c6329a96781fe42adc8772c3be3d3a2e65cec..3e479f4e15f5e3469ef0c7f72f6e88174f36ceba 100644 (file)
@@ -311,6 +311,8 @@ struct device;
 #define SND_SOC_DAPM_POST_PMD  0x8             /* after widget power down */
 #define SND_SOC_DAPM_PRE_REG   0x10    /* before audio path setup */
 #define SND_SOC_DAPM_POST_REG  0x20    /* after audio path setup */
+#define SND_SOC_DAPM_WILL_PMU   0x40    /* called at start of sequence */
+#define SND_SOC_DAPM_WILL_PMD   0x80    /* called at start of sequence */
 #define SND_SOC_DAPM_PRE_POST_PMD \
                                (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
 
@@ -479,7 +481,6 @@ struct snd_soc_dapm_route {
 /* dapm audio path between two widgets */
 struct snd_soc_dapm_path {
        const char *name;
-       const char *long_name;
 
        /* source (input) and sink (output) widgets */
        struct snd_soc_dapm_widget *source;
index 85c15226103b09c17c3b48b6366b182cac235ded..6eabee7ec15a90197ff3024f827d47cfaad91095 100644 (file)
@@ -340,7 +340,7 @@ struct snd_soc_jack_gpio;
 
 typedef int (*hw_write_t)(void *,const char* ,int);
 
-extern struct snd_ac97_bus_ops soc_ac97_ops;
+extern struct snd_ac97_bus_ops *soc_ac97_ops;
 
 enum snd_soc_control_type {
        SND_SOC_I2C = 1,
@@ -467,6 +467,8 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
        struct snd_ac97_bus_ops *ops, int num);
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
 
+int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
+
 /*
  *Controls
  */
index 1905ca8dd3990673ce5ccafa07144d5c3b19168d..02e1003568a414584431181603913de0cfb4cb21 100644 (file)
 #define DEFINE_EVENT(template, name, proto, args) \
        DEFINE_TRACE(name)
 
+#undef DEFINE_EVENT_FN
+#define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg) \
+       DEFINE_TRACE_FN(name, reg, unreg)
+
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_TRACE(name)
@@ -91,6 +95,7 @@
 #undef TRACE_EVENT_CONDITION
 #undef DECLARE_EVENT_CLASS
 #undef DEFINE_EVENT
+#undef DEFINE_EVENT_FN
 #undef DEFINE_EVENT_PRINT
 #undef DEFINE_EVENT_CONDITION
 #undef TRACE_HEADER_MULTI_READ
diff --git a/include/trace/events/nmi.h b/include/trace/events/nmi.h
new file mode 100644 (file)
index 0000000..da3ee96
--- /dev/null
@@ -0,0 +1,37 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM nmi
+
+#if !defined(_TRACE_NMI_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_NMI_H
+
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(nmi_handler,
+
+       TP_PROTO(void *handler, s64 delta_ns, int handled),
+
+       TP_ARGS(handler, delta_ns, handled),
+
+       TP_STRUCT__entry(
+               __field(        void *,         handler )
+               __field(        s64,            delta_ns)
+               __field(        int,            handled )
+       ),
+
+       TP_fast_assign(
+               __entry->handler = handler;
+               __entry->delta_ns = delta_ns;
+               __entry->handled = handled;
+       ),
+
+       TP_printk("%ps() delta_ns: %lld handled: %d",
+               __entry->handler,
+               __entry->delta_ns,
+               __entry->handled)
+);
+
+#endif /* _TRACE_NMI_H */
+
+/* This part ust be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/pagemap.h b/include/trace/events/pagemap.h
new file mode 100644 (file)
index 0000000..1c9fabd
--- /dev/null
@@ -0,0 +1,89 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM pagemap
+
+#if !defined(_TRACE_PAGEMAP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PAGEMAP_H
+
+#include <linux/tracepoint.h>
+#include <linux/mm.h>
+
+#define        PAGEMAP_MAPPED          0x0001u
+#define PAGEMAP_ANONYMOUS      0x0002u
+#define PAGEMAP_FILE           0x0004u
+#define PAGEMAP_SWAPCACHE      0x0008u
+#define PAGEMAP_SWAPBACKED     0x0010u
+#define PAGEMAP_MAPPEDDISK     0x0020u
+#define PAGEMAP_BUFFERS                0x0040u
+
+#define trace_pagemap_flags(page) ( \
+       (PageAnon(page)         ? PAGEMAP_ANONYMOUS  : PAGEMAP_FILE) | \
+       (page_mapped(page)      ? PAGEMAP_MAPPED     : 0) | \
+       (PageSwapCache(page)    ? PAGEMAP_SWAPCACHE  : 0) | \
+       (PageSwapBacked(page)   ? PAGEMAP_SWAPBACKED : 0) | \
+       (PageMappedToDisk(page) ? PAGEMAP_MAPPEDDISK : 0) | \
+       (page_has_private(page) ? PAGEMAP_BUFFERS    : 0) \
+       )
+
+TRACE_EVENT(mm_lru_insertion,
+
+       TP_PROTO(
+               struct page *page,
+               unsigned long pfn,
+               int lru,
+               unsigned long flags
+       ),
+
+       TP_ARGS(page, pfn, lru, flags),
+
+       TP_STRUCT__entry(
+               __field(struct page *,  page    )
+               __field(unsigned long,  pfn     )
+               __field(int,            lru     )
+               __field(unsigned long,  flags   )
+       ),
+
+       TP_fast_assign(
+               __entry->page   = page;
+               __entry->pfn    = pfn;
+               __entry->lru    = lru;
+               __entry->flags  = flags;
+       ),
+
+       /* Flag format is based on page-types.c formatting for pagemap */
+       TP_printk("page=%p pfn=%lu lru=%d flags=%s%s%s%s%s%s",
+                       __entry->page,
+                       __entry->pfn,
+                       __entry->lru,
+                       __entry->flags & PAGEMAP_MAPPED         ? "M" : " ",
+                       __entry->flags & PAGEMAP_ANONYMOUS      ? "a" : "f",
+                       __entry->flags & PAGEMAP_SWAPCACHE      ? "s" : " ",
+                       __entry->flags & PAGEMAP_SWAPBACKED     ? "b" : " ",
+                       __entry->flags & PAGEMAP_MAPPEDDISK     ? "d" : " ",
+                       __entry->flags & PAGEMAP_BUFFERS        ? "B" : " ")
+);
+
+TRACE_EVENT(mm_lru_activate,
+
+       TP_PROTO(struct page *page, unsigned long pfn),
+
+       TP_ARGS(page, pfn),
+
+       TP_STRUCT__entry(
+               __field(struct page *,  page    )
+               __field(unsigned long,  pfn     )
+       ),
+
+       TP_fast_assign(
+               __entry->page   = page;
+               __entry->pfn    = pfn;
+       ),
+
+       /* Flag format is based on page-types.c formatting for pagemap */
+       TP_printk("page=%p pfn=%lu", __entry->page, __entry->pfn)
+
+);
+
+#endif /* _TRACE_PAGEMAP_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 427acab5d69af24899c4daf19b194e4abd67a243..8e42410bd1591c5168d616d3ebcac66a1d22aed5 100644 (file)
@@ -5,6 +5,7 @@
 #define _TRACE_POWER_H
 
 #include <linux/ktime.h>
+#include <linux/pm_qos.h>
 #include <linux/tracepoint.h>
 
 DECLARE_EVENT_CLASS(cpu,
@@ -177,6 +178,178 @@ DEFINE_EVENT(power_domain, power_domain_target,
 
        TP_ARGS(name, state, cpu_id)
 );
+
+/*
+ * The pm qos events are used for pm qos update
+ */
+DECLARE_EVENT_CLASS(pm_qos_request,
+
+       TP_PROTO(int pm_qos_class, s32 value),
+
+       TP_ARGS(pm_qos_class, value),
+
+       TP_STRUCT__entry(
+               __field( int,                    pm_qos_class   )
+               __field( s32,                    value          )
+       ),
+
+       TP_fast_assign(
+               __entry->pm_qos_class = pm_qos_class;
+               __entry->value = value;
+       ),
+
+       TP_printk("pm_qos_class=%s value=%d",
+                 __print_symbolic(__entry->pm_qos_class,
+                       { PM_QOS_CPU_DMA_LATENCY,       "CPU_DMA_LATENCY" },
+                       { PM_QOS_NETWORK_LATENCY,       "NETWORK_LATENCY" },
+                       { PM_QOS_NETWORK_THROUGHPUT,    "NETWORK_THROUGHPUT" }),
+                 __entry->value)
+);
+
+DEFINE_EVENT(pm_qos_request, pm_qos_add_request,
+
+       TP_PROTO(int pm_qos_class, s32 value),
+
+       TP_ARGS(pm_qos_class, value)
+);
+
+DEFINE_EVENT(pm_qos_request, pm_qos_update_request,
+
+       TP_PROTO(int pm_qos_class, s32 value),
+
+       TP_ARGS(pm_qos_class, value)
+);
+
+DEFINE_EVENT(pm_qos_request, pm_qos_remove_request,
+
+       TP_PROTO(int pm_qos_class, s32 value),
+
+       TP_ARGS(pm_qos_class, value)
+);
+
+TRACE_EVENT(pm_qos_update_request_timeout,
+
+       TP_PROTO(int pm_qos_class, s32 value, unsigned long timeout_us),
+
+       TP_ARGS(pm_qos_class, value, timeout_us),
+
+       TP_STRUCT__entry(
+               __field( int,                    pm_qos_class   )
+               __field( s32,                    value          )
+               __field( unsigned long,          timeout_us     )
+       ),
+
+       TP_fast_assign(
+               __entry->pm_qos_class = pm_qos_class;
+               __entry->value = value;
+               __entry->timeout_us = timeout_us;
+       ),
+
+       TP_printk("pm_qos_class=%s value=%d, timeout_us=%ld",
+                 __print_symbolic(__entry->pm_qos_class,
+                       { PM_QOS_CPU_DMA_LATENCY,       "CPU_DMA_LATENCY" },
+                       { PM_QOS_NETWORK_LATENCY,       "NETWORK_LATENCY" },
+                       { PM_QOS_NETWORK_THROUGHPUT,    "NETWORK_THROUGHPUT" }),
+                 __entry->value, __entry->timeout_us)
+);
+
+DECLARE_EVENT_CLASS(pm_qos_update,
+
+       TP_PROTO(enum pm_qos_req_action action, int prev_value, int curr_value),
+
+       TP_ARGS(action, prev_value, curr_value),
+
+       TP_STRUCT__entry(
+               __field( enum pm_qos_req_action, action         )
+               __field( int,                    prev_value     )
+               __field( int,                    curr_value     )
+       ),
+
+       TP_fast_assign(
+               __entry->action = action;
+               __entry->prev_value = prev_value;
+               __entry->curr_value = curr_value;
+       ),
+
+       TP_printk("action=%s prev_value=%d curr_value=%d",
+                 __print_symbolic(__entry->action,
+                       { PM_QOS_ADD_REQ,       "ADD_REQ" },
+                       { PM_QOS_UPDATE_REQ,    "UPDATE_REQ" },
+                       { PM_QOS_REMOVE_REQ,    "REMOVE_REQ" }),
+                 __entry->prev_value, __entry->curr_value)
+);
+
+DEFINE_EVENT(pm_qos_update, pm_qos_update_target,
+
+       TP_PROTO(enum pm_qos_req_action action, int prev_value, int curr_value),
+
+       TP_ARGS(action, prev_value, curr_value)
+);
+
+DEFINE_EVENT_PRINT(pm_qos_update, pm_qos_update_flags,
+
+       TP_PROTO(enum pm_qos_req_action action, int prev_value, int curr_value),
+
+       TP_ARGS(action, prev_value, curr_value),
+
+       TP_printk("action=%s prev_value=0x%x curr_value=0x%x",
+                 __print_symbolic(__entry->action,
+                       { PM_QOS_ADD_REQ,       "ADD_REQ" },
+                       { PM_QOS_UPDATE_REQ,    "UPDATE_REQ" },
+                       { PM_QOS_REMOVE_REQ,    "REMOVE_REQ" }),
+                 __entry->prev_value, __entry->curr_value)
+);
+
+DECLARE_EVENT_CLASS(dev_pm_qos_request,
+
+       TP_PROTO(const char *name, enum dev_pm_qos_req_type type,
+                s32 new_value),
+
+       TP_ARGS(name, type, new_value),
+
+       TP_STRUCT__entry(
+               __string( name,                    name         )
+               __field( enum dev_pm_qos_req_type, type         )
+               __field( s32,                      new_value    )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, name);
+               __entry->type = type;
+               __entry->new_value = new_value;
+       ),
+
+       TP_printk("device=%s type=%s new_value=%d",
+                 __get_str(name),
+                 __print_symbolic(__entry->type,
+                       { DEV_PM_QOS_LATENCY,   "DEV_PM_QOS_LATENCY" },
+                       { DEV_PM_QOS_FLAGS,     "DEV_PM_QOS_FLAGS" }),
+                 __entry->new_value)
+);
+
+DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_add_request,
+
+       TP_PROTO(const char *name, enum dev_pm_qos_req_type type,
+                s32 new_value),
+
+       TP_ARGS(name, type, new_value)
+);
+
+DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_update_request,
+
+       TP_PROTO(const char *name, enum dev_pm_qos_req_type type,
+                s32 new_value),
+
+       TP_ARGS(name, type, new_value)
+);
+
+DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_remove_request,
+
+       TP_PROTO(const char *name, enum dev_pm_qos_req_type type,
+                s32 new_value),
+
+       TP_ARGS(name, type, new_value)
+);
 #endif /* _TRACE_POWER_H */
 
 /* This part must be outside protection */
index a43a2f67bd8e080d844a780a2255dc77af898762..23d561512f64fe65a5165a23d4620f7d457504a4 100644 (file)
@@ -223,6 +223,29 @@ DEFINE_EVENT(regmap_async, regmap_async_complete_done,
 
 );
 
+TRACE_EVENT(regcache_drop_region,
+
+       TP_PROTO(struct device *dev, unsigned int from,
+                unsigned int to),
+
+       TP_ARGS(dev, from, to),
+
+       TP_STRUCT__entry(
+               __string(       name,           dev_name(dev)   )
+               __field(        unsigned int,   from            )
+               __field(        unsigned int,   to              )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, dev_name(dev));
+               __entry->from = from;
+               __entry->to = to;
+       ),
+
+       TP_printk("%s %u-%u", __get_str(name), (unsigned int)__entry->from,
+                 (unsigned int)__entry->to)
+);
+
 #endif /* _TRACE_REGMAP_H */
 
 /* This part must be outside protection */
index 19edd7facaa1c627ac96574c93e9bf6b32c67aed..d615f78cc6b6945d3fa73609056aa1f0bc577870 100644 (file)
        static struct ftrace_event_call __used          \
        __attribute__((__aligned__(4))) event_##name
 
+#undef DEFINE_EVENT_FN
+#define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg)       \
+       DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
+
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \
        DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))
index a48937d4a5ea5715fafe813baf4f586a0b747355..06632beaa6d515d80fc2a62c5ddca455c964e0a3 100644 (file)
 #define O_PATH         010000000
 #endif
 
+#ifndef O_TMPFILE
+#define O_TMPFILE      020000000
+#endif
+
 #ifndef O_NDELAY
 #define O_NDELAY       O_NONBLOCK
 #endif
index 0cc74c4403e446c8ecc5a1bd9fd8f5f19b3ae0dc..a20a9b4d38713f5a92982457f0e8f330b0bfd58c 100644 (file)
@@ -361,7 +361,7 @@ __SYSCALL(__NR_syslog, sys_syslog)
 #define __NR_ptrace 117
 __SYSCALL(__NR_ptrace, sys_ptrace)
 
-/* kernel/sched.c */
+/* kernel/sched/core.c */
 #define __NR_sched_setparam 118
 __SYSCALL(__NR_sched_setparam, sys_sched_setparam)
 #define __NR_sched_setscheduler 119
index c22c707c455d6b379afa6c2642640e6b6277541e..c872bfd25e139115014764018072beb171dd23ad 100644 (file)
@@ -21,4 +21,7 @@
 #define _AT(T,X)       ((T)(X))
 #endif
 
+#define _BITUL(x)      (_AC(1,UL) << (x))
+#define _BITULL(x)     (_AC(1,ULL) << (x))
+
 #endif /* !(_LINUX_CONST_H) */
index d88c8ee00c8b7b39cc935c8353bc7f4f3eb3c8bf..acccd08be6c7563f6c2c316f6c2530563a7d3cb5 100644 (file)
@@ -666,6 +666,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_IRQ_MPIC 90
 #define KVM_CAP_PPC_RTAS 91
 #define KVM_CAP_IRQ_XICS 92
+#define KVM_CAP_ARM_EL1_32BIT 93
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -783,6 +784,7 @@ struct kvm_dirty_tlb {
 #define KVM_REG_IA64           0x3000000000000000ULL
 #define KVM_REG_ARM            0x4000000000000000ULL
 #define KVM_REG_S390           0x5000000000000000ULL
+#define KVM_REG_ARM64          0x6000000000000000ULL
 #define KVM_REG_MIPS           0x7000000000000000ULL
 
 #define KVM_REG_SIZE_SHIFT     52
index 864e324da80d73aad07778f38bba7f7be8e4d55d..c3cc01d474b0b545ecfb643782386aaadaf6f1da 100644 (file)
 #define  PCI_EXP_LNKCAP_ASPMS  0x00000c00 /* ASPM Support */
 #define  PCI_EXP_LNKCAP_L0SEL  0x00007000 /* L0s Exit Latency */
 #define  PCI_EXP_LNKCAP_L1EL   0x00038000 /* L1 Exit Latency */
-#define  PCI_EXP_LNKCAP_CLKPM  0x00040000 /* L1 Clock Power Management */
+#define  PCI_EXP_LNKCAP_CLKPM  0x00040000 /* Clock Power Management */
 #define  PCI_EXP_LNKCAP_SDERC  0x00080000 /* Surprise Down Error Reporting Capable */
 #define  PCI_EXP_LNKCAP_DLLLARC        0x00100000 /* Data Link Layer Link Active Reporting Capable */
 #define  PCI_EXP_LNKCAP_LBNC   0x00200000 /* Link Bandwidth Notification Capability */
index fb104e51496ed0779159541865d42933b1a5e7a2..0b1df41691e8cc2c5436ceeab4812c4753de6653 100644 (file)
@@ -157,8 +157,11 @@ enum perf_branch_sample_type {
        PERF_SAMPLE_BRANCH_ANY_CALL     = 1U << 4, /* any call branch */
        PERF_SAMPLE_BRANCH_ANY_RETURN   = 1U << 5, /* any return branch */
        PERF_SAMPLE_BRANCH_IND_CALL     = 1U << 6, /* indirect calls */
+       PERF_SAMPLE_BRANCH_ABORT_TX     = 1U << 7, /* transaction aborts */
+       PERF_SAMPLE_BRANCH_IN_TX        = 1U << 8, /* in transaction */
+       PERF_SAMPLE_BRANCH_NO_TX        = 1U << 9, /* not in transaction */
 
-       PERF_SAMPLE_BRANCH_MAX          = 1U << 7, /* non-ABI */
+       PERF_SAMPLE_BRANCH_MAX          = 1U << 10, /* non-ABI */
 };
 
 #define PERF_SAMPLE_BRANCH_PLM_ALL \
index 52ebcc89f306a3106489597c504ae60c0469b9ca..cf1019e15f5bc57c0fbf6120a96deb2340465294 100644 (file)
@@ -61,6 +61,9 @@ struct ptrace_peeksiginfo_args {
        __s32 nr;       /* how may siginfos to take */
 };
 
+#define PTRACE_GETSIGMASK      0x420a
+#define PTRACE_SETSIGMASK      0x420b
+
 /* Read signals from a shared (process wide) queue */
 #define PTRACE_PEEKSIGINFO_SHARED      (1 << 0)
 
index c312f16bc4e7e692f4117b0a9280cadf1977f8db..ba260dd0b33aece9b8ba983b9914583ff7b48e6c 100644 (file)
@@ -38,6 +38,7 @@
 /* Feature bits */
 #define VIRTIO_CONSOLE_F_SIZE  0       /* Does host provide console size? */
 #define VIRTIO_CONSOLE_F_MULTIPORT 1   /* Does host provide multiple ports? */
+#define VIRTIO_CONSOLE_F_EMERG_WRITE 2 /* Does host support emergency write? */
 
 #define VIRTIO_CONSOLE_BAD_ID          (~(__u32)0)
 
@@ -48,6 +49,8 @@ struct virtio_console_config {
        __u16 rows;
        /* max. number of ports this device can hold */
        __u32 max_nr_ports;
+       /* emergency write register */
+       __u32 emerg_wr;
 } __attribute__((packed));
 
 /*
index ea66f3f60d63f7db3234c2f75058826af072a771..e5ec1caab82aa70811a9d155e3e90dddfecb853c 100644 (file)
@@ -80,7 +80,9 @@
 
 /* The remaining space is defined by each driver as the per-driver
  * configuration space */
-#define VIRTIO_PCI_CONFIG(dev)         ((dev)->msix_enabled ? 24 : 20)
+#define VIRTIO_PCI_CONFIG_OFF(msix_enabled)    ((msix_enabled) ? 24 : 20)
+/* Deprecated: please use VIRTIO_PCI_CONFIG_OFF instead */
+#define VIRTIO_PCI_CONFIG(dev) VIRTIO_PCI_CONFIG_OFF((dev)->msix_enabled)
 
 /* Virtio ABI version, this must match exactly */
 #define VIRTIO_PCI_ABI_VERSION         0
index e3983d508272cf1fd1b566eec395800bd14a2a96..041203f20f6d1cb3cac42df78723356550729054 100644 (file)
@@ -817,6 +817,8 @@ typedef int __bitwise snd_ctl_elem_iface_t;
 #define SNDRV_CTL_POWER_D3hot          (SNDRV_CTL_POWER_D3|0x0000)     /* Off, with power */
 #define SNDRV_CTL_POWER_D3cold         (SNDRV_CTL_POWER_D3|0x0001)     /* Off, without power */
 
+#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN  44
+
 struct snd_ctl_elem_id {
        unsigned int numid;             /* numeric identifier, zero = invalid */
        snd_ctl_elem_iface_t iface;     /* interface identifier */
index 68d73d09b770308b6cd23ffadbfa52780581a2a1..46aa3d1c1654776b6b223d6089a7eb1597662afc 100644 (file)
@@ -78,11 +78,25 @@ static inline int xen_acpi_get_pxm(acpi_handle h)
 int xen_acpi_notify_hypervisor_state(u8 sleep_state,
                                     u32 pm1a_cnt, u32 pm1b_cnd);
 
+static inline int xen_acpi_suspend_lowlevel(void)
+{
+       /*
+       * Xen will save and restore CPU context, so
+       * we can skip that and just go straight to
+       * the suspend.
+       */
+       acpi_enter_sleep_state(ACPI_STATE_S3);
+       return 0;
+}
+
 static inline void xen_acpi_sleep_register(void)
 {
-       if (xen_initial_domain())
+       if (xen_initial_domain()) {
                acpi_os_set_prepare_sleep(
                        &xen_acpi_notify_hypervisor_state);
+
+               acpi_suspend_lowlevel = xen_acpi_suspend_lowlevel;
+       }
 }
 #else
 static inline void xen_acpi_sleep_register(void)
index b2b27c6a0f7bed4d17e85a57434cae2120cd4ec8..c9ea10ee227358b5e4deadc5b21c9612a9d15214 100644 (file)
@@ -76,6 +76,9 @@ unsigned irq_from_evtchn(unsigned int evtchn);
 
 /* Xen HVM evtchn vector callback */
 void xen_hvm_callback_vector(void);
+#ifdef CONFIG_TRACING
+#define trace_xen_hvm_callback_vector xen_hvm_callback_vector
+#endif
 extern int xen_have_vector_callback;
 int xen_set_callback_via(uint64_t via);
 void xen_evtchn_do_upcall(struct pt_regs *regs);
index 13e43e41637dad471aa9c7033474c57596260371..63917a8de3b077db8e944fae48cea0497046e001 100644 (file)
@@ -44,8 +44,8 @@ static inline int hvm_get_parameter(int idx, uint64_t *value)
        xhv.index = idx;
        r = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
        if (r < 0) {
-               printk(KERN_ERR "Cannot get hvm parameter %s (%d): %d!\n",
-                       param_name(idx), idx, r);
+               pr_err("Cannot get hvm parameter %s (%d): %d!\n",
+                      param_name(idx), idx, r);
                return r;
        }
        *value = xhv.value;
index 0eafaf254fff0e282e4fe340ede1950a5d9e86cb..056744b4b05eb7d34c10f8610a3148d3b2b4a668 100644 (file)
@@ -15,7 +15,7 @@
 # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_IA64
 #elif defined(__powerpc64__)
 # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_POWERPC64
-#elif defined(__arm__)
+#elif defined(__arm__) || defined(__aarch64__)
 # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_ARM
 #else
 # error arch fixup needed here
index 1e825c299ea5f1e30086824a7d198aa758a58645..ef10d83bc37900eba1d7f3e2378b6030a10ae657 100644 (file)
@@ -473,18 +473,10 @@ config TINY_RCU
          is not required.  This option greatly reduces the
          memory footprint of RCU.
 
-config TINY_PREEMPT_RCU
-       bool "Preemptible UP-only small-memory-footprint RCU"
-       depends on PREEMPT && !SMP
-       help
-         This option selects the RCU implementation that is designed
-         for real-time UP systems.  This option greatly reduces the
-         memory footprint of RCU.
-
 endchoice
 
 config PREEMPT_RCU
-       def_bool ( TREE_PREEMPT_RCU || TINY_PREEMPT_RCU )
+       def_bool TREE_PREEMPT_RCU
        help
          This option enables preemptible-RCU code that is common between
          the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations.
@@ -670,7 +662,7 @@ config RCU_BOOST_DELAY
          Accept the default if unsure.
 
 config RCU_NOCB_CPU
-       bool "Offload RCU callback processing from boot-selected CPUs (EXPERIMENTAL"
+       bool "Offload RCU callback processing from boot-selected CPUs"
        depends on TREE_RCU || TREE_PREEMPT_RCU
        default n
        help
@@ -696,9 +688,10 @@ choice
        prompt "Build-forced no-CBs CPUs"
        default RCU_NOCB_CPU_NONE
        help
-         This option allows no-CBs CPUs to be specified at build time.
-         Additional no-CBs CPUs may be specified by the rcu_nocbs=
-         boot parameter.
+         This option allows no-CBs CPUs (whose RCU callbacks are invoked
+         from kthreads rather than from softirq context) to be specified
+         at build time.  Additional no-CBs CPUs may be specified by
+         the rcu_nocbs= boot parameter.
 
 config RCU_NOCB_CPU_NONE
        bool "No build_forced no-CBs CPUs"
@@ -706,25 +699,40 @@ config RCU_NOCB_CPU_NONE
        help
          This option does not force any of the CPUs to be no-CBs CPUs.
          Only CPUs designated by the rcu_nocbs= boot parameter will be
-         no-CBs CPUs.
+         no-CBs CPUs, whose RCU callbacks will be invoked by per-CPU
+         kthreads whose names begin with "rcuo".  All other CPUs will
+         invoke their own RCU callbacks in softirq context.
+
+         Select this option if you want to choose no-CBs CPUs at
+         boot time, for example, to allow testing of different no-CBs
+         configurations without having to rebuild the kernel each time.
 
 config RCU_NOCB_CPU_ZERO
        bool "CPU 0 is a build_forced no-CBs CPU"
        depends on RCU_NOCB_CPU && !NO_HZ_FULL
        help
-         This option forces CPU 0 to be a no-CBs CPU.  Additional CPUs
-         may be designated as no-CBs CPUs using the rcu_nocbs= boot
-         parameter will be no-CBs CPUs.
+         This option forces CPU 0 to be a no-CBs CPU, so that its RCU
+         callbacks are invoked by a per-CPU kthread whose name begins
+         with "rcuo".  Additional CPUs may be designated as no-CBs
+         CPUs using the rcu_nocbs= boot parameter will be no-CBs CPUs.
+         All other CPUs will invoke their own RCU callbacks in softirq
+         context.
 
          Select this if CPU 0 needs to be a no-CBs CPU for real-time
-         or energy-efficiency reasons.
+         or energy-efficiency reasons, but the real reason it exists
+         is to ensure that randconfig testing covers mixed systems.
 
 config RCU_NOCB_CPU_ALL
        bool "All CPUs are build_forced no-CBs CPUs"
        depends on RCU_NOCB_CPU
        help
          This option forces all CPUs to be no-CBs CPUs.  The rcu_nocbs=
-         boot parameter will be ignored.
+         boot parameter will be ignored.  All CPUs' RCU callbacks will
+         be executed in the context of per-CPU rcuo kthreads created for
+         this purpose.  Assuming that the kthreads whose names start with
+         "rcuo" are bound to "housekeeping" CPUs, this reduces OS jitter
+         on the remaining CPUs, but might decrease memory locality during
+         RCU-callback invocation, thus potentially degrading throughput.
 
          Select this if all CPUs need to be no-CBs CPUs for real-time
          or energy-efficiency reasons.
@@ -891,7 +899,7 @@ config MEMCG
 
          Note that setting this option increases fixed memory overhead
          associated with each page of memory in the system. By this,
-         20(40)bytes/PAGE_SIZE on 32(64)bit system will be occupied by memory
+         8(16)bytes/PAGE_SIZE on 32(64)bit system will be occupied by memory
          usage tracking struct at boot. Total amount of this is printed out
          at boot.
 
index a2b49f2c1bd81c82fcf6766b5509b2341b8b98d6..816014c4627ee2f4adb7c8cf7ef53e6083de16fc 100644 (file)
@@ -536,7 +536,7 @@ void __init prepare_namespace(void)
        int is_floppy;
 
        if (root_delay) {
-               printk(KERN_INFO "Waiting %dsec before mounting root device...\n",
+               printk(KERN_INFO "Waiting %d sec before mounting root device...\n",
                       root_delay);
                ssleep(root_delay);
        }
index 9484f4ba88d05aa589bb737d96836a1a01db55ce..f2366533c922de7a49f1f9beee6b977603bdaaf2 100644 (file)
@@ -542,7 +542,6 @@ asmlinkage void __init start_kernel(void)
        if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
                local_irq_disable();
        idr_init_cache();
-       perf_event_init();
        rcu_init();
        tick_nohz_init();
        radix_tree_init();
@@ -555,6 +554,7 @@ asmlinkage void __init start_kernel(void)
        softirq_init();
        timekeeping_init();
        time_init();
+       perf_event_init();
        profile_init();
        call_function_init();
        WARN(!irqs_disabled(), "Interrupts were enabled early\n");
@@ -655,8 +655,6 @@ static void __init do_ctors(void)
 bool initcall_debug;
 core_param(initcall_debug, initcall_debug, bool, 0644);
 
-static char msgbuf[64];
-
 static int __init_or_module do_one_initcall_debug(initcall_t fn)
 {
        ktime_t calltime, delta, rettime;
@@ -679,6 +677,7 @@ int __init_or_module do_one_initcall(initcall_t fn)
 {
        int count = preempt_count();
        int ret;
+       char msgbuf[64];
 
        if (initcall_debug)
                ret = do_one_initcall_debug(fn);
index 44511d100eaa89f73c53f0e16828a9f03d7256ac..d2b32ac27a394095e87229030e010eb428ae7174 100644 (file)
@@ -138,7 +138,7 @@ config INLINE_SPIN_UNLOCK_BH
 
 config INLINE_SPIN_UNLOCK_IRQ
        def_bool y
-       depends on !PREEMPT || ARCH_INLINE_SPIN_UNLOCK_BH
+       depends on !PREEMPT || ARCH_INLINE_SPIN_UNLOCK_IRQ
 
 config INLINE_SPIN_UNLOCK_IRQRESTORE
        def_bool y
@@ -175,7 +175,7 @@ config INLINE_READ_UNLOCK_BH
 
 config INLINE_READ_UNLOCK_IRQ
        def_bool y
-       depends on !PREEMPT || ARCH_INLINE_READ_UNLOCK_BH
+       depends on !PREEMPT || ARCH_INLINE_READ_UNLOCK_IRQ
 
 config INLINE_READ_UNLOCK_IRQRESTORE
        def_bool y
@@ -212,7 +212,7 @@ config INLINE_WRITE_UNLOCK_BH
 
 config INLINE_WRITE_UNLOCK_IRQ
        def_bool y
-       depends on !PREEMPT || ARCH_INLINE_WRITE_UNLOCK_BH
+       depends on !PREEMPT || ARCH_INLINE_WRITE_UNLOCK_IRQ
 
 config INLINE_WRITE_UNLOCK_IRQRESTORE
        def_bool y
index a7c9e6ddb9797a886e96bbff7c75fb8ed9670c68..e5583d10a325657620add60075ae0c9eead92617 100644 (file)
@@ -63,9 +63,6 @@
 
 #include <linux/atomic.h>
 
-/* css deactivation bias, makes css->refcnt negative to deny new trygets */
-#define CSS_DEACT_BIAS         INT_MIN
-
 /*
  * cgroup_mutex is the master lock.  Any modification to cgroup or its
  * hierarchy must be performed while holding it.
@@ -99,16 +96,19 @@ static DEFINE_MUTEX(cgroup_root_mutex);
  */
 #define SUBSYS(_x) [_x ## _subsys_id] = &_x ## _subsys,
 #define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option)
-static struct cgroup_subsys *subsys[CGROUP_SUBSYS_COUNT] = {
+static struct cgroup_subsys *cgroup_subsys[CGROUP_SUBSYS_COUNT] = {
 #include <linux/cgroup_subsys.h>
 };
 
 /*
- * The "rootnode" hierarchy is the "dummy hierarchy", reserved for the
- * subsystems that are otherwise unattached - it never has more than a
- * single cgroup, and all tasks are part of that cgroup.
+ * The dummy hierarchy, reserved for the subsystems that are otherwise
+ * unattached - it never has more than a single cgroup, and all tasks are
+ * part of that cgroup.
  */
-static struct cgroupfs_root rootnode;
+static struct cgroupfs_root cgroup_dummy_root;
+
+/* dummy_top is a shorthand for the dummy hierarchy's top cgroup */
+static struct cgroup * const cgroup_dummy_top = &cgroup_dummy_root.top_cgroup;
 
 /*
  * cgroupfs file entry, pointed to from leaf dentry->d_fsdata.
@@ -186,18 +186,28 @@ struct cgroup_event {
 
 /* The list of hierarchy roots */
 
-static LIST_HEAD(roots);
-static int root_count;
+static LIST_HEAD(cgroup_roots);
+static int cgroup_root_count;
 
-static DEFINE_IDA(hierarchy_ida);
-static int next_hierarchy_id;
-static DEFINE_SPINLOCK(hierarchy_id_lock);
-
-/* dummytop is a shorthand for the dummy hierarchy's top cgroup */
-#define dummytop (&rootnode.top_cgroup)
+/*
+ * Hierarchy ID allocation and mapping.  It follows the same exclusion
+ * rules as other root ops - both cgroup_mutex and cgroup_root_mutex for
+ * writes, either for reads.
+ */
+static DEFINE_IDR(cgroup_hierarchy_idr);
 
 static struct cgroup_name root_cgroup_name = { .name = "/" };
 
+/*
+ * Assign a monotonically increasing serial number to cgroups.  It
+ * guarantees cgroups with bigger numbers are newer than those with smaller
+ * numbers.  Also, as cgroups are always appended to the parent's
+ * ->children list, it guarantees that sibling cgroups are always sorted in
+ * the ascending serial number order on the list.  Protected by
+ * cgroup_mutex.
+ */
+static u64 cgroup_serial_nr_next = 1;
+
 /* This flag indicates whether tasks in the fork and exit paths should
  * check for fork/exit handlers to call. This avoids us having to do
  * extra work in the fork/exit path if none of the subsystems need to
@@ -205,27 +215,15 @@ static struct cgroup_name root_cgroup_name = { .name = "/" };
  */
 static int need_forkexit_callback __read_mostly;
 
+static void cgroup_offline_fn(struct work_struct *work);
 static int cgroup_destroy_locked(struct cgroup *cgrp);
 static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
                              struct cftype cfts[], bool is_add);
 
-static int css_unbias_refcnt(int refcnt)
-{
-       return refcnt >= 0 ? refcnt : refcnt - CSS_DEACT_BIAS;
-}
-
-/* the current nr of refs, always >= 0 whether @css is deactivated or not */
-static int css_refcnt(struct cgroup_subsys_state *css)
-{
-       int v = atomic_read(&css->refcnt);
-
-       return css_unbias_refcnt(v);
-}
-
 /* convenient tests for these bits */
-inline int cgroup_is_removed(const struct cgroup *cgrp)
+static inline bool cgroup_is_dead(const struct cgroup *cgrp)
 {
-       return test_bit(CGRP_REMOVED, &cgrp->flags);
+       return test_bit(CGRP_DEAD, &cgrp->flags);
 }
 
 /**
@@ -261,16 +259,38 @@ static int notify_on_release(const struct cgroup *cgrp)
        return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
 }
 
-/*
- * for_each_subsys() allows you to iterate on each subsystem attached to
- * an active hierarchy
+/**
+ * for_each_subsys - iterate all loaded cgroup subsystems
+ * @ss: the iteration cursor
+ * @i: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end
+ *
+ * Should be called under cgroup_mutex.
  */
-#define for_each_subsys(_root, _ss) \
-list_for_each_entry(_ss, &_root->subsys_list, sibling)
+#define for_each_subsys(ss, i)                                         \
+       for ((i) = 0; (i) < CGROUP_SUBSYS_COUNT; (i)++)                 \
+               if (({ lockdep_assert_held(&cgroup_mutex);              \
+                      !((ss) = cgroup_subsys[i]); })) { }              \
+               else
+
+/**
+ * for_each_builtin_subsys - iterate all built-in cgroup subsystems
+ * @ss: the iteration cursor
+ * @i: the index of @ss, CGROUP_BUILTIN_SUBSYS_COUNT after reaching the end
+ *
+ * Bulit-in subsystems are always present and iteration itself doesn't
+ * require any synchronization.
+ */
+#define for_each_builtin_subsys(ss, i)                                 \
+       for ((i) = 0; (i) < CGROUP_BUILTIN_SUBSYS_COUNT &&              \
+            (((ss) = cgroup_subsys[i]) || true); (i)++)
+
+/* iterate each subsystem attached to a hierarchy */
+#define for_each_root_subsys(root, ss)                                 \
+       list_for_each_entry((ss), &(root)->subsys_list, sibling)
 
-/* for_each_active_root() allows you to iterate across the active hierarchies */
-#define for_each_active_root(_root) \
-list_for_each_entry(_root, &roots, root_list)
+/* iterate across the active hierarchies */
+#define for_each_active_root(root)                                     \
+       list_for_each_entry((root), &cgroup_roots, root_list)
 
 static inline struct cgroup *__d_cgrp(struct dentry *dentry)
 {
@@ -297,7 +317,7 @@ static inline struct cftype *__d_cft(struct dentry *dentry)
 static bool cgroup_lock_live_group(struct cgroup *cgrp)
 {
        mutex_lock(&cgroup_mutex);
-       if (cgroup_is_removed(cgrp)) {
+       if (cgroup_is_dead(cgrp)) {
                mutex_unlock(&cgroup_mutex);
                return false;
        }
@@ -312,20 +332,24 @@ static void cgroup_release_agent(struct work_struct *work);
 static DECLARE_WORK(release_agent_work, cgroup_release_agent);
 static void check_for_release(struct cgroup *cgrp);
 
-/* Link structure for associating css_set objects with cgroups */
-struct cg_cgroup_link {
-       /*
-        * List running through cg_cgroup_links associated with a
-        * cgroup, anchored on cgroup->css_sets
-        */
-       struct list_head cgrp_link_list;
-       struct cgroup *cgrp;
-       /*
-        * List running through cg_cgroup_links pointing at a
-        * single css_set object, anchored on css_set->cg_links
-        */
-       struct list_head cg_link_list;
-       struct css_set *cg;
+/*
+ * A cgroup can be associated with multiple css_sets as different tasks may
+ * belong to different cgroups on different hierarchies.  In the other
+ * direction, a css_set is naturally associated with multiple cgroups.
+ * This M:N relationship is represented by the following link structure
+ * which exists for each association and allows traversing the associations
+ * from both sides.
+ */
+struct cgrp_cset_link {
+       /* the cgroup and css_set this link associates */
+       struct cgroup           *cgrp;
+       struct css_set          *cset;
+
+       /* list of cgrp_cset_links anchored at cgrp->cset_links */
+       struct list_head        cset_link;
+
+       /* list of cgrp_cset_links anchored at css_set->cgrp_links */
+       struct list_head        cgrp_link;
 };
 
 /* The default css_set - used by init and its children prior to any
@@ -336,7 +360,7 @@ struct cg_cgroup_link {
  */
 
 static struct css_set init_css_set;
-static struct cg_cgroup_link init_css_set_link;
+static struct cgrp_cset_link init_cgrp_cset_link;
 
 static int cgroup_init_idr(struct cgroup_subsys *ss,
                           struct cgroup_subsys_state *css);
@@ -357,10 +381,11 @@ static DEFINE_HASHTABLE(css_set_table, CSS_SET_HASH_BITS);
 
 static unsigned long css_set_hash(struct cgroup_subsys_state *css[])
 {
-       int i;
        unsigned long key = 0UL;
+       struct cgroup_subsys *ss;
+       int i;
 
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++)
+       for_each_subsys(ss, i)
                key += (unsigned long)css[i];
        key = (key >> 16) ^ key;
 
@@ -373,90 +398,83 @@ static unsigned long css_set_hash(struct cgroup_subsys_state *css[])
  * compiled into their kernel but not actually in use */
 static int use_task_css_set_links __read_mostly;
 
-static void __put_css_set(struct css_set *cg, int taskexit)
+static void __put_css_set(struct css_set *cset, int taskexit)
 {
-       struct cg_cgroup_link *link;
-       struct cg_cgroup_link *saved_link;
+       struct cgrp_cset_link *link, *tmp_link;
+
        /*
         * Ensure that the refcount doesn't hit zero while any readers
         * can see it. Similar to atomic_dec_and_lock(), but for an
         * rwlock
         */
-       if (atomic_add_unless(&cg->refcount, -1, 1))
+       if (atomic_add_unless(&cset->refcount, -1, 1))
                return;
        write_lock(&css_set_lock);
-       if (!atomic_dec_and_test(&cg->refcount)) {
+       if (!atomic_dec_and_test(&cset->refcount)) {
                write_unlock(&css_set_lock);
                return;
        }
 
        /* This css_set is dead. unlink it and release cgroup refcounts */
-       hash_del(&cg->hlist);
+       hash_del(&cset->hlist);
        css_set_count--;
 
-       list_for_each_entry_safe(link, saved_link, &cg->cg_links,
-                                cg_link_list) {
+       list_for_each_entry_safe(link, tmp_link, &cset->cgrp_links, cgrp_link) {
                struct cgroup *cgrp = link->cgrp;
-               list_del(&link->cg_link_list);
-               list_del(&link->cgrp_link_list);
 
-               /*
-                * We may not be holding cgroup_mutex, and if cgrp->count is
-                * dropped to 0 the cgroup can be destroyed at any time, hence
-                * rcu_read_lock is used to keep it alive.
-                */
-               rcu_read_lock();
-               if (atomic_dec_and_test(&cgrp->count) &&
-                   notify_on_release(cgrp)) {
+               list_del(&link->cset_link);
+               list_del(&link->cgrp_link);
+
+               /* @cgrp can't go away while we're holding css_set_lock */
+               if (list_empty(&cgrp->cset_links) && notify_on_release(cgrp)) {
                        if (taskexit)
                                set_bit(CGRP_RELEASABLE, &cgrp->flags);
                        check_for_release(cgrp);
                }
-               rcu_read_unlock();
 
                kfree(link);
        }
 
        write_unlock(&css_set_lock);
-       kfree_rcu(cg, rcu_head);
+       kfree_rcu(cset, rcu_head);
 }
 
 /*
  * refcounted get/put for css_set objects
  */
-static inline void get_css_set(struct css_set *cg)
+static inline void get_css_set(struct css_set *cset)
 {
-       atomic_inc(&cg->refcount);
+       atomic_inc(&cset->refcount);
 }
 
-static inline void put_css_set(struct css_set *cg)
+static inline void put_css_set(struct css_set *cset)
 {
-       __put_css_set(cg, 0);
+       __put_css_set(cset, 0);
 }
 
-static inline void put_css_set_taskexit(struct css_set *cg)
+static inline void put_css_set_taskexit(struct css_set *cset)
 {
-       __put_css_set(cg, 1);
+       __put_css_set(cset, 1);
 }
 
-/*
+/**
  * compare_css_sets - helper function for find_existing_css_set().
- * @cg: candidate css_set being tested
- * @old_cg: existing css_set for a task
+ * @cset: candidate css_set being tested
+ * @old_cset: existing css_set for a task
  * @new_cgrp: cgroup that's being entered by the task
  * @template: desired set of css pointers in css_set (pre-calculated)
  *
  * Returns true if "cg" matches "old_cg" except for the hierarchy
  * which "new_cgrp" belongs to, for which it should match "new_cgrp".
  */
-static bool compare_css_sets(struct css_set *cg,
-                            struct css_set *old_cg,
+static bool compare_css_sets(struct css_set *cset,
+                            struct css_set *old_cset,
                             struct cgroup *new_cgrp,
                             struct cgroup_subsys_state *template[])
 {
        struct list_head *l1, *l2;
 
-       if (memcmp(template, cg->subsys, sizeof(cg->subsys))) {
+       if (memcmp(template, cset->subsys, sizeof(cset->subsys))) {
                /* Not all subsystems matched */
                return false;
        }
@@ -470,28 +488,28 @@ static bool compare_css_sets(struct css_set *cg,
         * candidates.
         */
 
-       l1 = &cg->cg_links;
-       l2 = &old_cg->cg_links;
+       l1 = &cset->cgrp_links;
+       l2 = &old_cset->cgrp_links;
        while (1) {
-               struct cg_cgroup_link *cgl1, *cgl2;
-               struct cgroup *cg1, *cg2;
+               struct cgrp_cset_link *link1, *link2;
+               struct cgroup *cgrp1, *cgrp2;
 
                l1 = l1->next;
                l2 = l2->next;
                /* See if we reached the end - both lists are equal length. */
-               if (l1 == &cg->cg_links) {
-                       BUG_ON(l2 != &old_cg->cg_links);
+               if (l1 == &cset->cgrp_links) {
+                       BUG_ON(l2 != &old_cset->cgrp_links);
                        break;
                } else {
-                       BUG_ON(l2 == &old_cg->cg_links);
+                       BUG_ON(l2 == &old_cset->cgrp_links);
                }
                /* Locate the cgroups associated with these links. */
-               cgl1 = list_entry(l1, struct cg_cgroup_link, cg_link_list);
-               cgl2 = list_entry(l2, struct cg_cgroup_link, cg_link_list);
-               cg1 = cgl1->cgrp;
-               cg2 = cgl2->cgrp;
+               link1 = list_entry(l1, struct cgrp_cset_link, cgrp_link);
+               link2 = list_entry(l2, struct cgrp_cset_link, cgrp_link);
+               cgrp1 = link1->cgrp;
+               cgrp2 = link2->cgrp;
                /* Hierarchies should be linked in the same order. */
-               BUG_ON(cg1->root != cg2->root);
+               BUG_ON(cgrp1->root != cgrp2->root);
 
                /*
                 * If this hierarchy is the hierarchy of the cgroup
@@ -500,46 +518,39 @@ static bool compare_css_sets(struct css_set *cg,
                 * hierarchy, then this css_set should point to the
                 * same cgroup as the old css_set.
                 */
-               if (cg1->root == new_cgrp->root) {
-                       if (cg1 != new_cgrp)
+               if (cgrp1->root == new_cgrp->root) {
+                       if (cgrp1 != new_cgrp)
                                return false;
                } else {
-                       if (cg1 != cg2)
+                       if (cgrp1 != cgrp2)
                                return false;
                }
        }
        return true;
 }
 
-/*
- * find_existing_css_set() is a helper for
- * find_css_set(), and checks to see whether an existing
- * css_set is suitable.
- *
- * oldcg: the cgroup group that we're using before the cgroup
- * transition
- *
- * cgrp: the cgroup that we're moving into
- *
- * template: location in which to build the desired set of subsystem
- * state objects for the new cgroup group
+/**
+ * find_existing_css_set - init css array and find the matching css_set
+ * @old_cset: the css_set that we're using before the cgroup transition
+ * @cgrp: the cgroup that we're moving into
+ * @template: out param for the new set of csses, should be clear on entry
  */
-static struct css_set *find_existing_css_set(
-       struct css_set *oldcg,
-       struct cgroup *cgrp,
-       struct cgroup_subsys_state *template[])
+static struct css_set *find_existing_css_set(struct css_set *old_cset,
+                                       struct cgroup *cgrp,
+                                       struct cgroup_subsys_state *template[])
 {
-       int i;
        struct cgroupfs_root *root = cgrp->root;
-       struct css_set *cg;
+       struct cgroup_subsys *ss;
+       struct css_set *cset;
        unsigned long key;
+       int i;
 
        /*
         * Build the set of subsystem state objects that we want to see in the
         * new css_set. while subsystems can change globally, the entries here
         * won't change, so no need for locking.
         */
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+       for_each_subsys(ss, i) {
                if (root->subsys_mask & (1UL << i)) {
                        /* Subsystem is in this hierarchy. So we want
                         * the subsystem state from the new
@@ -548,148 +559,152 @@ static struct css_set *find_existing_css_set(
                } else {
                        /* Subsystem is not in this hierarchy, so we
                         * don't want to change the subsystem state */
-                       template[i] = oldcg->subsys[i];
+                       template[i] = old_cset->subsys[i];
                }
        }
 
        key = css_set_hash(template);
-       hash_for_each_possible(css_set_table, cg, hlist, key) {
-               if (!compare_css_sets(cg, oldcg, cgrp, template))
+       hash_for_each_possible(css_set_table, cset, hlist, key) {
+               if (!compare_css_sets(cset, old_cset, cgrp, template))
                        continue;
 
                /* This css_set matches what we need */
-               return cg;
+               return cset;
        }
 
        /* No existing cgroup group matched */
        return NULL;
 }
 
-static void free_cg_links(struct list_head *tmp)
+static void free_cgrp_cset_links(struct list_head *links_to_free)
 {
-       struct cg_cgroup_link *link;
-       struct cg_cgroup_link *saved_link;
+       struct cgrp_cset_link *link, *tmp_link;
 
-       list_for_each_entry_safe(link, saved_link, tmp, cgrp_link_list) {
-               list_del(&link->cgrp_link_list);
+       list_for_each_entry_safe(link, tmp_link, links_to_free, cset_link) {
+               list_del(&link->cset_link);
                kfree(link);
        }
 }
 
-/*
- * allocate_cg_links() allocates "count" cg_cgroup_link structures
- * and chains them on tmp through their cgrp_link_list fields. Returns 0 on
- * success or a negative error
+/**
+ * allocate_cgrp_cset_links - allocate cgrp_cset_links
+ * @count: the number of links to allocate
+ * @tmp_links: list_head the allocated links are put on
+ *
+ * Allocate @count cgrp_cset_link structures and chain them on @tmp_links
+ * through ->cset_link.  Returns 0 on success or -errno.
  */
-static int allocate_cg_links(int count, struct list_head *tmp)
+static int allocate_cgrp_cset_links(int count, struct list_head *tmp_links)
 {
-       struct cg_cgroup_link *link;
+       struct cgrp_cset_link *link;
        int i;
-       INIT_LIST_HEAD(tmp);
+
+       INIT_LIST_HEAD(tmp_links);
+
        for (i = 0; i < count; i++) {
-               link = kmalloc(sizeof(*link), GFP_KERNEL);
+               link = kzalloc(sizeof(*link), GFP_KERNEL);
                if (!link) {
-                       free_cg_links(tmp);
+                       free_cgrp_cset_links(tmp_links);
                        return -ENOMEM;
                }
-               list_add(&link->cgrp_link_list, tmp);
+               list_add(&link->cset_link, tmp_links);
        }
        return 0;
 }
 
 /**
  * link_css_set - a helper function to link a css_set to a cgroup
- * @tmp_cg_links: cg_cgroup_link objects allocated by allocate_cg_links()
- * @cg: the css_set to be linked
+ * @tmp_links: cgrp_cset_link objects allocated by allocate_cgrp_cset_links()
+ * @cset: the css_set to be linked
  * @cgrp: the destination cgroup
  */
-static void link_css_set(struct list_head *tmp_cg_links,
-                        struct css_set *cg, struct cgroup *cgrp)
+static void link_css_set(struct list_head *tmp_links, struct css_set *cset,
+                        struct cgroup *cgrp)
 {
-       struct cg_cgroup_link *link;
+       struct cgrp_cset_link *link;
 
-       BUG_ON(list_empty(tmp_cg_links));
-       link = list_first_entry(tmp_cg_links, struct cg_cgroup_link,
-                               cgrp_link_list);
-       link->cg = cg;
+       BUG_ON(list_empty(tmp_links));
+       link = list_first_entry(tmp_links, struct cgrp_cset_link, cset_link);
+       link->cset = cset;
        link->cgrp = cgrp;
-       atomic_inc(&cgrp->count);
-       list_move(&link->cgrp_link_list, &cgrp->css_sets);
+       list_move(&link->cset_link, &cgrp->cset_links);
        /*
         * Always add links to the tail of the list so that the list
         * is sorted by order of hierarchy creation
         */
-       list_add_tail(&link->cg_link_list, &cg->cg_links);
+       list_add_tail(&link->cgrp_link, &cset->cgrp_links);
 }
 
-/*
- * find_css_set() takes an existing cgroup group and a
- * cgroup object, and returns a css_set object that's
- * equivalent to the old group, but with the given cgroup
- * substituted into the appropriate hierarchy. Must be called with
- * cgroup_mutex held
+/**
+ * find_css_set - return a new css_set with one cgroup updated
+ * @old_cset: the baseline css_set
+ * @cgrp: the cgroup to be updated
+ *
+ * Return a new css_set that's equivalent to @old_cset, but with @cgrp
+ * substituted into the appropriate hierarchy.
  */
-static struct css_set *find_css_set(
-       struct css_set *oldcg, struct cgroup *cgrp)
+static struct css_set *find_css_set(struct css_set *old_cset,
+                                   struct cgroup *cgrp)
 {
-       struct css_set *res;
-       struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT];
-
-       struct list_head tmp_cg_links;
-
-       struct cg_cgroup_link *link;
+       struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT] = { };
+       struct css_set *cset;
+       struct list_head tmp_links;
+       struct cgrp_cset_link *link;
        unsigned long key;
 
+       lockdep_assert_held(&cgroup_mutex);
+
        /* First see if we already have a cgroup group that matches
         * the desired set */
        read_lock(&css_set_lock);
-       res = find_existing_css_set(oldcg, cgrp, template);
-       if (res)
-               get_css_set(res);
+       cset = find_existing_css_set(old_cset, cgrp, template);
+       if (cset)
+               get_css_set(cset);
        read_unlock(&css_set_lock);
 
-       if (res)
-               return res;
+       if (cset)
+               return cset;
 
-       res = kmalloc(sizeof(*res), GFP_KERNEL);
-       if (!res)
+       cset = kzalloc(sizeof(*cset), GFP_KERNEL);
+       if (!cset)
                return NULL;
 
-       /* Allocate all the cg_cgroup_link objects that we'll need */
-       if (allocate_cg_links(root_count, &tmp_cg_links) < 0) {
-               kfree(res);
+       /* Allocate all the cgrp_cset_link objects that we'll need */
+       if (allocate_cgrp_cset_links(cgroup_root_count, &tmp_links) < 0) {
+               kfree(cset);
                return NULL;
        }
 
-       atomic_set(&res->refcount, 1);
-       INIT_LIST_HEAD(&res->cg_links);
-       INIT_LIST_HEAD(&res->tasks);
-       INIT_HLIST_NODE(&res->hlist);
+       atomic_set(&cset->refcount, 1);
+       INIT_LIST_HEAD(&cset->cgrp_links);
+       INIT_LIST_HEAD(&cset->tasks);
+       INIT_HLIST_NODE(&cset->hlist);
 
        /* Copy the set of subsystem state objects generated in
         * find_existing_css_set() */
-       memcpy(res->subsys, template, sizeof(res->subsys));
+       memcpy(cset->subsys, template, sizeof(cset->subsys));
 
        write_lock(&css_set_lock);
        /* Add reference counts and links from the new css_set. */
-       list_for_each_entry(link, &oldcg->cg_links, cg_link_list) {
+       list_for_each_entry(link, &old_cset->cgrp_links, cgrp_link) {
                struct cgroup *c = link->cgrp;
+
                if (c->root == cgrp->root)
                        c = cgrp;
-               link_css_set(&tmp_cg_links, res, c);
+               link_css_set(&tmp_links, cset, c);
        }
 
-       BUG_ON(!list_empty(&tmp_cg_links));
+       BUG_ON(!list_empty(&tmp_links));
 
        css_set_count++;
 
        /* Add this cgroup group to the hash table */
-       key = css_set_hash(res->subsys);
-       hash_add(css_set_table, &res->hlist, key);
+       key = css_set_hash(cset->subsys);
+       hash_add(css_set_table, &cset->hlist, key);
 
        write_unlock(&css_set_lock);
 
-       return res;
+       return cset;
 }
 
 /*
@@ -699,7 +714,7 @@ static struct css_set *find_css_set(
 static struct cgroup *task_cgroup_from_root(struct task_struct *task,
                                            struct cgroupfs_root *root)
 {
-       struct css_set *css;
+       struct css_set *cset;
        struct cgroup *res = NULL;
 
        BUG_ON(!mutex_is_locked(&cgroup_mutex));
@@ -709,13 +724,15 @@ static struct cgroup *task_cgroup_from_root(struct task_struct *task,
         * task can't change groups, so the only thing that can happen
         * is that it exits and its css is set back to init_css_set.
         */
-       css = task->cgroups;
-       if (css == &init_css_set) {
+       cset = task_css_set(task);
+       if (cset == &init_css_set) {
                res = &root->top_cgroup;
        } else {
-               struct cg_cgroup_link *link;
-               list_for_each_entry(link, &css->cg_links, cg_link_list) {
+               struct cgrp_cset_link *link;
+
+               list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
                        struct cgroup *c = link->cgrp;
+
                        if (c->root == root) {
                                res = c;
                                break;
@@ -828,14 +845,14 @@ static struct cgroup_name *cgroup_alloc_name(struct dentry *dentry)
 
 static void cgroup_free_fn(struct work_struct *work)
 {
-       struct cgroup *cgrp = container_of(work, struct cgroup, free_work);
+       struct cgroup *cgrp = container_of(work, struct cgroup, destroy_work);
        struct cgroup_subsys *ss;
 
        mutex_lock(&cgroup_mutex);
        /*
         * Release the subsystem state objects.
         */
-       for_each_subsys(cgrp->root, ss)
+       for_each_root_subsys(cgrp->root, ss)
                ss->css_free(cgrp);
 
        cgrp->root->number_of_cgroups--;
@@ -873,7 +890,8 @@ static void cgroup_free_rcu(struct rcu_head *head)
 {
        struct cgroup *cgrp = container_of(head, struct cgroup, rcu_head);
 
-       schedule_work(&cgrp->free_work);
+       INIT_WORK(&cgrp->destroy_work, cgroup_free_fn);
+       schedule_work(&cgrp->destroy_work);
 }
 
 static void cgroup_diput(struct dentry *dentry, struct inode *inode)
@@ -882,7 +900,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
        if (S_ISDIR(inode->i_mode)) {
                struct cgroup *cgrp = dentry->d_fsdata;
 
-               BUG_ON(!(cgroup_is_removed(cgrp)));
+               BUG_ON(!(cgroup_is_dead(cgrp)));
                call_rcu(&cgrp->rcu_head, cgroup_free_rcu);
        } else {
                struct cfent *cfe = __d_cfe(dentry);
@@ -950,7 +968,7 @@ static void cgroup_clear_directory(struct dentry *dir, bool base_files,
        struct cgroup *cgrp = __d_cgrp(dir);
        struct cgroup_subsys *ss;
 
-       for_each_subsys(cgrp->root, ss) {
+       for_each_root_subsys(cgrp->root, ss) {
                struct cftype_set *set;
                if (!test_bit(ss->subsys_id, &subsys_mask))
                        continue;
@@ -988,30 +1006,23 @@ static void cgroup_d_remove_dir(struct dentry *dentry)
  * returns an error, no reference counts are touched.
  */
 static int rebind_subsystems(struct cgroupfs_root *root,
-                             unsigned long final_subsys_mask)
+                            unsigned long added_mask, unsigned removed_mask)
 {
-       unsigned long added_mask, removed_mask;
        struct cgroup *cgrp = &root->top_cgroup;
+       struct cgroup_subsys *ss;
        int i;
 
        BUG_ON(!mutex_is_locked(&cgroup_mutex));
        BUG_ON(!mutex_is_locked(&cgroup_root_mutex));
 
-       removed_mask = root->actual_subsys_mask & ~final_subsys_mask;
-       added_mask = final_subsys_mask & ~root->actual_subsys_mask;
        /* Check that any added subsystems are currently free */
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+       for_each_subsys(ss, i) {
                unsigned long bit = 1UL << i;
-               struct cgroup_subsys *ss = subsys[i];
+
                if (!(bit & added_mask))
                        continue;
-               /*
-                * Nobody should tell us to do a subsys that doesn't exist:
-                * parse_cgroupfs_options should catch that case and refcounts
-                * ensure that subsystems won't disappear once selected.
-                */
-               BUG_ON(ss == NULL);
-               if (ss->root != &rootnode) {
+
+               if (ss->root != &cgroup_dummy_root) {
                        /* Subsystem isn't free */
                        return -EBUSY;
                }
@@ -1025,38 +1036,41 @@ static int rebind_subsystems(struct cgroupfs_root *root,
                return -EBUSY;
 
        /* Process each subsystem */
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-               struct cgroup_subsys *ss = subsys[i];
+       for_each_subsys(ss, i) {
                unsigned long bit = 1UL << i;
+
                if (bit & added_mask) {
                        /* We're binding this subsystem to this hierarchy */
-                       BUG_ON(ss == NULL);
                        BUG_ON(cgrp->subsys[i]);
-                       BUG_ON(!dummytop->subsys[i]);
-                       BUG_ON(dummytop->subsys[i]->cgroup != dummytop);
-                       cgrp->subsys[i] = dummytop->subsys[i];
+                       BUG_ON(!cgroup_dummy_top->subsys[i]);
+                       BUG_ON(cgroup_dummy_top->subsys[i]->cgroup != cgroup_dummy_top);
+
+                       cgrp->subsys[i] = cgroup_dummy_top->subsys[i];
                        cgrp->subsys[i]->cgroup = cgrp;
                        list_move(&ss->sibling, &root->subsys_list);
                        ss->root = root;
                        if (ss->bind)
                                ss->bind(cgrp);
+
                        /* refcount was already taken, and we're keeping it */
+                       root->subsys_mask |= bit;
                } else if (bit & removed_mask) {
                        /* We're removing this subsystem */
-                       BUG_ON(ss == NULL);
-                       BUG_ON(cgrp->subsys[i] != dummytop->subsys[i]);
+                       BUG_ON(cgrp->subsys[i] != cgroup_dummy_top->subsys[i]);
                        BUG_ON(cgrp->subsys[i]->cgroup != cgrp);
+
                        if (ss->bind)
-                               ss->bind(dummytop);
-                       dummytop->subsys[i]->cgroup = dummytop;
+                               ss->bind(cgroup_dummy_top);
+                       cgroup_dummy_top->subsys[i]->cgroup = cgroup_dummy_top;
                        cgrp->subsys[i] = NULL;
-                       subsys[i]->root = &rootnode;
-                       list_move(&ss->sibling, &rootnode.subsys_list);
+                       cgroup_subsys[i]->root = &cgroup_dummy_root;
+                       list_move(&ss->sibling, &cgroup_dummy_root.subsys_list);
+
                        /* subsystem is now free - drop reference on module */
                        module_put(ss->module);
-               } else if (bit & final_subsys_mask) {
+                       root->subsys_mask &= ~bit;
+               } else if (bit & root->subsys_mask) {
                        /* Subsystem state should already exist */
-                       BUG_ON(ss == NULL);
                        BUG_ON(!cgrp->subsys[i]);
                        /*
                         * a refcount was taken, but we already had one, so
@@ -1071,7 +1085,12 @@ static int rebind_subsystems(struct cgroupfs_root *root,
                        BUG_ON(cgrp->subsys[i]);
                }
        }
-       root->subsys_mask = root->actual_subsys_mask = final_subsys_mask;
+
+       /*
+        * Mark @root has finished binding subsystems.  @root->subsys_mask
+        * now matches the bound subsystems.
+        */
+       root->flags |= CGRP_ROOT_SUBSYS_BOUND;
 
        return 0;
 }
@@ -1082,7 +1101,7 @@ static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry)
        struct cgroup_subsys *ss;
 
        mutex_lock(&cgroup_root_mutex);
-       for_each_subsys(root, ss)
+       for_each_root_subsys(root, ss)
                seq_printf(seq, ",%s", ss->name);
        if (root->flags & CGRP_ROOT_SANE_BEHAVIOR)
                seq_puts(seq, ",sane_behavior");
@@ -1114,18 +1133,19 @@ struct cgroup_sb_opts {
 };
 
 /*
- * Convert a hierarchy specifier into a bitmask of subsystems and flags. Call
- * with cgroup_mutex held to protect the subsys[] array. This function takes
- * refcounts on subsystems to be used, unless it returns error, in which case
- * no refcounts are taken.
+ * Convert a hierarchy specifier into a bitmask of subsystems and
+ * flags. Call with cgroup_mutex held to protect the cgroup_subsys[]
+ * array. This function takes refcounts on subsystems to be used, unless it
+ * returns error, in which case no refcounts are taken.
  */
 static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
 {
        char *token, *o = data;
        bool all_ss = false, one_ss = false;
        unsigned long mask = (unsigned long)-1;
-       int i;
        bool module_pin_failed = false;
+       struct cgroup_subsys *ss;
+       int i;
 
        BUG_ON(!mutex_is_locked(&cgroup_mutex));
 
@@ -1202,10 +1222,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
                        continue;
                }
 
-               for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-                       struct cgroup_subsys *ss = subsys[i];
-                       if (ss == NULL)
-                               continue;
+               for_each_subsys(ss, i) {
                        if (strcmp(token, ss->name))
                                continue;
                        if (ss->disabled)
@@ -1228,16 +1245,10 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
         * otherwise if 'none', 'name=' and a subsystem name options
         * were not specified, let's default to 'all'
         */
-       if (all_ss || (!one_ss && !opts->none && !opts->name)) {
-               for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-                       struct cgroup_subsys *ss = subsys[i];
-                       if (ss == NULL)
-                               continue;
-                       if (ss->disabled)
-                               continue;
-                       set_bit(i, &opts->subsys_mask);
-               }
-       }
+       if (all_ss || (!one_ss && !opts->none && !opts->name))
+               for_each_subsys(ss, i)
+                       if (!ss->disabled)
+                               set_bit(i, &opts->subsys_mask);
 
        /* Consistency checks */
 
@@ -1281,12 +1292,10 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
         * take duplicate reference counts on a subsystem that's already used,
         * but rebind_subsystems handles this case.
         */
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-               unsigned long bit = 1UL << i;
-
-               if (!(bit & opts->subsys_mask))
+       for_each_subsys(ss, i) {
+               if (!(opts->subsys_mask & (1UL << i)))
                        continue;
-               if (!try_module_get(subsys[i]->module)) {
+               if (!try_module_get(cgroup_subsys[i]->module)) {
                        module_pin_failed = true;
                        break;
                }
@@ -1303,7 +1312,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
 
                        if (!(bit & opts->subsys_mask))
                                continue;
-                       module_put(subsys[i]->module);
+                       module_put(cgroup_subsys[i]->module);
                }
                return -ENOENT;
        }
@@ -1313,14 +1322,14 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
 
 static void drop_parsed_module_refcounts(unsigned long subsys_mask)
 {
+       struct cgroup_subsys *ss;
        int i;
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-               unsigned long bit = 1UL << i;
 
-               if (!(bit & subsys_mask))
-                       continue;
-               module_put(subsys[i]->module);
-       }
+       mutex_lock(&cgroup_mutex);
+       for_each_subsys(ss, i)
+               if (subsys_mask & (1UL << i))
+                       module_put(cgroup_subsys[i]->module);
+       mutex_unlock(&cgroup_mutex);
 }
 
 static int cgroup_remount(struct super_block *sb, int *flags, char *data)
@@ -1345,7 +1354,7 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
        if (ret)
                goto out_unlock;
 
-       if (opts.subsys_mask != root->actual_subsys_mask || opts.release_agent)
+       if (opts.subsys_mask != root->subsys_mask || opts.release_agent)
                pr_warning("cgroup: option changes via remount are deprecated (pid=%d comm=%s)\n",
                           task_tgid_nr(current), current->comm);
 
@@ -1353,10 +1362,12 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
        removed_mask = root->subsys_mask & ~opts.subsys_mask;
 
        /* Don't allow flags or name to change at remount */
-       if (opts.flags != root->flags ||
+       if (((opts.flags ^ root->flags) & CGRP_ROOT_OPTION_MASK) ||
            (opts.name && strcmp(opts.name, root->name))) {
+               pr_err("cgroup: option or name mismatch, new: 0x%lx \"%s\", old: 0x%lx \"%s\"\n",
+                      opts.flags & CGRP_ROOT_OPTION_MASK, opts.name ?: "",
+                      root->flags & CGRP_ROOT_OPTION_MASK, root->name);
                ret = -EINVAL;
-               drop_parsed_module_refcounts(opts.subsys_mask);
                goto out_unlock;
        }
 
@@ -1367,11 +1378,10 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
         */
        cgroup_clear_directory(cgrp->dentry, false, removed_mask);
 
-       ret = rebind_subsystems(root, opts.subsys_mask);
+       ret = rebind_subsystems(root, added_mask, removed_mask);
        if (ret) {
                /* rebind_subsystems failed, re-populate the removed files */
                cgroup_populate_dir(cgrp, false, removed_mask);
-               drop_parsed_module_refcounts(opts.subsys_mask);
                goto out_unlock;
        }
 
@@ -1386,6 +1396,8 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
        mutex_unlock(&cgroup_root_mutex);
        mutex_unlock(&cgroup_mutex);
        mutex_unlock(&cgrp->dentry->d_inode->i_mutex);
+       if (ret)
+               drop_parsed_module_refcounts(opts.subsys_mask);
        return ret;
 }
 
@@ -1401,11 +1413,9 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
        INIT_LIST_HEAD(&cgrp->sibling);
        INIT_LIST_HEAD(&cgrp->children);
        INIT_LIST_HEAD(&cgrp->files);
-       INIT_LIST_HEAD(&cgrp->css_sets);
-       INIT_LIST_HEAD(&cgrp->allcg_node);
+       INIT_LIST_HEAD(&cgrp->cset_links);
        INIT_LIST_HEAD(&cgrp->release_list);
        INIT_LIST_HEAD(&cgrp->pidlists);
-       INIT_WORK(&cgrp->free_work, cgroup_free_fn);
        mutex_init(&cgrp->pidlist_mutex);
        INIT_LIST_HEAD(&cgrp->event_list);
        spin_lock_init(&cgrp->event_list_lock);
@@ -1418,37 +1428,37 @@ static void init_cgroup_root(struct cgroupfs_root *root)
 
        INIT_LIST_HEAD(&root->subsys_list);
        INIT_LIST_HEAD(&root->root_list);
-       INIT_LIST_HEAD(&root->allcg_list);
        root->number_of_cgroups = 1;
        cgrp->root = root;
-       cgrp->name = &root_cgroup_name;
+       RCU_INIT_POINTER(cgrp->name, &root_cgroup_name);
        init_cgroup_housekeeping(cgrp);
-       list_add_tail(&cgrp->allcg_node, &root->allcg_list);
 }
 
-static bool init_root_id(struct cgroupfs_root *root)
+static int cgroup_init_root_id(struct cgroupfs_root *root, int start, int end)
 {
-       int ret = 0;
+       int id;
 
-       do {
-               if (!ida_pre_get(&hierarchy_ida, GFP_KERNEL))
-                       return false;
-               spin_lock(&hierarchy_id_lock);
-               /* Try to allocate the next unused ID */
-               ret = ida_get_new_above(&hierarchy_ida, next_hierarchy_id,
-                                       &root->hierarchy_id);
-               if (ret == -ENOSPC)
-                       /* Try again starting from 0 */
-                       ret = ida_get_new(&hierarchy_ida, &root->hierarchy_id);
-               if (!ret) {
-                       next_hierarchy_id = root->hierarchy_id + 1;
-               } else if (ret != -EAGAIN) {
-                       /* Can only get here if the 31-bit IDR is full ... */
-                       BUG_ON(ret);
-               }
-               spin_unlock(&hierarchy_id_lock);
-       } while (ret);
-       return true;
+       lockdep_assert_held(&cgroup_mutex);
+       lockdep_assert_held(&cgroup_root_mutex);
+
+       id = idr_alloc_cyclic(&cgroup_hierarchy_idr, root, start, end,
+                             GFP_KERNEL);
+       if (id < 0)
+               return id;
+
+       root->hierarchy_id = id;
+       return 0;
+}
+
+static void cgroup_exit_root_id(struct cgroupfs_root *root)
+{
+       lockdep_assert_held(&cgroup_mutex);
+       lockdep_assert_held(&cgroup_root_mutex);
+
+       if (root->hierarchy_id) {
+               idr_remove(&cgroup_hierarchy_idr, root->hierarchy_id);
+               root->hierarchy_id = 0;
+       }
 }
 
 static int cgroup_test_super(struct super_block *sb, void *data)
@@ -1482,12 +1492,16 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts)
        if (!root)
                return ERR_PTR(-ENOMEM);
 
-       if (!init_root_id(root)) {
-               kfree(root);
-               return ERR_PTR(-ENOMEM);
-       }
        init_cgroup_root(root);
 
+       /*
+        * We need to set @root->subsys_mask now so that @root can be
+        * matched by cgroup_test_super() before it finishes
+        * initialization; otherwise, competing mounts with the same
+        * options may try to bind the same subsystems instead of waiting
+        * for the first one leading to unexpected mount errors.
+        * SUBSYS_BOUND will be set once actual binding is complete.
+        */
        root->subsys_mask = opts->subsys_mask;
        root->flags = opts->flags;
        ida_init(&root->cgroup_ida);
@@ -1500,17 +1514,15 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts)
        return root;
 }
 
-static void cgroup_drop_root(struct cgroupfs_root *root)
+static void cgroup_free_root(struct cgroupfs_root *root)
 {
-       if (!root)
-               return;
+       if (root) {
+               /* hierarhcy ID shoulid already have been released */
+               WARN_ON_ONCE(root->hierarchy_id);
 
-       BUG_ON(!root->hierarchy_id);
-       spin_lock(&hierarchy_id_lock);
-       ida_remove(&hierarchy_ida, root->hierarchy_id);
-       spin_unlock(&hierarchy_id_lock);
-       ida_destroy(&root->cgroup_ida);
-       kfree(root);
+               ida_destroy(&root->cgroup_ida);
+               kfree(root);
+       }
 }
 
 static int cgroup_set_super(struct super_block *sb, void *data)
@@ -1597,7 +1609,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        sb = sget(fs_type, cgroup_test_super, cgroup_set_super, 0, &opts);
        if (IS_ERR(sb)) {
                ret = PTR_ERR(sb);
-               cgroup_drop_root(opts.new_root);
+               cgroup_free_root(opts.new_root);
                goto drop_modules;
        }
 
@@ -1605,12 +1617,12 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        BUG_ON(!root);
        if (root == opts.new_root) {
                /* We used the new root structure, so this is a new hierarchy */
-               struct list_head tmp_cg_links;
+               struct list_head tmp_links;
                struct cgroup *root_cgrp = &root->top_cgroup;
                struct cgroupfs_root *existing_root;
                const struct cred *cred;
                int i;
-               struct css_set *cg;
+               struct css_set *cset;
 
                BUG_ON(sb->s_root != NULL);
 
@@ -1637,13 +1649,18 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                 * that's us. The worst that can happen is that we
                 * have some link structures left over
                 */
-               ret = allocate_cg_links(css_set_count, &tmp_cg_links);
+               ret = allocate_cgrp_cset_links(css_set_count, &tmp_links);
                if (ret)
                        goto unlock_drop;
 
-               ret = rebind_subsystems(root, root->subsys_mask);
+               /* ID 0 is reserved for dummy root, 1 for unified hierarchy */
+               ret = cgroup_init_root_id(root, 2, 0);
+               if (ret)
+                       goto unlock_drop;
+
+               ret = rebind_subsystems(root, root->subsys_mask, 0);
                if (ret == -EBUSY) {
-                       free_cg_links(&tmp_cg_links);
+                       free_cgrp_cset_links(&tmp_links);
                        goto unlock_drop;
                }
                /*
@@ -1655,8 +1672,8 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                /* EBUSY should be the only error here */
                BUG_ON(ret);
 
-               list_add(&root->root_list, &roots);
-               root_count++;
+               list_add(&root->root_list, &cgroup_roots);
+               cgroup_root_count++;
 
                sb->s_root->d_fsdata = root_cgrp;
                root->top_cgroup.dentry = sb->s_root;
@@ -1664,11 +1681,11 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                /* Link the top cgroup in this hierarchy into all
                 * the css_set objects */
                write_lock(&css_set_lock);
-               hash_for_each(css_set_table, i, cg, hlist)
-                       link_css_set(&tmp_cg_links, cg, root_cgrp);
+               hash_for_each(css_set_table, i, cset, hlist)
+                       link_css_set(&tmp_links, cset, root_cgrp);
                write_unlock(&css_set_lock);
 
-               free_cg_links(&tmp_cg_links);
+               free_cgrp_cset_links(&tmp_links);
 
                BUG_ON(!list_empty(&root_cgrp->children));
                BUG_ON(root->number_of_cgroups != 1);
@@ -1684,9 +1701,9 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                 * We re-used an existing hierarchy - the new root (if
                 * any) is not needed
                 */
-               cgroup_drop_root(opts.new_root);
+               cgroup_free_root(opts.new_root);
 
-               if (root->flags != opts.flags) {
+               if ((root->flags ^ opts.flags) & CGRP_ROOT_OPTION_MASK) {
                        if ((root->flags | opts.flags) & CGRP_ROOT_SANE_BEHAVIOR) {
                                pr_err("cgroup: sane_behavior: new mount options should match the existing superblock\n");
                                ret = -EINVAL;
@@ -1705,6 +1722,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        return dget(sb->s_root);
 
  unlock_drop:
+       cgroup_exit_root_id(root);
        mutex_unlock(&cgroup_root_mutex);
        mutex_unlock(&cgroup_mutex);
        mutex_unlock(&inode->i_mutex);
@@ -1721,9 +1739,8 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
 static void cgroup_kill_sb(struct super_block *sb) {
        struct cgroupfs_root *root = sb->s_fs_info;
        struct cgroup *cgrp = &root->top_cgroup;
+       struct cgrp_cset_link *link, *tmp_link;
        int ret;
-       struct cg_cgroup_link *link;
-       struct cg_cgroup_link *saved_link;
 
        BUG_ON(!root);
 
@@ -1734,36 +1751,39 @@ static void cgroup_kill_sb(struct super_block *sb) {
        mutex_lock(&cgroup_root_mutex);
 
        /* Rebind all subsystems back to the default hierarchy */
-       ret = rebind_subsystems(root, 0);
-       /* Shouldn't be able to fail ... */
-       BUG_ON(ret);
+       if (root->flags & CGRP_ROOT_SUBSYS_BOUND) {
+               ret = rebind_subsystems(root, 0, root->subsys_mask);
+               /* Shouldn't be able to fail ... */
+               BUG_ON(ret);
+       }
 
        /*
-        * Release all the links from css_sets to this hierarchy's
+        * Release all the links from cset_links to this hierarchy's
         * root cgroup
         */
        write_lock(&css_set_lock);
 
-       list_for_each_entry_safe(link, saved_link, &cgrp->css_sets,
-                                cgrp_link_list) {
-               list_del(&link->cg_link_list);
-               list_del(&link->cgrp_link_list);
+       list_for_each_entry_safe(link, tmp_link, &cgrp->cset_links, cset_link) {
+               list_del(&link->cset_link);
+               list_del(&link->cgrp_link);
                kfree(link);
        }
        write_unlock(&css_set_lock);
 
        if (!list_empty(&root->root_list)) {
                list_del(&root->root_list);
-               root_count--;
+               cgroup_root_count--;
        }
 
+       cgroup_exit_root_id(root);
+
        mutex_unlock(&cgroup_root_mutex);
        mutex_unlock(&cgroup_mutex);
 
        simple_xattrs_free(&cgrp->xattrs);
 
        kill_litter_super(sb);
-       cgroup_drop_root(root);
+       cgroup_free_root(root);
 }
 
 static struct file_system_type cgroup_fs_type = {
@@ -1825,6 +1845,38 @@ out:
 }
 EXPORT_SYMBOL_GPL(cgroup_path);
 
+/**
+ * task_cgroup_path_from_hierarchy - cgroup path of a task on a hierarchy
+ * @task: target task
+ * @hierarchy_id: the hierarchy to look up @task's cgroup from
+ * @buf: the buffer to write the path into
+ * @buflen: the length of the buffer
+ *
+ * Determine @task's cgroup on the hierarchy specified by @hierarchy_id and
+ * copy its path into @buf.  This function grabs cgroup_mutex and shouldn't
+ * be used inside locks used by cgroup controller callbacks.
+ */
+int task_cgroup_path_from_hierarchy(struct task_struct *task, int hierarchy_id,
+                                   char *buf, size_t buflen)
+{
+       struct cgroupfs_root *root;
+       struct cgroup *cgrp = NULL;
+       int ret = -ENOENT;
+
+       mutex_lock(&cgroup_mutex);
+
+       root = idr_find(&cgroup_hierarchy_idr, hierarchy_id);
+       if (root) {
+               cgrp = task_cgroup_from_root(task, root);
+               ret = cgroup_path(cgrp, buf, buflen);
+       }
+
+       mutex_unlock(&cgroup_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(task_cgroup_path_from_hierarchy);
+
 /*
  * Control Group taskset
  */
@@ -1910,10 +1962,11 @@ EXPORT_SYMBOL_GPL(cgroup_taskset_size);
  *
  * Must be called with cgroup_mutex and threadgroup locked.
  */
-static void cgroup_task_migrate(struct cgroup *oldcgrp,
-                               struct task_struct *tsk, struct css_set *newcg)
+static void cgroup_task_migrate(struct cgroup *old_cgrp,
+                               struct task_struct *tsk,
+                               struct css_set *new_cset)
 {
-       struct css_set *oldcg;
+       struct css_set *old_cset;
 
        /*
         * We are synchronized through threadgroup_lock() against PF_EXITING
@@ -1921,25 +1974,25 @@ static void cgroup_task_migrate(struct cgroup *oldcgrp,
         * css_set to init_css_set and dropping the old one.
         */
        WARN_ON_ONCE(tsk->flags & PF_EXITING);
-       oldcg = tsk->cgroups;
+       old_cset = task_css_set(tsk);
 
        task_lock(tsk);
-       rcu_assign_pointer(tsk->cgroups, newcg);
+       rcu_assign_pointer(tsk->cgroups, new_cset);
        task_unlock(tsk);
 
        /* Update the css_set linked lists if we're using them */
        write_lock(&css_set_lock);
        if (!list_empty(&tsk->cg_list))
-               list_move(&tsk->cg_list, &newcg->tasks);
+               list_move(&tsk->cg_list, &new_cset->tasks);
        write_unlock(&css_set_lock);
 
        /*
-        * We just gained a reference on oldcg by taking it from the task. As
-        * trading it for newcg is protected by cgroup_mutex, we're safe to drop
-        * it here; it will be freed under RCU.
+        * We just gained a reference on old_cset by taking it from the
+        * task. As trading it for new_cset is protected by cgroup_mutex,
+        * we're safe to drop it here; it will be freed under RCU.
         */
-       set_bit(CGRP_RELEASABLE, &oldcgrp->flags);
-       put_css_set(oldcg);
+       set_bit(CGRP_RELEASABLE, &old_cgrp->flags);
+       put_css_set(old_cset);
 }
 
 /**
@@ -2029,7 +2082,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
        /*
         * step 1: check that we can legitimately attach to the cgroup.
         */
-       for_each_subsys(root, ss) {
+       for_each_root_subsys(root, ss) {
                if (ss->can_attach) {
                        retval = ss->can_attach(cgrp, &tset);
                        if (retval) {
@@ -2044,8 +2097,11 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
         * we use find_css_set, which allocates a new one if necessary.
         */
        for (i = 0; i < group_size; i++) {
+               struct css_set *old_cset;
+
                tc = flex_array_get(group, i);
-               tc->cg = find_css_set(tc->task->cgroups, cgrp);
+               old_cset = task_css_set(tc->task);
+               tc->cg = find_css_set(old_cset, cgrp);
                if (!tc->cg) {
                        retval = -ENOMEM;
                        goto out_put_css_set_refs;
@@ -2066,7 +2122,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
        /*
         * step 4: do subsystem attach callbacks.
         */
-       for_each_subsys(root, ss) {
+       for_each_root_subsys(root, ss) {
                if (ss->attach)
                        ss->attach(cgrp, &tset);
        }
@@ -2086,7 +2142,7 @@ out_put_css_set_refs:
        }
 out_cancel_attach:
        if (retval) {
-               for_each_subsys(root, ss) {
+               for_each_root_subsys(root, ss) {
                        if (ss == failed_ss)
                                break;
                        if (ss->cancel_attach)
@@ -2323,7 +2379,7 @@ static ssize_t cgroup_file_write(struct file *file, const char __user *buf,
        struct cftype *cft = __d_cft(file->f_dentry);
        struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
 
-       if (cgroup_is_removed(cgrp))
+       if (cgroup_is_dead(cgrp))
                return -ENODEV;
        if (cft->write)
                return cft->write(cgrp, cft, file, buf, nbytes, ppos);
@@ -2368,7 +2424,7 @@ static ssize_t cgroup_file_read(struct file *file, char __user *buf,
        struct cftype *cft = __d_cft(file->f_dentry);
        struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
 
-       if (cgroup_is_removed(cgrp))
+       if (cgroup_is_dead(cgrp))
                return -ENODEV;
 
        if (cft->read)
@@ -2435,10 +2491,12 @@ static int cgroup_file_open(struct inode *inode, struct file *file)
        cft = __d_cft(file->f_dentry);
 
        if (cft->read_map || cft->read_seq_string) {
-               struct cgroup_seqfile_state *state =
-                       kzalloc(sizeof(*state), GFP_USER);
+               struct cgroup_seqfile_state *state;
+
+               state = kzalloc(sizeof(*state), GFP_USER);
                if (!state)
                        return -ENOMEM;
+
                state->cft = cft;
                state->cgroup = __d_cgrp(file->f_dentry->d_parent);
                file->f_op = &cgroup_seqfile_operations;
@@ -2486,6 +2544,13 @@ static int cgroup_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        cgrp = __d_cgrp(old_dentry);
 
+       /*
+        * This isn't a proper migration and its usefulness is very
+        * limited.  Disallow if sane_behavior.
+        */
+       if (cgroup_sane_behavior(cgrp))
+               return -EPERM;
+
        name = cgroup_alloc_name(new_dentry);
        if (!name)
                return -ENOMEM;
@@ -2496,7 +2561,7 @@ static int cgroup_rename(struct inode *old_dir, struct dentry *old_dentry,
                return ret;
        }
 
-       old_name = cgrp->name;
+       old_name = rcu_dereference_protected(cgrp->name, true);
        rcu_assign_pointer(cgrp->name, name);
 
        kfree_rcu(old_name, rcu_head);
@@ -2747,58 +2812,78 @@ static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
        return ret;
 }
 
-static DEFINE_MUTEX(cgroup_cft_mutex);
-
 static void cgroup_cfts_prepare(void)
-       __acquires(&cgroup_cft_mutex) __acquires(&cgroup_mutex)
+       __acquires(&cgroup_mutex)
 {
        /*
         * Thanks to the entanglement with vfs inode locking, we can't walk
         * the existing cgroups under cgroup_mutex and create files.
-        * Instead, we increment reference on all cgroups and build list of
-        * them using @cgrp->cft_q_node.  Grab cgroup_cft_mutex to ensure
-        * exclusive access to the field.
+        * Instead, we use cgroup_for_each_descendant_pre() and drop RCU
+        * read lock before calling cgroup_addrm_files().
         */
-       mutex_lock(&cgroup_cft_mutex);
        mutex_lock(&cgroup_mutex);
 }
 
 static void cgroup_cfts_commit(struct cgroup_subsys *ss,
                               struct cftype *cfts, bool is_add)
-       __releases(&cgroup_mutex) __releases(&cgroup_cft_mutex)
+       __releases(&cgroup_mutex)
 {
        LIST_HEAD(pending);
-       struct cgroup *cgrp, *n;
+       struct cgroup *cgrp, *root = &ss->root->top_cgroup;
+       struct super_block *sb = ss->root->sb;
+       struct dentry *prev = NULL;
+       struct inode *inode;
+       u64 update_before;
 
        /* %NULL @cfts indicates abort and don't bother if @ss isn't attached */
-       if (cfts && ss->root != &rootnode) {
-               list_for_each_entry(cgrp, &ss->root->allcg_list, allcg_node) {
-                       dget(cgrp->dentry);
-                       list_add_tail(&cgrp->cft_q_node, &pending);
-               }
+       if (!cfts || ss->root == &cgroup_dummy_root ||
+           !atomic_inc_not_zero(&sb->s_active)) {
+               mutex_unlock(&cgroup_mutex);
+               return;
        }
 
-       mutex_unlock(&cgroup_mutex);
-
        /*
-        * All new cgroups will see @cfts update on @ss->cftsets.  Add/rm
-        * files for all cgroups which were created before.
+        * All cgroups which are created after we drop cgroup_mutex will
+        * have the updated set of files, so we only need to update the
+        * cgroups created before the current @cgroup_serial_nr_next.
         */
-       list_for_each_entry_safe(cgrp, n, &pending, cft_q_node) {
-               struct inode *inode = cgrp->dentry->d_inode;
+       update_before = cgroup_serial_nr_next;
+
+       mutex_unlock(&cgroup_mutex);
+
+       /* @root always needs to be updated */
+       inode = root->dentry->d_inode;
+       mutex_lock(&inode->i_mutex);
+       mutex_lock(&cgroup_mutex);
+       cgroup_addrm_files(root, ss, cfts, is_add);
+       mutex_unlock(&cgroup_mutex);
+       mutex_unlock(&inode->i_mutex);
+
+       /* add/rm files for all cgroups created before */
+       rcu_read_lock();
+       cgroup_for_each_descendant_pre(cgrp, root) {
+               if (cgroup_is_dead(cgrp))
+                       continue;
+
+               inode = cgrp->dentry->d_inode;
+               dget(cgrp->dentry);
+               rcu_read_unlock();
+
+               dput(prev);
+               prev = cgrp->dentry;
 
                mutex_lock(&inode->i_mutex);
                mutex_lock(&cgroup_mutex);
-               if (!cgroup_is_removed(cgrp))
+               if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp))
                        cgroup_addrm_files(cgrp, ss, cfts, is_add);
                mutex_unlock(&cgroup_mutex);
                mutex_unlock(&inode->i_mutex);
 
-               list_del_init(&cgrp->cft_q_node);
-               dput(cgrp->dentry);
+               rcu_read_lock();
        }
-
-       mutex_unlock(&cgroup_cft_mutex);
+       rcu_read_unlock();
+       dput(prev);
+       deactivate_super(sb);
 }
 
 /**
@@ -2853,7 +2938,8 @@ int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
 
        list_for_each_entry(set, &ss->cftsets, node) {
                if (set->cfts == cfts) {
-                       list_del_init(&set->node);
+                       list_del(&set->node);
+                       kfree(set);
                        cgroup_cfts_commit(ss, cfts, false);
                        return 0;
                }
@@ -2872,12 +2958,11 @@ int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
 int cgroup_task_count(const struct cgroup *cgrp)
 {
        int count = 0;
-       struct cg_cgroup_link *link;
+       struct cgrp_cset_link *link;
 
        read_lock(&css_set_lock);
-       list_for_each_entry(link, &cgrp->css_sets, cgrp_link_list) {
-               count += atomic_read(&link->cg->refcount);
-       }
+       list_for_each_entry(link, &cgrp->cset_links, cset_link)
+               count += atomic_read(&link->cset->refcount);
        read_unlock(&css_set_lock);
        return count;
 }
@@ -2886,25 +2971,24 @@ int cgroup_task_count(const struct cgroup *cgrp)
  * Advance a list_head iterator.  The iterator should be positioned at
  * the start of a css_set
  */
-static void cgroup_advance_iter(struct cgroup *cgrp,
-                               struct cgroup_iter *it)
+static void cgroup_advance_iter(struct cgroup *cgrp, struct cgroup_iter *it)
 {
-       struct list_head *l = it->cg_link;
-       struct cg_cgroup_link *link;
-       struct css_set *cg;
+       struct list_head *l = it->cset_link;
+       struct cgrp_cset_link *link;
+       struct css_set *cset;
 
        /* Advance to the next non-empty css_set */
        do {
                l = l->next;
-               if (l == &cgrp->css_sets) {
-                       it->cg_link = NULL;
+               if (l == &cgrp->cset_links) {
+                       it->cset_link = NULL;
                        return;
                }
-               link = list_entry(l, struct cg_cgroup_link, cgrp_link_list);
-               cg = link->cg;
-       } while (list_empty(&cg->tasks));
-       it->cg_link = l;
-       it->task = cg->tasks.next;
+               link = list_entry(l, struct cgrp_cset_link, cset_link);
+               cset = link->cset;
+       } while (list_empty(&cset->tasks));
+       it->cset_link = l;
+       it->task = cset->tasks.next;
 }
 
 /*
@@ -2934,13 +3018,63 @@ static void cgroup_enable_task_cg_lists(void)
                 * entry won't be deleted though the process has exited.
                 */
                if (!(p->flags & PF_EXITING) && list_empty(&p->cg_list))
-                       list_add(&p->cg_list, &p->cgroups->tasks);
+                       list_add(&p->cg_list, &task_css_set(p)->tasks);
                task_unlock(p);
        } while_each_thread(g, p);
        read_unlock(&tasklist_lock);
        write_unlock(&css_set_lock);
 }
 
+/**
+ * cgroup_next_sibling - find the next sibling of a given cgroup
+ * @pos: the current cgroup
+ *
+ * This function returns the next sibling of @pos and should be called
+ * under RCU read lock.  The only requirement is that @pos is accessible.
+ * The next sibling is guaranteed to be returned regardless of @pos's
+ * state.
+ */
+struct cgroup *cgroup_next_sibling(struct cgroup *pos)
+{
+       struct cgroup *next;
+
+       WARN_ON_ONCE(!rcu_read_lock_held());
+
+       /*
+        * @pos could already have been removed.  Once a cgroup is removed,
+        * its ->sibling.next is no longer updated when its next sibling
+        * changes.  As CGRP_DEAD assertion is serialized and happens
+        * before the cgroup is taken off the ->sibling list, if we see it
+        * unasserted, it's guaranteed that the next sibling hasn't
+        * finished its grace period even if it's already removed, and thus
+        * safe to dereference from this RCU critical section.  If
+        * ->sibling.next is inaccessible, cgroup_is_dead() is guaranteed
+        * to be visible as %true here.
+        */
+       if (likely(!cgroup_is_dead(pos))) {
+               next = list_entry_rcu(pos->sibling.next, struct cgroup, sibling);
+               if (&next->sibling != &pos->parent->children)
+                       return next;
+               return NULL;
+       }
+
+       /*
+        * Can't dereference the next pointer.  Each cgroup is given a
+        * monotonically increasing unique serial number and always
+        * appended to the sibling list, so the next one can be found by
+        * walking the parent's children until we see a cgroup with higher
+        * serial number than @pos's.
+        *
+        * While this path can be slow, it's taken only when either the
+        * current cgroup is removed or iteration and removal race.
+        */
+       list_for_each_entry_rcu(next, &pos->parent->children, sibling)
+               if (next->serial_nr > pos->serial_nr)
+                       return next;
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(cgroup_next_sibling);
+
 /**
  * cgroup_next_descendant_pre - find the next descendant for pre-order walk
  * @pos: the current position (%NULL to initiate traversal)
@@ -2948,6 +3082,11 @@ static void cgroup_enable_task_cg_lists(void)
  *
  * To be used by cgroup_for_each_descendant_pre().  Find the next
  * descendant to visit for pre-order traversal of @cgroup's descendants.
+ *
+ * While this function requires RCU read locking, it doesn't require the
+ * whole traversal to be contained in a single RCU critical section.  This
+ * function will return the correct next descendant as long as both @pos
+ * and @cgroup are accessible and @pos is a descendant of @cgroup.
  */
 struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
                                          struct cgroup *cgroup)
@@ -2967,11 +3106,9 @@ struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
 
        /* no child, visit my or the closest ancestor's next sibling */
        while (pos != cgroup) {
-               next = list_entry_rcu(pos->sibling.next, struct cgroup,
-                                     sibling);
-               if (&next->sibling != &pos->parent->children)
+               next = cgroup_next_sibling(pos);
+               if (next)
                        return next;
-
                pos = pos->parent;
        }
 
@@ -2986,6 +3123,11 @@ EXPORT_SYMBOL_GPL(cgroup_next_descendant_pre);
  * Return the rightmost descendant of @pos.  If there's no descendant,
  * @pos is returned.  This can be used during pre-order traversal to skip
  * subtree of @pos.
+ *
+ * While this function requires RCU read locking, it doesn't require the
+ * whole traversal to be contained in a single RCU critical section.  This
+ * function will return the correct rightmost descendant as long as @pos is
+ * accessible.
  */
 struct cgroup *cgroup_rightmost_descendant(struct cgroup *pos)
 {
@@ -3025,6 +3167,11 @@ static struct cgroup *cgroup_leftmost_descendant(struct cgroup *pos)
  *
  * To be used by cgroup_for_each_descendant_post().  Find the next
  * descendant to visit for post-order traversal of @cgroup's descendants.
+ *
+ * While this function requires RCU read locking, it doesn't require the
+ * whole traversal to be contained in a single RCU critical section.  This
+ * function will return the correct next descendant as long as both @pos
+ * and @cgroup are accessible and @pos is a descendant of @cgroup.
  */
 struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
                                           struct cgroup *cgroup)
@@ -3040,8 +3187,8 @@ struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
        }
 
        /* if there's an unvisited sibling, visit its leftmost descendant */
-       next = list_entry_rcu(pos->sibling.next, struct cgroup, sibling);
-       if (&next->sibling != &pos->parent->children)
+       next = cgroup_next_sibling(pos);
+       if (next)
                return cgroup_leftmost_descendant(next);
 
        /* no sibling left, visit parent */
@@ -3062,7 +3209,7 @@ void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it)
                cgroup_enable_task_cg_lists();
 
        read_lock(&css_set_lock);
-       it->cg_link = &cgrp->css_sets;
+       it->cset_link = &cgrp->cset_links;
        cgroup_advance_iter(cgrp, it);
 }
 
@@ -3071,16 +3218,16 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp,
 {
        struct task_struct *res;
        struct list_head *l = it->task;
-       struct cg_cgroup_link *link;
+       struct cgrp_cset_link *link;
 
        /* If the iterator cg is NULL, we have no tasks */
-       if (!it->cg_link)
+       if (!it->cset_link)
                return NULL;
        res = list_entry(l, struct task_struct, cg_list);
        /* Advance iterator to find next entry */
        l = l->next;
-       link = list_entry(it->cg_link, struct cg_cgroup_link, cgrp_link_list);
-       if (l == &link->cg->tasks) {
+       link = list_entry(it->cset_link, struct cgrp_cset_link, cset_link);
+       if (l == &link->cset->tasks) {
                /* We reached the end of this task list - move on to
                 * the next cg_cgroup_link */
                cgroup_advance_iter(cgrp, it);
@@ -3411,7 +3558,7 @@ static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp,
                }
        }
        /* entry not found; create a new one */
-       l = kmalloc(sizeof(struct cgroup_pidlist), GFP_KERNEL);
+       l = kzalloc(sizeof(struct cgroup_pidlist), GFP_KERNEL);
        if (!l) {
                mutex_unlock(&cgrp->pidlist_mutex);
                return l;
@@ -3420,8 +3567,6 @@ static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp,
        down_write(&l->mutex);
        l->key.type = type;
        l->key.ns = get_pid_ns(ns);
-       l->use_count = 0; /* don't increment here */
-       l->list = NULL;
        l->owner = cgrp;
        list_add(&l->links, &cgrp->pidlists);
        mutex_unlock(&cgrp->pidlist_mutex);
@@ -3726,6 +3871,23 @@ static int cgroup_write_notify_on_release(struct cgroup *cgrp,
        return 0;
 }
 
+/*
+ * When dput() is called asynchronously, if umount has been done and
+ * then deactivate_super() in cgroup_free_fn() kills the superblock,
+ * there's a small window that vfs will see the root dentry with non-zero
+ * refcnt and trigger BUG().
+ *
+ * That's why we hold a reference before dput() and drop it right after.
+ */
+static void cgroup_dput(struct cgroup *cgrp)
+{
+       struct super_block *sb = cgrp->root->sb;
+
+       atomic_inc(&sb->s_active);
+       dput(cgrp->dentry);
+       deactivate_super(sb);
+}
+
 /*
  * Unregister event and free resources.
  *
@@ -3746,7 +3908,7 @@ static void cgroup_event_remove(struct work_struct *work)
 
        eventfd_ctx_put(event->eventfd);
        kfree(event);
-       dput(cgrp->dentry);
+       cgroup_dput(cgrp);
 }
 
 /*
@@ -3933,33 +4095,16 @@ static int cgroup_clone_children_write(struct cgroup *cgrp,
        return 0;
 }
 
-/*
- * for the common functions, 'private' gives the type of file
- */
-/* for hysterical raisins, we can't put this on the older files */
-#define CGROUP_FILE_GENERIC_PREFIX "cgroup."
-static struct cftype files[] = {
-       {
-               .name = "tasks",
-               .open = cgroup_tasks_open,
-               .write_u64 = cgroup_tasks_write,
-               .release = cgroup_pidlist_release,
-               .mode = S_IRUGO | S_IWUSR,
-       },
+static struct cftype cgroup_base_files[] = {
        {
-               .name = CGROUP_FILE_GENERIC_PREFIX "procs",
+               .name = "cgroup.procs",
                .open = cgroup_procs_open,
                .write_u64 = cgroup_procs_write,
                .release = cgroup_pidlist_release,
                .mode = S_IRUGO | S_IWUSR,
        },
        {
-               .name = "notify_on_release",
-               .read_u64 = cgroup_read_notify_on_release,
-               .write_u64 = cgroup_write_notify_on_release,
-       },
-       {
-               .name = CGROUP_FILE_GENERIC_PREFIX "event_control",
+               .name = "cgroup.event_control",
                .write_string = cgroup_write_event_control,
                .mode = S_IWUGO,
        },
@@ -3974,9 +4119,29 @@ static struct cftype files[] = {
                .flags = CFTYPE_ONLY_ON_ROOT,
                .read_seq_string = cgroup_sane_behavior_show,
        },
+
+       /*
+        * Historical crazy stuff.  These don't have "cgroup."  prefix and
+        * don't exist if sane_behavior.  If you're depending on these, be
+        * prepared to be burned.
+        */
+       {
+               .name = "tasks",
+               .flags = CFTYPE_INSANE,         /* use "procs" instead */
+               .open = cgroup_tasks_open,
+               .write_u64 = cgroup_tasks_write,
+               .release = cgroup_pidlist_release,
+               .mode = S_IRUGO | S_IWUSR,
+       },
+       {
+               .name = "notify_on_release",
+               .flags = CFTYPE_INSANE,
+               .read_u64 = cgroup_read_notify_on_release,
+               .write_u64 = cgroup_write_notify_on_release,
+       },
        {
                .name = "release_agent",
-               .flags = CFTYPE_ONLY_ON_ROOT,
+               .flags = CFTYPE_INSANE | CFTYPE_ONLY_ON_ROOT,
                .read_seq_string = cgroup_release_agent_show,
                .write_string = cgroup_release_agent_write,
                .max_write_len = PATH_MAX,
@@ -3997,13 +4162,13 @@ static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files,
        struct cgroup_subsys *ss;
 
        if (base_files) {
-               err = cgroup_addrm_files(cgrp, NULL, files, true);
+               err = cgroup_addrm_files(cgrp, NULL, cgroup_base_files, true);
                if (err < 0)
                        return err;
        }
 
        /* process cftsets of each subsystem */
-       for_each_subsys(cgrp->root, ss) {
+       for_each_root_subsys(cgrp->root, ss) {
                struct cftype_set *set;
                if (!test_bit(ss->subsys_id, &subsys_mask))
                        continue;
@@ -4013,15 +4178,17 @@ static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files,
        }
 
        /* This cgroup is ready now */
-       for_each_subsys(cgrp->root, ss) {
+       for_each_root_subsys(cgrp->root, ss) {
                struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
+               struct css_id *id = rcu_dereference_protected(css->id, true);
+
                /*
                 * Update id->css pointer and make this css visible from
                 * CSS ID functions. This pointer will be dereferened
                 * from RCU-read-side without locks.
                 */
-               if (css->id)
-                       rcu_assign_pointer(css->id->css, css);
+               if (id)
+                       rcu_assign_pointer(id->css, css);
        }
 
        return 0;
@@ -4031,12 +4198,16 @@ static void css_dput_fn(struct work_struct *work)
 {
        struct cgroup_subsys_state *css =
                container_of(work, struct cgroup_subsys_state, dput_work);
-       struct dentry *dentry = css->cgroup->dentry;
-       struct super_block *sb = dentry->d_sb;
 
-       atomic_inc(&sb->s_active);
-       dput(dentry);
-       deactivate_super(sb);
+       cgroup_dput(css->cgroup);
+}
+
+static void css_release(struct percpu_ref *ref)
+{
+       struct cgroup_subsys_state *css =
+               container_of(ref, struct cgroup_subsys_state, refcnt);
+
+       schedule_work(&css->dput_work);
 }
 
 static void init_cgroup_css(struct cgroup_subsys_state *css,
@@ -4044,10 +4215,9 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
                               struct cgroup *cgrp)
 {
        css->cgroup = cgrp;
-       atomic_set(&css->refcnt, 1);
        css->flags = 0;
        css->id = NULL;
-       if (cgrp == dummytop)
+       if (cgrp == cgroup_dummy_top)
                css->flags |= CSS_ROOT;
        BUG_ON(cgrp->subsys[ss->subsys_id]);
        cgrp->subsys[ss->subsys_id] = css;
@@ -4157,7 +4327,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
        if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &parent->flags))
                set_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags);
 
-       for_each_subsys(root, ss) {
+       for_each_root_subsys(root, ss) {
                struct cgroup_subsys_state *css;
 
                css = ss->css_alloc(cgrp);
@@ -4165,7 +4335,13 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                        err = PTR_ERR(css);
                        goto err_free_all;
                }
+
+               err = percpu_ref_init(&css->refcnt, css_release);
+               if (err)
+                       goto err_free_all;
+
                init_cgroup_css(css, ss, cgrp);
+
                if (ss->use_id) {
                        err = alloc_css_id(ss, parent, cgrp);
                        if (err)
@@ -4183,20 +4359,21 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                goto err_free_all;
        lockdep_assert_held(&dentry->d_inode->i_mutex);
 
+       cgrp->serial_nr = cgroup_serial_nr_next++;
+
        /* allocation complete, commit to creation */
-       list_add_tail(&cgrp->allcg_node, &root->allcg_list);
        list_add_tail_rcu(&cgrp->sibling, &cgrp->parent->children);
        root->number_of_cgroups++;
 
        /* each css holds a ref to the cgroup's dentry */
-       for_each_subsys(root, ss)
+       for_each_root_subsys(root, ss)
                dget(dentry);
 
        /* hold a ref to the parent's dentry */
        dget(parent->dentry);
 
        /* creation succeeded, notify subsystems */
-       for_each_subsys(root, ss) {
+       for_each_root_subsys(root, ss) {
                err = online_css(ss, cgrp);
                if (err)
                        goto err_destroy;
@@ -4221,9 +4398,13 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
        return 0;
 
 err_free_all:
-       for_each_subsys(root, ss) {
-               if (cgrp->subsys[ss->subsys_id])
+       for_each_root_subsys(root, ss) {
+               struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
+
+               if (css) {
+                       percpu_ref_cancel_init(&css->refcnt);
                        ss->css_free(cgrp);
+               }
        }
        mutex_unlock(&cgroup_mutex);
        /* Release the reference count that we took on the superblock */
@@ -4251,63 +4432,120 @@ static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        return cgroup_create(c_parent, dentry, mode | S_IFDIR);
 }
 
+static void cgroup_css_killed(struct cgroup *cgrp)
+{
+       if (!atomic_dec_and_test(&cgrp->css_kill_cnt))
+               return;
+
+       /* percpu ref's of all css's are killed, kick off the next step */
+       INIT_WORK(&cgrp->destroy_work, cgroup_offline_fn);
+       schedule_work(&cgrp->destroy_work);
+}
+
+static void css_ref_killed_fn(struct percpu_ref *ref)
+{
+       struct cgroup_subsys_state *css =
+               container_of(ref, struct cgroup_subsys_state, refcnt);
+
+       cgroup_css_killed(css->cgroup);
+}
+
+/**
+ * cgroup_destroy_locked - the first stage of cgroup destruction
+ * @cgrp: cgroup to be destroyed
+ *
+ * css's make use of percpu refcnts whose killing latency shouldn't be
+ * exposed to userland and are RCU protected.  Also, cgroup core needs to
+ * guarantee that css_tryget() won't succeed by the time ->css_offline() is
+ * invoked.  To satisfy all the requirements, destruction is implemented in
+ * the following two steps.
+ *
+ * s1. Verify @cgrp can be destroyed and mark it dying.  Remove all
+ *     userland visible parts and start killing the percpu refcnts of
+ *     css's.  Set up so that the next stage will be kicked off once all
+ *     the percpu refcnts are confirmed to be killed.
+ *
+ * s2. Invoke ->css_offline(), mark the cgroup dead and proceed with the
+ *     rest of destruction.  Once all cgroup references are gone, the
+ *     cgroup is RCU-freed.
+ *
+ * This function implements s1.  After this step, @cgrp is gone as far as
+ * the userland is concerned and a new cgroup with the same name may be
+ * created.  As cgroup doesn't care about the names internally, this
+ * doesn't cause any problem.
+ */
 static int cgroup_destroy_locked(struct cgroup *cgrp)
        __releases(&cgroup_mutex) __acquires(&cgroup_mutex)
 {
        struct dentry *d = cgrp->dentry;
-       struct cgroup *parent = cgrp->parent;
        struct cgroup_event *event, *tmp;
        struct cgroup_subsys *ss;
+       bool empty;
 
        lockdep_assert_held(&d->d_inode->i_mutex);
        lockdep_assert_held(&cgroup_mutex);
 
-       if (atomic_read(&cgrp->count) || !list_empty(&cgrp->children))
+       /*
+        * css_set_lock synchronizes access to ->cset_links and prevents
+        * @cgrp from being removed while __put_css_set() is in progress.
+        */
+       read_lock(&css_set_lock);
+       empty = list_empty(&cgrp->cset_links) && list_empty(&cgrp->children);
+       read_unlock(&css_set_lock);
+       if (!empty)
                return -EBUSY;
 
        /*
-        * Block new css_tryget() by deactivating refcnt and mark @cgrp
-        * removed.  This makes future css_tryget() and child creation
-        * attempts fail thus maintaining the removal conditions verified
-        * above.
+        * Block new css_tryget() by killing css refcnts.  cgroup core
+        * guarantees that, by the time ->css_offline() is invoked, no new
+        * css reference will be given out via css_tryget().  We can't
+        * simply call percpu_ref_kill() and proceed to offlining css's
+        * because percpu_ref_kill() doesn't guarantee that the ref is seen
+        * as killed on all CPUs on return.
+        *
+        * Use percpu_ref_kill_and_confirm() to get notifications as each
+        * css is confirmed to be seen as killed on all CPUs.  The
+        * notification callback keeps track of the number of css's to be
+        * killed and schedules cgroup_offline_fn() to perform the rest of
+        * destruction once the percpu refs of all css's are confirmed to
+        * be killed.
         */
-       for_each_subsys(cgrp->root, ss) {
+       atomic_set(&cgrp->css_kill_cnt, 1);
+       for_each_root_subsys(cgrp->root, ss) {
                struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
 
-               WARN_ON(atomic_read(&css->refcnt) < 0);
-               atomic_add(CSS_DEACT_BIAS, &css->refcnt);
-       }
-       set_bit(CGRP_REMOVED, &cgrp->flags);
+               /*
+                * Killing would put the base ref, but we need to keep it
+                * alive until after ->css_offline.
+                */
+               percpu_ref_get(&css->refcnt);
 
-       /* tell subsystems to initate destruction */
-       for_each_subsys(cgrp->root, ss)
-               offline_css(ss, cgrp);
+               atomic_inc(&cgrp->css_kill_cnt);
+               percpu_ref_kill_and_confirm(&css->refcnt, css_ref_killed_fn);
+       }
+       cgroup_css_killed(cgrp);
 
        /*
-        * Put all the base refs.  Each css holds an extra reference to the
-        * cgroup's dentry and cgroup removal proceeds regardless of css
-        * refs.  On the last put of each css, whenever that may be, the
-        * extra dentry ref is put so that dentry destruction happens only
-        * after all css's are released.
+        * Mark @cgrp dead.  This prevents further task migration and child
+        * creation by disabling cgroup_lock_live_group().  Note that
+        * CGRP_DEAD assertion is depended upon by cgroup_next_sibling() to
+        * resume iteration after dropping RCU read lock.  See
+        * cgroup_next_sibling() for details.
         */
-       for_each_subsys(cgrp->root, ss)
-               css_put(cgrp->subsys[ss->subsys_id]);
+       set_bit(CGRP_DEAD, &cgrp->flags);
 
+       /* CGRP_DEAD is set, remove from ->release_list for the last time */
        raw_spin_lock(&release_list_lock);
        if (!list_empty(&cgrp->release_list))
                list_del_init(&cgrp->release_list);
        raw_spin_unlock(&release_list_lock);
 
-       /* delete this cgroup from parent->children */
-       list_del_rcu(&cgrp->sibling);
-       list_del_init(&cgrp->allcg_node);
-
+       /*
+        * Remove @cgrp directory.  The removal puts the base ref but we
+        * aren't quite done with @cgrp yet, so hold onto it.
+        */
        dget(d);
        cgroup_d_remove_dir(d);
-       dput(d);
-
-       set_bit(CGRP_RELEASABLE, &parent->flags);
-       check_for_release(parent);
 
        /*
         * Unregister events and notify userspace.
@@ -4322,6 +4560,53 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
        spin_unlock(&cgrp->event_list_lock);
 
        return 0;
+};
+
+/**
+ * cgroup_offline_fn - the second step of cgroup destruction
+ * @work: cgroup->destroy_free_work
+ *
+ * This function is invoked from a work item for a cgroup which is being
+ * destroyed after the percpu refcnts of all css's are guaranteed to be
+ * seen as killed on all CPUs, and performs the rest of destruction.  This
+ * is the second step of destruction described in the comment above
+ * cgroup_destroy_locked().
+ */
+static void cgroup_offline_fn(struct work_struct *work)
+{
+       struct cgroup *cgrp = container_of(work, struct cgroup, destroy_work);
+       struct cgroup *parent = cgrp->parent;
+       struct dentry *d = cgrp->dentry;
+       struct cgroup_subsys *ss;
+
+       mutex_lock(&cgroup_mutex);
+
+       /*
+        * css_tryget() is guaranteed to fail now.  Tell subsystems to
+        * initate destruction.
+        */
+       for_each_root_subsys(cgrp->root, ss)
+               offline_css(ss, cgrp);
+
+       /*
+        * Put the css refs from cgroup_destroy_locked().  Each css holds
+        * an extra reference to the cgroup's dentry and cgroup removal
+        * proceeds regardless of css refs.  On the last put of each css,
+        * whenever that may be, the extra dentry ref is put so that dentry
+        * destruction happens only after all css's are released.
+        */
+       for_each_root_subsys(cgrp->root, ss)
+               css_put(cgrp->subsys[ss->subsys_id]);
+
+       /* delete this cgroup from parent->children */
+       list_del_rcu(&cgrp->sibling);
+
+       dput(d);
+
+       set_bit(CGRP_RELEASABLE, &parent->flags);
+       check_for_release(parent);
+
+       mutex_unlock(&cgroup_mutex);
 }
 
 static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
@@ -4361,12 +4646,12 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
        cgroup_init_cftsets(ss);
 
        /* Create the top cgroup state for this subsystem */
-       list_add(&ss->sibling, &rootnode.subsys_list);
-       ss->root = &rootnode;
-       css = ss->css_alloc(dummytop);
+       list_add(&ss->sibling, &cgroup_dummy_root.subsys_list);
+       ss->root = &cgroup_dummy_root;
+       css = ss->css_alloc(cgroup_dummy_top);
        /* We don't handle early failures gracefully */
        BUG_ON(IS_ERR(css));
-       init_cgroup_css(css, ss, dummytop);
+       init_cgroup_css(css, ss, cgroup_dummy_top);
 
        /* Update the init_css_set to contain a subsys
         * pointer to this state - since the subsystem is
@@ -4381,7 +4666,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
         * need to invoke fork callbacks here. */
        BUG_ON(!list_empty(&init_task.tasks));
 
-       BUG_ON(online_css(ss, dummytop));
+       BUG_ON(online_css(ss, cgroup_dummy_top));
 
        mutex_unlock(&cgroup_mutex);
 
@@ -4404,7 +4689,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
        struct cgroup_subsys_state *css;
        int i, ret;
        struct hlist_node *tmp;
-       struct css_set *cg;
+       struct css_set *cset;
        unsigned long key;
 
        /* check name and function validity */
@@ -4427,7 +4712,7 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
         */
        if (ss->module == NULL) {
                /* a sanity check */
-               BUG_ON(subsys[ss->subsys_id] != ss);
+               BUG_ON(cgroup_subsys[ss->subsys_id] != ss);
                return 0;
        }
 
@@ -4435,26 +4720,26 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
        cgroup_init_cftsets(ss);
 
        mutex_lock(&cgroup_mutex);
-       subsys[ss->subsys_id] = ss;
+       cgroup_subsys[ss->subsys_id] = ss;
 
        /*
         * no ss->css_alloc seems to need anything important in the ss
-        * struct, so this can happen first (i.e. before the rootnode
+        * struct, so this can happen first (i.e. before the dummy root
         * attachment).
         */
-       css = ss->css_alloc(dummytop);
+       css = ss->css_alloc(cgroup_dummy_top);
        if (IS_ERR(css)) {
-               /* failure case - need to deassign the subsys[] slot. */
-               subsys[ss->subsys_id] = NULL;
+               /* failure case - need to deassign the cgroup_subsys[] slot. */
+               cgroup_subsys[ss->subsys_id] = NULL;
                mutex_unlock(&cgroup_mutex);
                return PTR_ERR(css);
        }
 
-       list_add(&ss->sibling, &rootnode.subsys_list);
-       ss->root = &rootnode;
+       list_add(&ss->sibling, &cgroup_dummy_root.subsys_list);
+       ss->root = &cgroup_dummy_root;
 
        /* our new subsystem will be attached to the dummy hierarchy. */
-       init_cgroup_css(css, ss, dummytop);
+       init_cgroup_css(css, ss, cgroup_dummy_top);
        /* init_idr must be after init_cgroup_css because it sets css->id. */
        if (ss->use_id) {
                ret = cgroup_init_idr(ss, css);
@@ -4471,21 +4756,21 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
         * this is all done under the css_set_lock.
         */
        write_lock(&css_set_lock);
-       hash_for_each_safe(css_set_table, i, tmp, cg, hlist) {
+       hash_for_each_safe(css_set_table, i, tmp, cset, hlist) {
                /* skip entries that we already rehashed */
-               if (cg->subsys[ss->subsys_id])
+               if (cset->subsys[ss->subsys_id])
                        continue;
                /* remove existing entry */
-               hash_del(&cg->hlist);
+               hash_del(&cset->hlist);
                /* set new value */
-               cg->subsys[ss->subsys_id] = css;
+               cset->subsys[ss->subsys_id] = css;
                /* recompute hash and restore entry */
-               key = css_set_hash(cg->subsys);
-               hash_add(css_set_table, &cg->hlist, key);
+               key = css_set_hash(cset->subsys);
+               hash_add(css_set_table, &cset->hlist, key);
        }
        write_unlock(&css_set_lock);
 
-       ret = online_css(ss, dummytop);
+       ret = online_css(ss, cgroup_dummy_top);
        if (ret)
                goto err_unload;
 
@@ -4511,7 +4796,7 @@ EXPORT_SYMBOL_GPL(cgroup_load_subsys);
  */
 void cgroup_unload_subsys(struct cgroup_subsys *ss)
 {
-       struct cg_cgroup_link *link;
+       struct cgrp_cset_link *link;
 
        BUG_ON(ss->module == NULL);
 
@@ -4520,45 +4805,46 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
         * try_module_get in parse_cgroupfs_options should ensure that it
         * doesn't start being used while we're killing it off.
         */
-       BUG_ON(ss->root != &rootnode);
+       BUG_ON(ss->root != &cgroup_dummy_root);
 
        mutex_lock(&cgroup_mutex);
 
-       offline_css(ss, dummytop);
+       offline_css(ss, cgroup_dummy_top);
 
        if (ss->use_id)
                idr_destroy(&ss->idr);
 
        /* deassign the subsys_id */
-       subsys[ss->subsys_id] = NULL;
+       cgroup_subsys[ss->subsys_id] = NULL;
 
-       /* remove subsystem from rootnode's list of subsystems */
+       /* remove subsystem from the dummy root's list of subsystems */
        list_del_init(&ss->sibling);
 
        /*
-        * disentangle the css from all css_sets attached to the dummytop. as
-        * in loading, we need to pay our respects to the hashtable gods.
+        * disentangle the css from all css_sets attached to the dummy
+        * top. as in loading, we need to pay our respects to the hashtable
+        * gods.
         */
        write_lock(&css_set_lock);
-       list_for_each_entry(link, &dummytop->css_sets, cgrp_link_list) {
-               struct css_set *cg = link->cg;
+       list_for_each_entry(link, &cgroup_dummy_top->cset_links, cset_link) {
+               struct css_set *cset = link->cset;
                unsigned long key;
 
-               hash_del(&cg->hlist);
-               cg->subsys[ss->subsys_id] = NULL;
-               key = css_set_hash(cg->subsys);
-               hash_add(css_set_table, &cg->hlist, key);
+               hash_del(&cset->hlist);
+               cset->subsys[ss->subsys_id] = NULL;
+               key = css_set_hash(cset->subsys);
+               hash_add(css_set_table, &cset->hlist, key);
        }
        write_unlock(&css_set_lock);
 
        /*
-        * remove subsystem's css from the dummytop and free it - need to
-        * free before marking as null because ss->css_free needs the
-        * cgrp->subsys pointer to find their state. note that this also
-        * takes care of freeing the css_id.
+        * remove subsystem's css from the cgroup_dummy_top and free it -
+        * need to free before marking as null because ss->css_free needs
+        * the cgrp->subsys pointer to find their state. note that this
+        * also takes care of freeing the css_id.
         */
-       ss->css_free(dummytop);
-       dummytop->subsys[ss->subsys_id] = NULL;
+       ss->css_free(cgroup_dummy_top);
+       cgroup_dummy_top->subsys[ss->subsys_id] = NULL;
 
        mutex_unlock(&cgroup_mutex);
 }
@@ -4572,30 +4858,25 @@ EXPORT_SYMBOL_GPL(cgroup_unload_subsys);
  */
 int __init cgroup_init_early(void)
 {
+       struct cgroup_subsys *ss;
        int i;
+
        atomic_set(&init_css_set.refcount, 1);
-       INIT_LIST_HEAD(&init_css_set.cg_links);
+       INIT_LIST_HEAD(&init_css_set.cgrp_links);
        INIT_LIST_HEAD(&init_css_set.tasks);
        INIT_HLIST_NODE(&init_css_set.hlist);
        css_set_count = 1;
-       init_cgroup_root(&rootnode);
-       root_count = 1;
-       init_task.cgroups = &init_css_set;
-
-       init_css_set_link.cg = &init_css_set;
-       init_css_set_link.cgrp = dummytop;
-       list_add(&init_css_set_link.cgrp_link_list,
-                &rootnode.top_cgroup.css_sets);
-       list_add(&init_css_set_link.cg_link_list,
-                &init_css_set.cg_links);
-
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-               struct cgroup_subsys *ss = subsys[i];
-
-               /* at bootup time, we don't worry about modular subsystems */
-               if (!ss || ss->module)
-                       continue;
+       init_cgroup_root(&cgroup_dummy_root);
+       cgroup_root_count = 1;
+       RCU_INIT_POINTER(init_task.cgroups, &init_css_set);
+
+       init_cgrp_cset_link.cset = &init_css_set;
+       init_cgrp_cset_link.cgrp = cgroup_dummy_top;
+       list_add(&init_cgrp_cset_link.cset_link, &cgroup_dummy_top->cset_links);
+       list_add(&init_cgrp_cset_link.cgrp_link, &init_css_set.cgrp_links);
 
+       /* at bootup time, we don't worry about modular subsystems */
+       for_each_builtin_subsys(ss, i) {
                BUG_ON(!ss->name);
                BUG_ON(strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN);
                BUG_ON(!ss->css_alloc);
@@ -4620,30 +4901,33 @@ int __init cgroup_init_early(void)
  */
 int __init cgroup_init(void)
 {
-       int err;
-       int i;
+       struct cgroup_subsys *ss;
        unsigned long key;
+       int i, err;
 
        err = bdi_init(&cgroup_backing_dev_info);
        if (err)
                return err;
 
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-               struct cgroup_subsys *ss = subsys[i];
-
-               /* at bootup time, we don't worry about modular subsystems */
-               if (!ss || ss->module)
-                       continue;
+       for_each_builtin_subsys(ss, i) {
                if (!ss->early_init)
                        cgroup_init_subsys(ss);
                if (ss->use_id)
                        cgroup_init_idr(ss, init_css_set.subsys[ss->subsys_id]);
        }
 
+       /* allocate id for the dummy hierarchy */
+       mutex_lock(&cgroup_mutex);
+       mutex_lock(&cgroup_root_mutex);
+
        /* Add init_css_set to the hash table */
        key = css_set_hash(init_css_set.subsys);
        hash_add(css_set_table, &init_css_set.hlist, key);
-       BUG_ON(!init_root_id(&rootnode));
+
+       BUG_ON(cgroup_init_root_id(&cgroup_dummy_root, 0, 1));
+
+       mutex_unlock(&cgroup_root_mutex);
+       mutex_unlock(&cgroup_mutex);
 
        cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj);
        if (!cgroup_kobj) {
@@ -4708,7 +4992,7 @@ int proc_cgroup_show(struct seq_file *m, void *v)
                int count = 0;
 
                seq_printf(m, "%d:", root->hierarchy_id);
-               for_each_subsys(root, ss)
+               for_each_root_subsys(root, ss)
                        seq_printf(m, "%s%s", count++ ? "," : "", ss->name);
                if (strlen(root->name))
                        seq_printf(m, "%sname=%s", count ? "," : "",
@@ -4734,6 +5018,7 @@ out:
 /* Display information about each subsystem and each hierarchy */
 static int proc_cgroupstats_show(struct seq_file *m, void *v)
 {
+       struct cgroup_subsys *ss;
        int i;
 
        seq_puts(m, "#subsys_name\thierarchy\tnum_cgroups\tenabled\n");
@@ -4743,14 +5028,12 @@ static int proc_cgroupstats_show(struct seq_file *m, void *v)
         * subsys/hierarchy state.
         */
        mutex_lock(&cgroup_mutex);
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-               struct cgroup_subsys *ss = subsys[i];
-               if (ss == NULL)
-                       continue;
+
+       for_each_subsys(ss, i)
                seq_printf(m, "%s\t%d\t%d\t%d\n",
                           ss->name, ss->root->hierarchy_id,
                           ss->root->number_of_cgroups, !ss->disabled);
-       }
+
        mutex_unlock(&cgroup_mutex);
        return 0;
 }
@@ -4786,8 +5069,8 @@ static const struct file_operations proc_cgroupstats_operations = {
 void cgroup_fork(struct task_struct *child)
 {
        task_lock(current);
+       get_css_set(task_css_set(current));
        child->cgroups = current->cgroups;
-       get_css_set(child->cgroups);
        task_unlock(current);
        INIT_LIST_HEAD(&child->cg_list);
 }
@@ -4804,6 +5087,7 @@ void cgroup_fork(struct task_struct *child)
  */
 void cgroup_post_fork(struct task_struct *child)
 {
+       struct cgroup_subsys *ss;
        int i;
 
        /*
@@ -4821,7 +5105,7 @@ void cgroup_post_fork(struct task_struct *child)
                write_lock(&css_set_lock);
                task_lock(child);
                if (list_empty(&child->cg_list))
-                       list_add(&child->cg_list, &child->cgroups->tasks);
+                       list_add(&child->cg_list, &task_css_set(child)->tasks);
                task_unlock(child);
                write_unlock(&css_set_lock);
        }
@@ -4840,12 +5124,9 @@ void cgroup_post_fork(struct task_struct *child)
                 * of the array can be freed at module unload, so we
                 * can't touch that.
                 */
-               for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
-                       struct cgroup_subsys *ss = subsys[i];
-
+               for_each_builtin_subsys(ss, i)
                        if (ss->fork)
                                ss->fork(child);
-               }
        }
 }
 
@@ -4886,7 +5167,8 @@ void cgroup_post_fork(struct task_struct *child)
  */
 void cgroup_exit(struct task_struct *tsk, int run_callbacks)
 {
-       struct css_set *cg;
+       struct cgroup_subsys *ss;
+       struct css_set *cset;
        int i;
 
        /*
@@ -4903,36 +5185,32 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
 
        /* Reassign the task to the init_css_set. */
        task_lock(tsk);
-       cg = tsk->cgroups;
-       tsk->cgroups = &init_css_set;
+       cset = task_css_set(tsk);
+       RCU_INIT_POINTER(tsk->cgroups, &init_css_set);
 
        if (run_callbacks && need_forkexit_callback) {
                /*
                 * fork/exit callbacks are supported only for builtin
                 * subsystems, see cgroup_post_fork() for details.
                 */
-               for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
-                       struct cgroup_subsys *ss = subsys[i];
-
+               for_each_builtin_subsys(ss, i) {
                        if (ss->exit) {
-                               struct cgroup *old_cgrp =
-                                       rcu_dereference_raw(cg->subsys[i])->cgroup;
+                               struct cgroup *old_cgrp = cset->subsys[i]->cgroup;
                                struct cgroup *cgrp = task_cgroup(tsk, i);
+
                                ss->exit(cgrp, old_cgrp, tsk);
                        }
                }
        }
        task_unlock(tsk);
 
-       put_css_set_taskexit(cg);
+       put_css_set_taskexit(cset);
 }
 
 static void check_for_release(struct cgroup *cgrp)
 {
-       /* All of these checks rely on RCU to keep the cgroup
-        * structure alive */
        if (cgroup_is_releasable(cgrp) &&
-           !atomic_read(&cgrp->count) && list_empty(&cgrp->children)) {
+           list_empty(&cgrp->cset_links) && list_empty(&cgrp->children)) {
                /*
                 * Control Group is currently removeable. If it's not
                 * already queued for a userspace notification, queue
@@ -4941,7 +5219,7 @@ static void check_for_release(struct cgroup *cgrp)
                int need_schedule_work = 0;
 
                raw_spin_lock(&release_list_lock);
-               if (!cgroup_is_removed(cgrp) &&
+               if (!cgroup_is_dead(cgrp) &&
                    list_empty(&cgrp->release_list)) {
                        list_add(&cgrp->release_list, &release_list);
                        need_schedule_work = 1;
@@ -4952,34 +5230,6 @@ static void check_for_release(struct cgroup *cgrp)
        }
 }
 
-/* Caller must verify that the css is not for root cgroup */
-bool __css_tryget(struct cgroup_subsys_state *css)
-{
-       while (true) {
-               int t, v;
-
-               v = css_refcnt(css);
-               t = atomic_cmpxchg(&css->refcnt, v, v + 1);
-               if (likely(t == v))
-                       return true;
-               else if (t < 0)
-                       return false;
-               cpu_relax();
-       }
-}
-EXPORT_SYMBOL_GPL(__css_tryget);
-
-/* Caller must verify that the css is not for root cgroup */
-void __css_put(struct cgroup_subsys_state *css)
-{
-       int v;
-
-       v = css_unbias_refcnt(atomic_dec_return(&css->refcnt));
-       if (v == 0)
-               schedule_work(&css->dput_work);
-}
-EXPORT_SYMBOL_GPL(__css_put);
-
 /*
  * Notify userspace when a cgroup is released, by running the
  * configured release agent with the name of the cgroup (path
@@ -5054,23 +5304,19 @@ static void cgroup_release_agent(struct work_struct *work)
 
 static int __init cgroup_disable(char *str)
 {
-       int i;
+       struct cgroup_subsys *ss;
        char *token;
+       int i;
 
        while ((token = strsep(&str, ",")) != NULL) {
                if (!*token)
                        continue;
-               for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-                       struct cgroup_subsys *ss = subsys[i];
-
-                       /*
-                        * cgroup_disable, being at boot time, can't
-                        * know about module subsystems, so we don't
-                        * worry about them.
-                        */
-                       if (!ss || ss->module)
-                               continue;
 
+               /*
+                * cgroup_disable, being at boot time, can't know about
+                * module subsystems, so we don't worry about them.
+                */
+               for_each_builtin_subsys(ss, i) {
                        if (!strcmp(token, ss->name)) {
                                ss->disabled = 1;
                                printk(KERN_INFO "Disabling %s control group"
@@ -5087,9 +5333,7 @@ __setup("cgroup_disable=", cgroup_disable);
  * Functons for CSS ID.
  */
 
-/*
- *To get ID other than 0, this should be called when !cgroup_is_removed().
- */
+/* to get ID other than 0, this should be called when !cgroup_is_dead() */
 unsigned short css_id(struct cgroup_subsys_state *css)
 {
        struct css_id *cssid;
@@ -5099,7 +5343,7 @@ unsigned short css_id(struct cgroup_subsys_state *css)
         * on this or this is under rcu_read_lock(). Once css->id is allocated,
         * it's unchanged until freed.
         */
-       cssid = rcu_dereference_check(css->id, css_refcnt(css));
+       cssid = rcu_dereference_raw(css->id);
 
        if (cssid)
                return cssid->id;
@@ -5107,18 +5351,6 @@ unsigned short css_id(struct cgroup_subsys_state *css)
 }
 EXPORT_SYMBOL_GPL(css_id);
 
-unsigned short css_depth(struct cgroup_subsys_state *css)
-{
-       struct css_id *cssid;
-
-       cssid = rcu_dereference_check(css->id, css_refcnt(css));
-
-       if (cssid)
-               return cssid->depth;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(css_depth);
-
 /**
  *  css_is_ancestor - test "root" css is an ancestor of "child"
  * @child: the css to be tested.
@@ -5153,7 +5385,8 @@ bool css_is_ancestor(struct cgroup_subsys_state *child,
 
 void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css)
 {
-       struct css_id *id = css->id;
+       struct css_id *id = rcu_dereference_protected(css->id, true);
+
        /* When this is called before css_id initialization, id can be NULL */
        if (!id)
                return;
@@ -5219,8 +5452,8 @@ static int __init_or_module cgroup_init_idr(struct cgroup_subsys *ss,
                return PTR_ERR(newid);
 
        newid->stack[0] = newid->id;
-       newid->css = rootcss;
-       rootcss->id = newid;
+       RCU_INIT_POINTER(newid->css, rootcss);
+       RCU_INIT_POINTER(rootcss->id, newid);
        return 0;
 }
 
@@ -5234,7 +5467,7 @@ static int alloc_css_id(struct cgroup_subsys *ss, struct cgroup *parent,
        subsys_id = ss->subsys_id;
        parent_css = parent->subsys[subsys_id];
        child_css = child->subsys[subsys_id];
-       parent_id = parent_css->id;
+       parent_id = rcu_dereference_protected(parent_css->id, true);
        depth = parent_id->depth + 1;
 
        child_id = get_new_cssid(ss, depth);
@@ -5299,7 +5532,7 @@ struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id)
 }
 
 #ifdef CONFIG_CGROUP_DEBUG
-static struct cgroup_subsys_state *debug_css_alloc(struct cgroup *cont)
+static struct cgroup_subsys_state *debug_css_alloc(struct cgroup *cgrp)
 {
        struct cgroup_subsys_state *css = kzalloc(sizeof(*css), GFP_KERNEL);
 
@@ -5309,48 +5542,43 @@ static struct cgroup_subsys_state *debug_css_alloc(struct cgroup *cont)
        return css;
 }
 
-static void debug_css_free(struct cgroup *cont)
-{
-       kfree(cont->subsys[debug_subsys_id]);
-}
-
-static u64 cgroup_refcount_read(struct cgroup *cont, struct cftype *cft)
+static void debug_css_free(struct cgroup *cgrp)
 {
-       return atomic_read(&cont->count);
+       kfree(cgrp->subsys[debug_subsys_id]);
 }
 
-static u64 debug_taskcount_read(struct cgroup *cont, struct cftype *cft)
+static u64 debug_taskcount_read(struct cgroup *cgrp, struct cftype *cft)
 {
-       return cgroup_task_count(cont);
+       return cgroup_task_count(cgrp);
 }
 
-static u64 current_css_set_read(struct cgroup *cont, struct cftype *cft)
+static u64 current_css_set_read(struct cgroup *cgrp, struct cftype *cft)
 {
        return (u64)(unsigned long)current->cgroups;
 }
 
-static u64 current_css_set_refcount_read(struct cgroup *cont,
-                                          struct cftype *cft)
+static u64 current_css_set_refcount_read(struct cgroup *cgrp,
+                                        struct cftype *cft)
 {
        u64 count;
 
        rcu_read_lock();
-       count = atomic_read(&current->cgroups->refcount);
+       count = atomic_read(&task_css_set(current)->refcount);
        rcu_read_unlock();
        return count;
 }
 
-static int current_css_set_cg_links_read(struct cgroup *cont,
+static int current_css_set_cg_links_read(struct cgroup *cgrp,
                                         struct cftype *cft,
                                         struct seq_file *seq)
 {
-       struct cg_cgroup_link *link;
-       struct css_set *cg;
+       struct cgrp_cset_link *link;
+       struct css_set *cset;
 
        read_lock(&css_set_lock);
        rcu_read_lock();
-       cg = rcu_dereference(current->cgroups);
-       list_for_each_entry(link, &cg->cg_links, cg_link_list) {
+       cset = rcu_dereference(current->cgroups);
+       list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
                struct cgroup *c = link->cgrp;
                const char *name;
 
@@ -5367,19 +5595,19 @@ static int current_css_set_cg_links_read(struct cgroup *cont,
 }
 
 #define MAX_TASKS_SHOWN_PER_CSS 25
-static int cgroup_css_links_read(struct cgroup *cont,
+static int cgroup_css_links_read(struct cgroup *cgrp,
                                 struct cftype *cft,
                                 struct seq_file *seq)
 {
-       struct cg_cgroup_link *link;
+       struct cgrp_cset_link *link;
 
        read_lock(&css_set_lock);
-       list_for_each_entry(link, &cont->css_sets, cgrp_link_list) {
-               struct css_set *cg = link->cg;
+       list_for_each_entry(link, &cgrp->cset_links, cset_link) {
+               struct css_set *cset = link->cset;
                struct task_struct *task;
                int count = 0;
-               seq_printf(seq, "css_set %p\n", cg);
-               list_for_each_entry(task, &cg->tasks, cg_list) {
+               seq_printf(seq, "css_set %p\n", cset);
+               list_for_each_entry(task, &cset->tasks, cg_list) {
                        if (count++ > MAX_TASKS_SHOWN_PER_CSS) {
                                seq_puts(seq, "  ...\n");
                                break;
@@ -5399,10 +5627,6 @@ static u64 releasable_read(struct cgroup *cgrp, struct cftype *cft)
 }
 
 static struct cftype debug_files[] =  {
-       {
-               .name = "cgroup_refcount",
-               .read_u64 = cgroup_refcount_read,
-       },
        {
                .name = "taskcount",
                .read_u64 = debug_taskcount_read,
index 64b3f791bbe595905b00e9cf8ecbee763cbacf7d..e5657788feddfefaaed5f7ce3ce2ac26ca80a9c1 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
 #include <linux/cgroup.h>
+#include <linux/wait.h>
 
 /*
  * Tracks how many cpusets are currently defined in system.
@@ -87,6 +88,18 @@ struct cpuset {
        cpumask_var_t cpus_allowed;     /* CPUs allowed to tasks in cpuset */
        nodemask_t mems_allowed;        /* Memory Nodes allowed to tasks */
 
+       /*
+        * This is old Memory Nodes tasks took on.
+        *
+        * - top_cpuset.old_mems_allowed is initialized to mems_allowed.
+        * - A new cpuset's old_mems_allowed is initialized when some
+        *   task is moved into it.
+        * - old_mems_allowed is used in cpuset_migrate_mm() when we change
+        *   cpuset.mems_allowed and have tasks' nodemask updated, and
+        *   then old_mems_allowed is updated to mems_allowed.
+        */
+       nodemask_t old_mems_allowed;
+
        struct fmeter fmeter;           /* memory_pressure filter */
 
        /*
@@ -100,14 +113,12 @@ struct cpuset {
 
        /* for custom sched domain */
        int relax_domain_level;
-
-       struct work_struct hotplug_work;
 };
 
 /* Retrieve the cpuset for a cgroup */
-static inline struct cpuset *cgroup_cs(struct cgroup *cont)
+static inline struct cpuset *cgroup_cs(struct cgroup *cgrp)
 {
-       return container_of(cgroup_subsys_state(cont, cpuset_subsys_id),
+       return container_of(cgroup_subsys_state(cgrp, cpuset_subsys_id),
                            struct cpuset, css);
 }
 
@@ -267,14 +278,11 @@ static DEFINE_MUTEX(callback_mutex);
 /*
  * CPU / memory hotplug is handled asynchronously.
  */
-static struct workqueue_struct *cpuset_propagate_hotplug_wq;
-
 static void cpuset_hotplug_workfn(struct work_struct *work);
-static void cpuset_propagate_hotplug_workfn(struct work_struct *work);
-static void schedule_cpuset_propagate_hotplug(struct cpuset *cs);
-
 static DECLARE_WORK(cpuset_hotplug_work, cpuset_hotplug_workfn);
 
+static DECLARE_WAIT_QUEUE_HEAD(cpuset_attach_wq);
+
 /*
  * This is ugly, but preserves the userspace API for existing cpuset
  * users. If someone tries to mount the "cpuset" filesystem, we
@@ -304,53 +312,38 @@ static struct file_system_type cpuset_fs_type = {
 /*
  * Return in pmask the portion of a cpusets's cpus_allowed that
  * are online.  If none are online, walk up the cpuset hierarchy
- * until we find one that does have some online cpus.  If we get
- * all the way to the top and still haven't found any online cpus,
- * return cpu_online_mask.  Or if passed a NULL cs from an exit'ing
- * task, return cpu_online_mask.
+ * until we find one that does have some online cpus.  The top
+ * cpuset always has some cpus online.
  *
  * One way or another, we guarantee to return some non-empty subset
  * of cpu_online_mask.
  *
  * Call with callback_mutex held.
  */
-
 static void guarantee_online_cpus(const struct cpuset *cs,
                                  struct cpumask *pmask)
 {
-       while (cs && !cpumask_intersects(cs->cpus_allowed, cpu_online_mask))
+       while (!cpumask_intersects(cs->cpus_allowed, cpu_online_mask))
                cs = parent_cs(cs);
-       if (cs)
-               cpumask_and(pmask, cs->cpus_allowed, cpu_online_mask);
-       else
-               cpumask_copy(pmask, cpu_online_mask);
-       BUG_ON(!cpumask_intersects(pmask, cpu_online_mask));
+       cpumask_and(pmask, cs->cpus_allowed, cpu_online_mask);
 }
 
 /*
  * Return in *pmask the portion of a cpusets's mems_allowed that
  * are online, with memory.  If none are online with memory, walk
  * up the cpuset hierarchy until we find one that does have some
- * online mems.  If we get all the way to the top and still haven't
- * found any online mems, return node_states[N_MEMORY].
+ * online mems.  The top cpuset always has some mems online.
  *
  * One way or another, we guarantee to return some non-empty subset
  * of node_states[N_MEMORY].
  *
  * Call with callback_mutex held.
  */
-
 static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
 {
-       while (cs && !nodes_intersects(cs->mems_allowed,
-                                       node_states[N_MEMORY]))
+       while (!nodes_intersects(cs->mems_allowed, node_states[N_MEMORY]))
                cs = parent_cs(cs);
-       if (cs)
-               nodes_and(*pmask, cs->mems_allowed,
-                                       node_states[N_MEMORY]);
-       else
-               *pmask = node_states[N_MEMORY];
-       BUG_ON(!nodes_intersects(*pmask, node_states[N_MEMORY]));
+       nodes_and(*pmask, cs->mems_allowed, node_states[N_MEMORY]);
 }
 
 /*
@@ -440,7 +433,7 @@ static void free_trial_cpuset(struct cpuset *trial)
 
 static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
 {
-       struct cgroup *cont;
+       struct cgroup *cgrp;
        struct cpuset *c, *par;
        int ret;
 
@@ -448,7 +441,7 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
 
        /* Each of our child cpusets must be a subset of us */
        ret = -EBUSY;
-       cpuset_for_each_child(c, cont, cur)
+       cpuset_for_each_child(c, cgrp, cur)
                if (!is_cpuset_subset(c, trial))
                        goto out;
 
@@ -469,7 +462,7 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
         * overlap
         */
        ret = -EINVAL;
-       cpuset_for_each_child(c, cont, par) {
+       cpuset_for_each_child(c, cgrp, par) {
                if ((is_cpu_exclusive(trial) || is_cpu_exclusive(c)) &&
                    c != cur &&
                    cpumask_intersects(trial->cpus_allowed, c->cpus_allowed))
@@ -486,7 +479,7 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
         */
        ret = -ENOSPC;
        if ((cgroup_task_count(cur->css.cgroup) || cur->attach_in_progress) &&
-           (cpumask_empty(trial->cpus_allowed) ||
+           (cpumask_empty(trial->cpus_allowed) &&
             nodes_empty(trial->mems_allowed)))
                goto out;
 
@@ -540,7 +533,7 @@ static void update_domain_attr_tree(struct sched_domain_attr *dattr,
  * This function builds a partial partition of the systems CPUs
  * A 'partial partition' is a set of non-overlapping subsets whose
  * union is a subset of that set.
- * The output of this function needs to be passed to kernel/sched.c
+ * The output of this function needs to be passed to kernel/sched/core.c
  * partition_sched_domains() routine, which will rebuild the scheduler's
  * load balancing domains (sched domains) as specified by that partial
  * partition.
@@ -569,7 +562,7 @@ static void update_domain_attr_tree(struct sched_domain_attr *dattr,
  *        is a subset of one of these domains, while there are as
  *        many such domains as possible, each as small as possible.
  * doms  - Conversion of 'csa' to an array of cpumasks, for passing to
- *        the kernel/sched.c routine partition_sched_domains() in a
+ *        the kernel/sched/core.c routine partition_sched_domains() in a
  *        convenient format, that can be easily compared to the prior
  *        value to determine what partition elements (sched domains)
  *        were changed (added or removed.)
@@ -798,21 +791,43 @@ void rebuild_sched_domains(void)
        mutex_unlock(&cpuset_mutex);
 }
 
-/**
- * cpuset_test_cpumask - test a task's cpus_allowed versus its cpuset's
- * @tsk: task to test
- * @scan: struct cgroup_scanner contained in its struct cpuset_hotplug_scanner
+/*
+ * effective_cpumask_cpuset - return nearest ancestor with non-empty cpus
+ * @cs: the cpuset in interest
  *
- * Call with cpuset_mutex held.  May take callback_mutex during call.
- * Called for each task in a cgroup by cgroup_scan_tasks().
- * Return nonzero if this tasks's cpus_allowed mask should be changed (in other
- * words, if its mask is not equal to its cpuset's mask).
+ * A cpuset's effective cpumask is the cpumask of the nearest ancestor
+ * with non-empty cpus. We use effective cpumask whenever:
+ * - we update tasks' cpus_allowed. (they take on the ancestor's cpumask
+ *   if the cpuset they reside in has no cpus)
+ * - we want to retrieve task_cs(tsk)'s cpus_allowed.
+ *
+ * Called with cpuset_mutex held. cpuset_cpus_allowed_fallback() is an
+ * exception. See comments there.
  */
-static int cpuset_test_cpumask(struct task_struct *tsk,
-                              struct cgroup_scanner *scan)
+static struct cpuset *effective_cpumask_cpuset(struct cpuset *cs)
 {
-       return !cpumask_equal(&tsk->cpus_allowed,
-                       (cgroup_cs(scan->cg))->cpus_allowed);
+       while (cpumask_empty(cs->cpus_allowed))
+               cs = parent_cs(cs);
+       return cs;
+}
+
+/*
+ * effective_nodemask_cpuset - return nearest ancestor with non-empty mems
+ * @cs: the cpuset in interest
+ *
+ * A cpuset's effective nodemask is the nodemask of the nearest ancestor
+ * with non-empty memss. We use effective nodemask whenever:
+ * - we update tasks' mems_allowed. (they take on the ancestor's nodemask
+ *   if the cpuset they reside in has no mems)
+ * - we want to retrieve task_cs(tsk)'s mems_allowed.
+ *
+ * Called with cpuset_mutex held.
+ */
+static struct cpuset *effective_nodemask_cpuset(struct cpuset *cs)
+{
+       while (nodes_empty(cs->mems_allowed))
+               cs = parent_cs(cs);
+       return cs;
 }
 
 /**
@@ -829,7 +844,10 @@ static int cpuset_test_cpumask(struct task_struct *tsk,
 static void cpuset_change_cpumask(struct task_struct *tsk,
                                  struct cgroup_scanner *scan)
 {
-       set_cpus_allowed_ptr(tsk, ((cgroup_cs(scan->cg))->cpus_allowed));
+       struct cpuset *cpus_cs;
+
+       cpus_cs = effective_cpumask_cpuset(cgroup_cs(scan->cg));
+       set_cpus_allowed_ptr(tsk, cpus_cs->cpus_allowed);
 }
 
 /**
@@ -850,12 +868,51 @@ static void update_tasks_cpumask(struct cpuset *cs, struct ptr_heap *heap)
        struct cgroup_scanner scan;
 
        scan.cg = cs->css.cgroup;
-       scan.test_task = cpuset_test_cpumask;
+       scan.test_task = NULL;
        scan.process_task = cpuset_change_cpumask;
        scan.heap = heap;
        cgroup_scan_tasks(&scan);
 }
 
+/*
+ * update_tasks_cpumask_hier - Update the cpumasks of tasks in the hierarchy.
+ * @root_cs: the root cpuset of the hierarchy
+ * @update_root: update root cpuset or not?
+ * @heap: the heap used by cgroup_scan_tasks()
+ *
+ * This will update cpumasks of tasks in @root_cs and all other empty cpusets
+ * which take on cpumask of @root_cs.
+ *
+ * Called with cpuset_mutex held
+ */
+static void update_tasks_cpumask_hier(struct cpuset *root_cs,
+                                     bool update_root, struct ptr_heap *heap)
+{
+       struct cpuset *cp;
+       struct cgroup *pos_cgrp;
+
+       if (update_root)
+               update_tasks_cpumask(root_cs, heap);
+
+       rcu_read_lock();
+       cpuset_for_each_descendant_pre(cp, pos_cgrp, root_cs) {
+               /* skip the whole subtree if @cp have some CPU */
+               if (!cpumask_empty(cp->cpus_allowed)) {
+                       pos_cgrp = cgroup_rightmost_descendant(pos_cgrp);
+                       continue;
+               }
+               if (!css_tryget(&cp->css))
+                       continue;
+               rcu_read_unlock();
+
+               update_tasks_cpumask(cp, heap);
+
+               rcu_read_lock();
+               css_put(&cp->css);
+       }
+       rcu_read_unlock();
+}
+
 /**
  * update_cpumask - update the cpus_allowed mask of a cpuset and all tasks in it
  * @cs: the cpuset to consider
@@ -888,14 +945,15 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
                if (!cpumask_subset(trialcs->cpus_allowed, cpu_active_mask))
                        return -EINVAL;
        }
-       retval = validate_change(cs, trialcs);
-       if (retval < 0)
-               return retval;
 
        /* Nothing to do if the cpus didn't change */
        if (cpumask_equal(cs->cpus_allowed, trialcs->cpus_allowed))
                return 0;
 
+       retval = validate_change(cs, trialcs);
+       if (retval < 0)
+               return retval;
+
        retval = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, NULL);
        if (retval)
                return retval;
@@ -906,11 +964,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
        cpumask_copy(cs->cpus_allowed, trialcs->cpus_allowed);
        mutex_unlock(&callback_mutex);
 
-       /*
-        * Scan tasks in the cpuset, and update the cpumasks of any
-        * that need an update.
-        */
-       update_tasks_cpumask(cs, &heap);
+       update_tasks_cpumask_hier(cs, true, &heap);
 
        heap_free(&heap);
 
@@ -943,12 +997,14 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
                                                        const nodemask_t *to)
 {
        struct task_struct *tsk = current;
+       struct cpuset *mems_cs;
 
        tsk->mems_allowed = *to;
 
        do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL);
 
-       guarantee_online_mems(task_cs(tsk),&tsk->mems_allowed);
+       mems_cs = effective_nodemask_cpuset(task_cs(tsk));
+       guarantee_online_mems(mems_cs, &tsk->mems_allowed);
 }
 
 /*
@@ -1007,16 +1063,12 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
 static void cpuset_change_nodemask(struct task_struct *p,
                                   struct cgroup_scanner *scan)
 {
+       struct cpuset *cs = cgroup_cs(scan->cg);
        struct mm_struct *mm;
-       struct cpuset *cs;
        int migrate;
-       const nodemask_t *oldmem = scan->data;
-       static nodemask_t newmems;      /* protected by cpuset_mutex */
-
-       cs = cgroup_cs(scan->cg);
-       guarantee_online_mems(cs, &newmems);
+       nodemask_t *newmems = scan->data;
 
-       cpuset_change_task_nodemask(p, &newmems);
+       cpuset_change_task_nodemask(p, newmems);
 
        mm = get_task_mm(p);
        if (!mm)
@@ -1026,7 +1078,7 @@ static void cpuset_change_nodemask(struct task_struct *p,
 
        mpol_rebind_mm(mm, &cs->mems_allowed);
        if (migrate)
-               cpuset_migrate_mm(mm, oldmem, &cs->mems_allowed);
+               cpuset_migrate_mm(mm, &cs->old_mems_allowed, newmems);
        mmput(mm);
 }
 
@@ -1035,25 +1087,27 @@ static void *cpuset_being_rebound;
 /**
  * update_tasks_nodemask - Update the nodemasks of tasks in the cpuset.
  * @cs: the cpuset in which each task's mems_allowed mask needs to be changed
- * @oldmem: old mems_allowed of cpuset cs
  * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
  *
  * Called with cpuset_mutex held
  * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
  * if @heap != NULL.
  */
-static void update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem,
-                                struct ptr_heap *heap)
+static void update_tasks_nodemask(struct cpuset *cs, struct ptr_heap *heap)
 {
+       static nodemask_t newmems;      /* protected by cpuset_mutex */
        struct cgroup_scanner scan;
+       struct cpuset *mems_cs = effective_nodemask_cpuset(cs);
 
        cpuset_being_rebound = cs;              /* causes mpol_dup() rebind */
 
+       guarantee_online_mems(mems_cs, &newmems);
+
        scan.cg = cs->css.cgroup;
        scan.test_task = NULL;
        scan.process_task = cpuset_change_nodemask;
        scan.heap = heap;
-       scan.data = (nodemask_t *)oldmem;
+       scan.data = &newmems;
 
        /*
         * The mpol_rebind_mm() call takes mmap_sem, which we couldn't
@@ -1067,10 +1121,55 @@ static void update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem,
         */
        cgroup_scan_tasks(&scan);
 
+       /*
+        * All the tasks' nodemasks have been updated, update
+        * cs->old_mems_allowed.
+        */
+       cs->old_mems_allowed = newmems;
+
        /* We're done rebinding vmas to this cpuset's new mems_allowed. */
        cpuset_being_rebound = NULL;
 }
 
+/*
+ * update_tasks_nodemask_hier - Update the nodemasks of tasks in the hierarchy.
+ * @cs: the root cpuset of the hierarchy
+ * @update_root: update the root cpuset or not?
+ * @heap: the heap used by cgroup_scan_tasks()
+ *
+ * This will update nodemasks of tasks in @root_cs and all other empty cpusets
+ * which take on nodemask of @root_cs.
+ *
+ * Called with cpuset_mutex held
+ */
+static void update_tasks_nodemask_hier(struct cpuset *root_cs,
+                                      bool update_root, struct ptr_heap *heap)
+{
+       struct cpuset *cp;
+       struct cgroup *pos_cgrp;
+
+       if (update_root)
+               update_tasks_nodemask(root_cs, heap);
+
+       rcu_read_lock();
+       cpuset_for_each_descendant_pre(cp, pos_cgrp, root_cs) {
+               /* skip the whole subtree if @cp have some CPU */
+               if (!nodes_empty(cp->mems_allowed)) {
+                       pos_cgrp = cgroup_rightmost_descendant(pos_cgrp);
+                       continue;
+               }
+               if (!css_tryget(&cp->css))
+                       continue;
+               rcu_read_unlock();
+
+               update_tasks_nodemask(cp, heap);
+
+               rcu_read_lock();
+               css_put(&cp->css);
+       }
+       rcu_read_unlock();
+}
+
 /*
  * Handle user request to change the 'mems' memory placement
  * of a cpuset.  Needs to validate the request, update the
@@ -1087,13 +1186,9 @@ static void update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem,
 static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
                           const char *buf)
 {
-       NODEMASK_ALLOC(nodemask_t, oldmem, GFP_KERNEL);
        int retval;
        struct ptr_heap heap;
 
-       if (!oldmem)
-               return -ENOMEM;
-
        /*
         * top_cpuset.mems_allowed tracks node_stats[N_MEMORY];
         * it's read-only
@@ -1122,8 +1217,8 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
                        goto done;
                }
        }
-       *oldmem = cs->mems_allowed;
-       if (nodes_equal(*oldmem, trialcs->mems_allowed)) {
+
+       if (nodes_equal(cs->mems_allowed, trialcs->mems_allowed)) {
                retval = 0;             /* Too easy - nothing to do */
                goto done;
        }
@@ -1139,11 +1234,10 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
        cs->mems_allowed = trialcs->mems_allowed;
        mutex_unlock(&callback_mutex);
 
-       update_tasks_nodemask(cs, oldmem, &heap);
+       update_tasks_nodemask_hier(cs, true, &heap);
 
        heap_free(&heap);
 done:
-       NODEMASK_FREE(oldmem);
        return retval;
 }
 
@@ -1372,8 +1466,13 @@ static int cpuset_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 
        mutex_lock(&cpuset_mutex);
 
+       /*
+        * We allow to move tasks into an empty cpuset if sane_behavior
+        * flag is set.
+        */
        ret = -ENOSPC;
-       if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
+       if (!cgroup_sane_behavior(cgrp) &&
+           (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed)))
                goto out_unlock;
 
        cgroup_taskset_for_each(task, cgrp, tset) {
@@ -1422,8 +1521,7 @@ static cpumask_var_t cpus_attach;
 
 static void cpuset_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 {
-       /* static bufs protected by cpuset_mutex */
-       static nodemask_t cpuset_attach_nodemask_from;
+       /* static buf protected by cpuset_mutex */
        static nodemask_t cpuset_attach_nodemask_to;
        struct mm_struct *mm;
        struct task_struct *task;
@@ -1431,6 +1529,8 @@ static void cpuset_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
        struct cgroup *oldcgrp = cgroup_taskset_cur_cgroup(tset);
        struct cpuset *cs = cgroup_cs(cgrp);
        struct cpuset *oldcs = cgroup_cs(oldcgrp);
+       struct cpuset *cpus_cs = effective_cpumask_cpuset(cs);
+       struct cpuset *mems_cs = effective_nodemask_cpuset(cs);
 
        mutex_lock(&cpuset_mutex);
 
@@ -1438,9 +1538,9 @@ static void cpuset_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
        if (cs == &top_cpuset)
                cpumask_copy(cpus_attach, cpu_possible_mask);
        else
-               guarantee_online_cpus(cs, cpus_attach);
+               guarantee_online_cpus(cpus_cs, cpus_attach);
 
-       guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
+       guarantee_online_mems(mems_cs, &cpuset_attach_nodemask_to);
 
        cgroup_taskset_for_each(task, cgrp, tset) {
                /*
@@ -1457,26 +1557,32 @@ static void cpuset_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
         * Change mm, possibly for multiple threads in a threadgroup. This is
         * expensive and may sleep.
         */
-       cpuset_attach_nodemask_from = oldcs->mems_allowed;
        cpuset_attach_nodemask_to = cs->mems_allowed;
        mm = get_task_mm(leader);
        if (mm) {
+               struct cpuset *mems_oldcs = effective_nodemask_cpuset(oldcs);
+
                mpol_rebind_mm(mm, &cpuset_attach_nodemask_to);
-               if (is_memory_migrate(cs))
-                       cpuset_migrate_mm(mm, &cpuset_attach_nodemask_from,
+
+               /*
+                * old_mems_allowed is the same with mems_allowed here, except
+                * if this task is being moved automatically due to hotplug.
+                * In that case @mems_allowed has been updated and is empty,
+                * so @old_mems_allowed is the right nodesets that we migrate
+                * mm from.
+                */
+               if (is_memory_migrate(cs)) {
+                       cpuset_migrate_mm(mm, &mems_oldcs->old_mems_allowed,
                                          &cpuset_attach_nodemask_to);
+               }
                mmput(mm);
        }
 
-       cs->attach_in_progress--;
+       cs->old_mems_allowed = cpuset_attach_nodemask_to;
 
-       /*
-        * We may have raced with CPU/memory hotunplug.  Trigger hotplug
-        * propagation if @cs doesn't have any CPU or memory.  It will move
-        * the newly added tasks to the nearest parent which can execute.
-        */
-       if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
-               schedule_cpuset_propagate_hotplug(cs);
+       cs->attach_in_progress--;
+       if (!cs->attach_in_progress)
+               wake_up(&cpuset_attach_wq);
 
        mutex_unlock(&cpuset_mutex);
 }
@@ -1588,13 +1694,8 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
         * resources, wait for the previously scheduled operations before
         * proceeding, so that we don't end up keep removing tasks added
         * after execution capability is restored.
-        *
-        * Flushing cpuset_hotplug_work is enough to synchronize against
-        * hotplug hanlding; however, cpuset_attach() may schedule
-        * propagation work directly.  Flush the workqueue too.
         */
        flush_work(&cpuset_hotplug_work);
-       flush_workqueue(cpuset_propagate_hotplug_wq);
 
        mutex_lock(&cpuset_mutex);
        if (!is_cpuset_online(cs))
@@ -1658,13 +1759,13 @@ static size_t cpuset_sprintf_memlist(char *page, struct cpuset *cs)
        return count;
 }
 
-static ssize_t cpuset_common_file_read(struct cgroup *cont,
+static ssize_t cpuset_common_file_read(struct cgroup *cgrp,
                                       struct cftype *cft,
                                       struct file *file,
                                       char __user *buf,
                                       size_t nbytes, loff_t *ppos)
 {
-       struct cpuset *cs = cgroup_cs(cont);
+       struct cpuset *cs = cgroup_cs(cgrp);
        cpuset_filetype_t type = cft->private;
        char *page;
        ssize_t retval = 0;
@@ -1694,9 +1795,9 @@ out:
        return retval;
 }
 
-static u64 cpuset_read_u64(struct cgroup *cont, struct cftype *cft)
+static u64 cpuset_read_u64(struct cgroup *cgrp, struct cftype *cft)
 {
-       struct cpuset *cs = cgroup_cs(cont);
+       struct cpuset *cs = cgroup_cs(cgrp);
        cpuset_filetype_t type = cft->private;
        switch (type) {
        case FILE_CPU_EXCLUSIVE:
@@ -1725,9 +1826,9 @@ static u64 cpuset_read_u64(struct cgroup *cont, struct cftype *cft)
        return 0;
 }
 
-static s64 cpuset_read_s64(struct cgroup *cont, struct cftype *cft)
+static s64 cpuset_read_s64(struct cgroup *cgrp, struct cftype *cft)
 {
-       struct cpuset *cs = cgroup_cs(cont);
+       struct cpuset *cs = cgroup_cs(cgrp);
        cpuset_filetype_t type = cft->private;
        switch (type) {
        case FILE_SCHED_RELAX_DOMAIN_LEVEL:
@@ -1839,14 +1940,14 @@ static struct cftype files[] = {
 
 /*
  *     cpuset_css_alloc - allocate a cpuset css
- *     cont:   control group that the new cpuset will be part of
+ *     cgrp:   control group that the new cpuset will be part of
  */
 
-static struct cgroup_subsys_state *cpuset_css_alloc(struct cgroup *cont)
+static struct cgroup_subsys_state *cpuset_css_alloc(struct cgroup *cgrp)
 {
        struct cpuset *cs;
 
-       if (!cont->parent)
+       if (!cgrp->parent)
                return &top_cpuset.css;
 
        cs = kzalloc(sizeof(*cs), GFP_KERNEL);
@@ -1861,7 +1962,6 @@ static struct cgroup_subsys_state *cpuset_css_alloc(struct cgroup *cont)
        cpumask_clear(cs->cpus_allowed);
        nodes_clear(cs->mems_allowed);
        fmeter_init(&cs->fmeter);
-       INIT_WORK(&cs->hotplug_work, cpuset_propagate_hotplug_workfn);
        cs->relax_domain_level = -1;
 
        return &cs->css;
@@ -1942,9 +2042,9 @@ static void cpuset_css_offline(struct cgroup *cgrp)
  * will call rebuild_sched_domains_locked().
  */
 
-static void cpuset_css_free(struct cgroup *cont)
+static void cpuset_css_free(struct cgroup *cgrp)
 {
-       struct cpuset *cs = cgroup_cs(cont);
+       struct cpuset *cs = cgroup_cs(cgrp);
 
        free_cpumask_var(cs->cpus_allowed);
        kfree(cs);
@@ -2024,41 +2124,64 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
 }
 
 /**
- * cpuset_propagate_hotplug_workfn - propagate CPU/memory hotplug to a cpuset
+ * cpuset_hotplug_update_tasks - update tasks in a cpuset for hotunplug
  * @cs: cpuset in interest
  *
  * Compare @cs's cpu and mem masks against top_cpuset and if some have gone
  * offline, update @cs accordingly.  If @cs ends up with no CPU or memory,
  * all its tasks are moved to the nearest ancestor with both resources.
  */
-static void cpuset_propagate_hotplug_workfn(struct work_struct *work)
+static void cpuset_hotplug_update_tasks(struct cpuset *cs)
 {
        static cpumask_t off_cpus;
-       static nodemask_t off_mems, tmp_mems;
-       struct cpuset *cs = container_of(work, struct cpuset, hotplug_work);
+       static nodemask_t off_mems;
        bool is_empty;
+       bool sane = cgroup_sane_behavior(cs->css.cgroup);
+
+retry:
+       wait_event(cpuset_attach_wq, cs->attach_in_progress == 0);
 
        mutex_lock(&cpuset_mutex);
 
+       /*
+        * We have raced with task attaching. We wait until attaching
+        * is finished, so we won't attach a task to an empty cpuset.
+        */
+       if (cs->attach_in_progress) {
+               mutex_unlock(&cpuset_mutex);
+               goto retry;
+       }
+
        cpumask_andnot(&off_cpus, cs->cpus_allowed, top_cpuset.cpus_allowed);
        nodes_andnot(off_mems, cs->mems_allowed, top_cpuset.mems_allowed);
 
-       /* remove offline cpus from @cs */
-       if (!cpumask_empty(&off_cpus)) {
-               mutex_lock(&callback_mutex);
-               cpumask_andnot(cs->cpus_allowed, cs->cpus_allowed, &off_cpus);
-               mutex_unlock(&callback_mutex);
+       mutex_lock(&callback_mutex);
+       cpumask_andnot(cs->cpus_allowed, cs->cpus_allowed, &off_cpus);
+       mutex_unlock(&callback_mutex);
+
+       /*
+        * If sane_behavior flag is set, we need to update tasks' cpumask
+        * for empty cpuset to take on ancestor's cpumask. Otherwise, don't
+        * call update_tasks_cpumask() if the cpuset becomes empty, as
+        * the tasks in it will be migrated to an ancestor.
+        */
+       if ((sane && cpumask_empty(cs->cpus_allowed)) ||
+           (!cpumask_empty(&off_cpus) && !cpumask_empty(cs->cpus_allowed)))
                update_tasks_cpumask(cs, NULL);
-       }
 
-       /* remove offline mems from @cs */
-       if (!nodes_empty(off_mems)) {
-               tmp_mems = cs->mems_allowed;
-               mutex_lock(&callback_mutex);
-               nodes_andnot(cs->mems_allowed, cs->mems_allowed, off_mems);
-               mutex_unlock(&callback_mutex);
-               update_tasks_nodemask(cs, &tmp_mems, NULL);
-       }
+       mutex_lock(&callback_mutex);
+       nodes_andnot(cs->mems_allowed, cs->mems_allowed, off_mems);
+       mutex_unlock(&callback_mutex);
+
+       /*
+        * If sane_behavior flag is set, we need to update tasks' nodemask
+        * for empty cpuset to take on ancestor's nodemask. Otherwise, don't
+        * call update_tasks_nodemask() if the cpuset becomes empty, as
+        * the tasks in it will be migratd to an ancestor.
+        */
+       if ((sane && nodes_empty(cs->mems_allowed)) ||
+           (!nodes_empty(off_mems) && !nodes_empty(cs->mems_allowed)))
+               update_tasks_nodemask(cs, NULL);
 
        is_empty = cpumask_empty(cs->cpus_allowed) ||
                nodes_empty(cs->mems_allowed);
@@ -2066,40 +2189,14 @@ static void cpuset_propagate_hotplug_workfn(struct work_struct *work)
        mutex_unlock(&cpuset_mutex);
 
        /*
-        * If @cs became empty, move tasks to the nearest ancestor with
-        * execution resources.  This is full cgroup operation which will
+        * If sane_behavior flag is set, we'll keep tasks in empty cpusets.
+        *
+        * Otherwise move tasks to the nearest ancestor with execution
+        * resources.  This is full cgroup operation which will
         * also call back into cpuset.  Should be done outside any lock.
         */
-       if (is_empty)
+       if (!sane && is_empty)
                remove_tasks_in_empty_cpuset(cs);
-
-       /* the following may free @cs, should be the last operation */
-       css_put(&cs->css);
-}
-
-/**
- * schedule_cpuset_propagate_hotplug - schedule hotplug propagation to a cpuset
- * @cs: cpuset of interest
- *
- * Schedule cpuset_propagate_hotplug_workfn() which will update CPU and
- * memory masks according to top_cpuset.
- */
-static void schedule_cpuset_propagate_hotplug(struct cpuset *cs)
-{
-       /*
-        * Pin @cs.  The refcnt will be released when the work item
-        * finishes executing.
-        */
-       if (!css_tryget(&cs->css))
-               return;
-
-       /*
-        * Queue @cs->hotplug_work.  If already pending, lose the css ref.
-        * cpuset_propagate_hotplug_wq is ordered and propagation will
-        * happen in the order this function is called.
-        */
-       if (!queue_work(cpuset_propagate_hotplug_wq, &cs->hotplug_work))
-               css_put(&cs->css);
 }
 
 /**
@@ -2112,18 +2209,17 @@ static void schedule_cpuset_propagate_hotplug(struct cpuset *cs)
  * actively using CPU hotplug but making no active use of cpusets.
  *
  * Non-root cpusets are only affected by offlining.  If any CPUs or memory
- * nodes have been taken down, cpuset_propagate_hotplug() is invoked on all
- * descendants.
+ * nodes have been taken down, cpuset_hotplug_update_tasks() is invoked on
+ * all descendants.
  *
  * Note that CPU offlining during suspend is ignored.  We don't modify
  * cpusets across suspend/resume cycles at all.
  */
 static void cpuset_hotplug_workfn(struct work_struct *work)
 {
-       static cpumask_t new_cpus, tmp_cpus;
-       static nodemask_t new_mems, tmp_mems;
+       static cpumask_t new_cpus;
+       static nodemask_t new_mems;
        bool cpus_updated, mems_updated;
-       bool cpus_offlined, mems_offlined;
 
        mutex_lock(&cpuset_mutex);
 
@@ -2132,12 +2228,7 @@ static void cpuset_hotplug_workfn(struct work_struct *work)
        new_mems = node_states[N_MEMORY];
 
        cpus_updated = !cpumask_equal(top_cpuset.cpus_allowed, &new_cpus);
-       cpus_offlined = cpumask_andnot(&tmp_cpus, top_cpuset.cpus_allowed,
-                                      &new_cpus);
-
        mems_updated = !nodes_equal(top_cpuset.mems_allowed, new_mems);
-       nodes_andnot(tmp_mems, top_cpuset.mems_allowed, new_mems);
-       mems_offlined = !nodes_empty(tmp_mems);
 
        /* synchronize cpus_allowed to cpu_active_mask */
        if (cpus_updated) {
@@ -2149,28 +2240,32 @@ static void cpuset_hotplug_workfn(struct work_struct *work)
 
        /* synchronize mems_allowed to N_MEMORY */
        if (mems_updated) {
-               tmp_mems = top_cpuset.mems_allowed;
                mutex_lock(&callback_mutex);
                top_cpuset.mems_allowed = new_mems;
                mutex_unlock(&callback_mutex);
-               update_tasks_nodemask(&top_cpuset, &tmp_mems, NULL);
+               update_tasks_nodemask(&top_cpuset, NULL);
        }
 
-       /* if cpus or mems went down, we need to propagate to descendants */
-       if (cpus_offlined || mems_offlined) {
+       mutex_unlock(&cpuset_mutex);
+
+       /* if cpus or mems changed, we need to propagate to descendants */
+       if (cpus_updated || mems_updated) {
                struct cpuset *cs;
                struct cgroup *pos_cgrp;
 
                rcu_read_lock();
-               cpuset_for_each_descendant_pre(cs, pos_cgrp, &top_cpuset)
-                       schedule_cpuset_propagate_hotplug(cs);
-               rcu_read_unlock();
-       }
+               cpuset_for_each_descendant_pre(cs, pos_cgrp, &top_cpuset) {
+                       if (!css_tryget(&cs->css))
+                               continue;
+                       rcu_read_unlock();
 
-       mutex_unlock(&cpuset_mutex);
+                       cpuset_hotplug_update_tasks(cs);
 
-       /* wait for propagations to finish */
-       flush_workqueue(cpuset_propagate_hotplug_wq);
+                       rcu_read_lock();
+                       css_put(&cs->css);
+               }
+               rcu_read_unlock();
+       }
 
        /* rebuild sched domains if cpus_allowed has changed */
        if (cpus_updated)
@@ -2219,12 +2314,9 @@ void __init cpuset_init_smp(void)
 {
        cpumask_copy(top_cpuset.cpus_allowed, cpu_active_mask);
        top_cpuset.mems_allowed = node_states[N_MEMORY];
+       top_cpuset.old_mems_allowed = top_cpuset.mems_allowed;
 
        register_hotmemory_notifier(&cpuset_track_online_nodes_nb);
-
-       cpuset_propagate_hotplug_wq =
-               alloc_ordered_workqueue("cpuset_hotplug", 0);
-       BUG_ON(!cpuset_propagate_hotplug_wq);
 }
 
 /**
@@ -2240,21 +2332,23 @@ void __init cpuset_init_smp(void)
 
 void cpuset_cpus_allowed(struct task_struct *tsk, struct cpumask *pmask)
 {
+       struct cpuset *cpus_cs;
+
        mutex_lock(&callback_mutex);
        task_lock(tsk);
-       guarantee_online_cpus(task_cs(tsk), pmask);
+       cpus_cs = effective_cpumask_cpuset(task_cs(tsk));
+       guarantee_online_cpus(cpus_cs, pmask);
        task_unlock(tsk);
        mutex_unlock(&callback_mutex);
 }
 
 void cpuset_cpus_allowed_fallback(struct task_struct *tsk)
 {
-       const struct cpuset *cs;
+       const struct cpuset *cpus_cs;
 
        rcu_read_lock();
-       cs = task_cs(tsk);
-       if (cs)
-               do_set_cpus_allowed(tsk, cs->cpus_allowed);
+       cpus_cs = effective_cpumask_cpuset(task_cs(tsk));
+       do_set_cpus_allowed(tsk, cpus_cs->cpus_allowed);
        rcu_read_unlock();
 
        /*
@@ -2293,11 +2387,13 @@ void cpuset_init_current_mems_allowed(void)
 
 nodemask_t cpuset_mems_allowed(struct task_struct *tsk)
 {
+       struct cpuset *mems_cs;
        nodemask_t mask;
 
        mutex_lock(&callback_mutex);
        task_lock(tsk);
-       guarantee_online_mems(task_cs(tsk), &mask);
+       mems_cs = effective_nodemask_cpuset(task_cs(tsk));
+       guarantee_online_mems(mems_cs, &mask);
        task_unlock(tsk);
        mutex_unlock(&callback_mutex);
 
index b391907d53520cb4a126bc8e3e0a2d5a64ade54d..1db3af93370410ed8538e04b785f7cb2a3e4b33c 100644 (file)
@@ -165,10 +165,28 @@ int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free'
 /*
  * max perf event sample rate
  */
-#define DEFAULT_MAX_SAMPLE_RATE 100000
-int sysctl_perf_event_sample_rate __read_mostly = DEFAULT_MAX_SAMPLE_RATE;
-static int max_samples_per_tick __read_mostly =
-       DIV_ROUND_UP(DEFAULT_MAX_SAMPLE_RATE, HZ);
+#define DEFAULT_MAX_SAMPLE_RATE                100000
+#define DEFAULT_SAMPLE_PERIOD_NS       (NSEC_PER_SEC / DEFAULT_MAX_SAMPLE_RATE)
+#define DEFAULT_CPU_TIME_MAX_PERCENT   25
+
+int sysctl_perf_event_sample_rate __read_mostly        = DEFAULT_MAX_SAMPLE_RATE;
+
+static int max_samples_per_tick __read_mostly  = DIV_ROUND_UP(DEFAULT_MAX_SAMPLE_RATE, HZ);
+static int perf_sample_period_ns __read_mostly = DEFAULT_SAMPLE_PERIOD_NS;
+
+static atomic_t perf_sample_allowed_ns __read_mostly =
+       ATOMIC_INIT( DEFAULT_SAMPLE_PERIOD_NS * DEFAULT_CPU_TIME_MAX_PERCENT / 100);
+
+void update_perf_cpu_limits(void)
+{
+       u64 tmp = perf_sample_period_ns;
+
+       tmp *= sysctl_perf_cpu_time_max_percent;
+       tmp = do_div(tmp, 100);
+       atomic_set(&perf_sample_allowed_ns, tmp);
+}
+
+static int perf_rotate_context(struct perf_cpu_context *cpuctx);
 
 int perf_proc_update_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
@@ -180,10 +198,78 @@ int perf_proc_update_handler(struct ctl_table *table, int write,
                return ret;
 
        max_samples_per_tick = DIV_ROUND_UP(sysctl_perf_event_sample_rate, HZ);
+       perf_sample_period_ns = NSEC_PER_SEC / sysctl_perf_event_sample_rate;
+       update_perf_cpu_limits();
 
        return 0;
 }
 
+int sysctl_perf_cpu_time_max_percent __read_mostly = DEFAULT_CPU_TIME_MAX_PERCENT;
+
+int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write,
+                               void __user *buffer, size_t *lenp,
+                               loff_t *ppos)
+{
+       int ret = proc_dointvec(table, write, buffer, lenp, ppos);
+
+       if (ret || !write)
+               return ret;
+
+       update_perf_cpu_limits();
+
+       return 0;
+}
+
+/*
+ * perf samples are done in some very critical code paths (NMIs).
+ * If they take too much CPU time, the system can lock up and not
+ * get any real work done.  This will drop the sample rate when
+ * we detect that events are taking too long.
+ */
+#define NR_ACCUMULATED_SAMPLES 128
+DEFINE_PER_CPU(u64, running_sample_length);
+
+void perf_sample_event_took(u64 sample_len_ns)
+{
+       u64 avg_local_sample_len;
+       u64 local_samples_len = __get_cpu_var(running_sample_length);
+
+       if (atomic_read(&perf_sample_allowed_ns) == 0)
+               return;
+
+       /* decay the counter by 1 average sample */
+       local_samples_len = __get_cpu_var(running_sample_length);
+       local_samples_len -= local_samples_len/NR_ACCUMULATED_SAMPLES;
+       local_samples_len += sample_len_ns;
+       __get_cpu_var(running_sample_length) = local_samples_len;
+
+       /*
+        * note: this will be biased artifically low until we have
+        * seen NR_ACCUMULATED_SAMPLES.  Doing it this way keeps us
+        * from having to maintain a count.
+        */
+       avg_local_sample_len = local_samples_len/NR_ACCUMULATED_SAMPLES;
+
+       if (avg_local_sample_len <= atomic_read(&perf_sample_allowed_ns))
+               return;
+
+       if (max_samples_per_tick <= 1)
+               return;
+
+       max_samples_per_tick = DIV_ROUND_UP(max_samples_per_tick, 2);
+       sysctl_perf_event_sample_rate = max_samples_per_tick * HZ;
+       perf_sample_period_ns = NSEC_PER_SEC / sysctl_perf_event_sample_rate;
+
+       printk_ratelimited(KERN_WARNING
+                       "perf samples too long (%lld > %d), lowering "
+                       "kernel.perf_event_max_sample_rate to %d\n",
+                       avg_local_sample_len,
+                       atomic_read(&perf_sample_allowed_ns),
+                       sysctl_perf_event_sample_rate);
+
+       update_perf_cpu_limits();
+}
+
 static atomic64_t perf_event_id;
 
 static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx,
@@ -655,6 +741,106 @@ perf_cgroup_mark_enabled(struct perf_event *event,
 }
 #endif
 
+/*
+ * set default to be dependent on timer tick just
+ * like original code
+ */
+#define PERF_CPU_HRTIMER (1000 / HZ)
+/*
+ * function must be called with interrupts disbled
+ */
+static enum hrtimer_restart perf_cpu_hrtimer_handler(struct hrtimer *hr)
+{
+       struct perf_cpu_context *cpuctx;
+       enum hrtimer_restart ret = HRTIMER_NORESTART;
+       int rotations = 0;
+
+       WARN_ON(!irqs_disabled());
+
+       cpuctx = container_of(hr, struct perf_cpu_context, hrtimer);
+
+       rotations = perf_rotate_context(cpuctx);
+
+       /*
+        * arm timer if needed
+        */
+       if (rotations) {
+               hrtimer_forward_now(hr, cpuctx->hrtimer_interval);
+               ret = HRTIMER_RESTART;
+       }
+
+       return ret;
+}
+
+/* CPU is going down */
+void perf_cpu_hrtimer_cancel(int cpu)
+{
+       struct perf_cpu_context *cpuctx;
+       struct pmu *pmu;
+       unsigned long flags;
+
+       if (WARN_ON(cpu != smp_processor_id()))
+               return;
+
+       local_irq_save(flags);
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(pmu, &pmus, entry) {
+               cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+
+               if (pmu->task_ctx_nr == perf_sw_context)
+                       continue;
+
+               hrtimer_cancel(&cpuctx->hrtimer);
+       }
+
+       rcu_read_unlock();
+
+       local_irq_restore(flags);
+}
+
+static void __perf_cpu_hrtimer_init(struct perf_cpu_context *cpuctx, int cpu)
+{
+       struct hrtimer *hr = &cpuctx->hrtimer;
+       struct pmu *pmu = cpuctx->ctx.pmu;
+       int timer;
+
+       /* no multiplexing needed for SW PMU */
+       if (pmu->task_ctx_nr == perf_sw_context)
+               return;
+
+       /*
+        * check default is sane, if not set then force to
+        * default interval (1/tick)
+        */
+       timer = pmu->hrtimer_interval_ms;
+       if (timer < 1)
+               timer = pmu->hrtimer_interval_ms = PERF_CPU_HRTIMER;
+
+       cpuctx->hrtimer_interval = ns_to_ktime(NSEC_PER_MSEC * timer);
+
+       hrtimer_init(hr, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+       hr->function = perf_cpu_hrtimer_handler;
+}
+
+static void perf_cpu_hrtimer_restart(struct perf_cpu_context *cpuctx)
+{
+       struct hrtimer *hr = &cpuctx->hrtimer;
+       struct pmu *pmu = cpuctx->ctx.pmu;
+
+       /* not for SW PMU */
+       if (pmu->task_ctx_nr == perf_sw_context)
+               return;
+
+       if (hrtimer_active(hr))
+               return;
+
+       if (!hrtimer_callback_running(hr))
+               __hrtimer_start_range_ns(hr, cpuctx->hrtimer_interval,
+                                        0, HRTIMER_MODE_REL_PINNED, 0);
+}
+
 void perf_pmu_disable(struct pmu *pmu)
 {
        int *count = this_cpu_ptr(pmu->pmu_disable_count);
@@ -1503,6 +1689,7 @@ group_sched_in(struct perf_event *group_event,
 
        if (event_sched_in(group_event, cpuctx, ctx)) {
                pmu->cancel_txn(pmu);
+               perf_cpu_hrtimer_restart(cpuctx);
                return -EAGAIN;
        }
 
@@ -1549,6 +1736,8 @@ group_error:
 
        pmu->cancel_txn(pmu);
 
+       perf_cpu_hrtimer_restart(cpuctx);
+
        return -EAGAIN;
 }
 
@@ -1804,8 +1993,10 @@ static int __perf_event_enable(void *info)
                 * If this event can't go on and it's part of a
                 * group, then the whole group has to come off.
                 */
-               if (leader != event)
+               if (leader != event) {
                        group_sched_out(leader, cpuctx, ctx);
+                       perf_cpu_hrtimer_restart(cpuctx);
+               }
                if (leader->attr.pinned) {
                        update_group_times(leader);
                        leader->state = PERF_EVENT_STATE_ERROR;
@@ -2552,7 +2743,7 @@ static void rotate_ctx(struct perf_event_context *ctx)
  * because they're strictly cpu affine and rotate_start is called with IRQs
  * disabled, while rotate_context is called from IRQ context.
  */
-static void perf_rotate_context(struct perf_cpu_context *cpuctx)
+static int perf_rotate_context(struct perf_cpu_context *cpuctx)
 {
        struct perf_event_context *ctx = NULL;
        int rotate = 0, remove = 1;
@@ -2591,6 +2782,8 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx)
 done:
        if (remove)
                list_del_init(&cpuctx->rotation_list);
+
+       return rotate;
 }
 
 #ifdef CONFIG_NO_HZ_FULL
@@ -2622,10 +2815,6 @@ void perf_event_task_tick(void)
                ctx = cpuctx->task_ctx;
                if (ctx)
                        perf_adjust_freq_unthr_context(ctx, throttled);
-
-               if (cpuctx->jiffies_interval == 1 ||
-                               !(jiffies % cpuctx->jiffies_interval))
-                       perf_rotate_context(cpuctx);
        }
 }
 
@@ -5036,7 +5225,7 @@ static DEFINE_PER_CPU(struct swevent_htable, swevent_htable);
  * sign as trigger.
  */
 
-static u64 perf_swevent_set_period(struct perf_event *event)
+u64 perf_swevent_set_period(struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
        u64 period = hwc->last_period;
@@ -5979,9 +6168,56 @@ type_show(struct device *dev, struct device_attribute *attr, char *page)
        return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->type);
 }
 
+static ssize_t
+perf_event_mux_interval_ms_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *page)
+{
+       struct pmu *pmu = dev_get_drvdata(dev);
+
+       return snprintf(page, PAGE_SIZE-1, "%d\n", pmu->hrtimer_interval_ms);
+}
+
+static ssize_t
+perf_event_mux_interval_ms_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct pmu *pmu = dev_get_drvdata(dev);
+       int timer, cpu, ret;
+
+       ret = kstrtoint(buf, 0, &timer);
+       if (ret)
+               return ret;
+
+       if (timer < 1)
+               return -EINVAL;
+
+       /* same value, noting to do */
+       if (timer == pmu->hrtimer_interval_ms)
+               return count;
+
+       pmu->hrtimer_interval_ms = timer;
+
+       /* update all cpuctx for this PMU */
+       for_each_possible_cpu(cpu) {
+               struct perf_cpu_context *cpuctx;
+               cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
+               cpuctx->hrtimer_interval = ns_to_ktime(NSEC_PER_MSEC * timer);
+
+               if (hrtimer_active(&cpuctx->hrtimer))
+                       hrtimer_forward_now(&cpuctx->hrtimer, cpuctx->hrtimer_interval);
+       }
+
+       return count;
+}
+
+#define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store)
+
 static struct device_attribute pmu_dev_attrs[] = {
-       __ATTR_RO(type),
-       __ATTR_NULL,
+       __ATTR_RO(type),
+       __ATTR_RW(perf_event_mux_interval_ms),
+       __ATTR_NULL,
 };
 
 static int pmu_bus_running;
@@ -6027,7 +6263,7 @@ free_dev:
 static struct lock_class_key cpuctx_mutex;
 static struct lock_class_key cpuctx_lock;
 
-int perf_pmu_register(struct pmu *pmu, char *name, int type)
+int perf_pmu_register(struct pmu *pmu, const char *name, int type)
 {
        int cpu, ret;
 
@@ -6076,7 +6312,9 @@ skip_type:
                lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock);
                cpuctx->ctx.type = cpu_context;
                cpuctx->ctx.pmu = pmu;
-               cpuctx->jiffies_interval = 1;
+
+               __perf_cpu_hrtimer_init(cpuctx, cpu);
+
                INIT_LIST_HEAD(&cpuctx->rotation_list);
                cpuctx->unique_pmu = pmu;
        }
@@ -6402,11 +6640,6 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
                if (!(mask & ~PERF_SAMPLE_BRANCH_PLM_ALL))
                        return -EINVAL;
 
-               /* kernel level capture: check permissions */
-               if ((mask & PERF_SAMPLE_BRANCH_PERM_PLM)
-                   && perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN))
-                       return -EACCES;
-
                /* propagate priv level, when not set for branch */
                if (!(mask & PERF_SAMPLE_BRANCH_PLM_ALL)) {
 
@@ -6424,6 +6657,10 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
                         */
                        attr->branch_sample_type = mask;
                }
+               /* privileged levels capture (kernel, hv): check permissions */
+               if ((mask & PERF_SAMPLE_BRANCH_PERM_PLM)
+                   && perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN))
+                       return -EACCES;
        }
 
        if (attr->sample_type & PERF_SAMPLE_REGS_USER) {
@@ -7476,7 +7713,6 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
        case CPU_DOWN_PREPARE:
                perf_event_exit_cpu(cpu);
                break;
-
        default:
                break;
        }
index 20185ea64aa6f952022d0e8a1f64ffea044526da..1559fb0b929650fe8951ee4b5084717d9d0b4895 100644 (file)
 #include <linux/smp.h>
 
 #include <linux/hw_breakpoint.h>
-
-
 /*
  * Constraints data
  */
+struct bp_cpuinfo {
+       /* Number of pinned cpu breakpoints in a cpu */
+       unsigned int    cpu_pinned;
+       /* tsk_pinned[n] is the number of tasks having n+1 breakpoints */
+       unsigned int    *tsk_pinned;
+       /* Number of non-pinned cpu/task breakpoints in a cpu */
+       unsigned int    flexible; /* XXX: placeholder, see fetch_this_slot() */
+};
 
-/* Number of pinned cpu breakpoints in a cpu */
-static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned[TYPE_MAX]);
-
-/* Number of pinned task breakpoints in a cpu */
-static DEFINE_PER_CPU(unsigned int *, nr_task_bp_pinned[TYPE_MAX]);
-
-/* Number of non-pinned cpu/task breakpoints in a cpu */
-static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]);
-
+static DEFINE_PER_CPU(struct bp_cpuinfo, bp_cpuinfo[TYPE_MAX]);
 static int nr_slots[TYPE_MAX];
 
+static struct bp_cpuinfo *get_bp_info(int cpu, enum bp_type_idx type)
+{
+       return per_cpu_ptr(bp_cpuinfo + type, cpu);
+}
+
 /* Keep track of the breakpoints attached to tasks */
 static LIST_HEAD(bp_task_head);
 
@@ -96,8 +99,8 @@ static inline enum bp_type_idx find_slot_idx(struct perf_event *bp)
  */
 static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type)
 {
+       unsigned int *tsk_pinned = get_bp_info(cpu, type)->tsk_pinned;
        int i;
-       unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu);
 
        for (i = nr_slots[type] - 1; i >= 0; i--) {
                if (tsk_pinned[i] > 0)
@@ -127,6 +130,13 @@ static int task_bp_pinned(int cpu, struct perf_event *bp, enum bp_type_idx type)
        return count;
 }
 
+static const struct cpumask *cpumask_of_bp(struct perf_event *bp)
+{
+       if (bp->cpu >= 0)
+               return cpumask_of(bp->cpu);
+       return cpu_possible_mask;
+}
+
 /*
  * Report the number of pinned/un-pinned breakpoints we have in
  * a given cpu (cpu > -1) or in all of them (cpu = -1).
@@ -135,25 +145,15 @@ static void
 fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp,
                    enum bp_type_idx type)
 {
-       int cpu = bp->cpu;
-       struct task_struct *tsk = bp->hw.bp_target;
-
-       if (cpu >= 0) {
-               slots->pinned = per_cpu(nr_cpu_bp_pinned[type], cpu);
-               if (!tsk)
-                       slots->pinned += max_task_bp_pinned(cpu, type);
-               else
-                       slots->pinned += task_bp_pinned(cpu, bp, type);
-               slots->flexible = per_cpu(nr_bp_flexible[type], cpu);
-
-               return;
-       }
+       const struct cpumask *cpumask = cpumask_of_bp(bp);
+       int cpu;
 
-       for_each_possible_cpu(cpu) {
-               unsigned int nr;
+       for_each_cpu(cpu, cpumask) {
+               struct bp_cpuinfo *info = get_bp_info(cpu, type);
+               int nr;
 
-               nr = per_cpu(nr_cpu_bp_pinned[type], cpu);
-               if (!tsk)
+               nr = info->cpu_pinned;
+               if (!bp->hw.bp_target)
                        nr += max_task_bp_pinned(cpu, type);
                else
                        nr += task_bp_pinned(cpu, bp, type);
@@ -161,8 +161,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp,
                if (nr > slots->pinned)
                        slots->pinned = nr;
 
-               nr = per_cpu(nr_bp_flexible[type], cpu);
-
+               nr = info->flexible;
                if (nr > slots->flexible)
                        slots->flexible = nr;
        }
@@ -182,29 +181,19 @@ fetch_this_slot(struct bp_busy_slots *slots, int weight)
 /*
  * Add a pinned breakpoint for the given task in our constraint table
  */
-static void toggle_bp_task_slot(struct perf_event *bp, int cpu, bool enable,
+static void toggle_bp_task_slot(struct perf_event *bp, int cpu,
                                enum bp_type_idx type, int weight)
 {
-       unsigned int *tsk_pinned;
-       int old_count = 0;
-       int old_idx = 0;
-       int idx = 0;
-
-       old_count = task_bp_pinned(cpu, bp, type);
-       old_idx = old_count - 1;
-       idx = old_idx + weight;
-
-       /* tsk_pinned[n] is the number of tasks having n breakpoints */
-       tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu);
-       if (enable) {
-               tsk_pinned[idx]++;
-               if (old_count > 0)
-                       tsk_pinned[old_idx]--;
-       } else {
-               tsk_pinned[idx]--;
-               if (old_count > 0)
-                       tsk_pinned[old_idx]++;
-       }
+       unsigned int *tsk_pinned = get_bp_info(cpu, type)->tsk_pinned;
+       int old_idx, new_idx;
+
+       old_idx = task_bp_pinned(cpu, bp, type) - 1;
+       new_idx = old_idx + weight;
+
+       if (old_idx >= 0)
+               tsk_pinned[old_idx]--;
+       if (new_idx >= 0)
+               tsk_pinned[new_idx]++;
 }
 
 /*
@@ -214,33 +203,26 @@ static void
 toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type,
               int weight)
 {
-       int cpu = bp->cpu;
-       struct task_struct *tsk = bp->hw.bp_target;
+       const struct cpumask *cpumask = cpumask_of_bp(bp);
+       int cpu;
 
-       /* Pinned counter cpu profiling */
-       if (!tsk) {
+       if (!enable)
+               weight = -weight;
 
-               if (enable)
-                       per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight;
-               else
-                       per_cpu(nr_cpu_bp_pinned[type], bp->cpu) -= weight;
+       /* Pinned counter cpu profiling */
+       if (!bp->hw.bp_target) {
+               get_bp_info(bp->cpu, type)->cpu_pinned += weight;
                return;
        }
 
        /* Pinned counter task profiling */
-
-       if (!enable)
-               list_del(&bp->hw.bp_list);
-
-       if (cpu >= 0) {
-               toggle_bp_task_slot(bp, cpu, enable, type, weight);
-       } else {
-               for_each_possible_cpu(cpu)
-                       toggle_bp_task_slot(bp, cpu, enable, type, weight);
-       }
+       for_each_cpu(cpu, cpumask)
+               toggle_bp_task_slot(bp, cpu, type, weight);
 
        if (enable)
                list_add_tail(&bp->hw.bp_list, &bp_task_head);
+       else
+               list_del(&bp->hw.bp_list);
 }
 
 /*
@@ -261,8 +243,8 @@ __weak void arch_unregister_hw_breakpoint(struct perf_event *bp)
  *
  *   - If attached to a single cpu, check:
  *
- *       (per_cpu(nr_bp_flexible, cpu) || (per_cpu(nr_cpu_bp_pinned, cpu)
- *           + max(per_cpu(nr_task_bp_pinned, cpu)))) < HBP_NUM
+ *       (per_cpu(info->flexible, cpu) || (per_cpu(info->cpu_pinned, cpu)
+ *           + max(per_cpu(info->tsk_pinned, cpu)))) < HBP_NUM
  *
  *       -> If there are already non-pinned counters in this cpu, it means
  *          there is already a free slot for them.
@@ -272,8 +254,8 @@ __weak void arch_unregister_hw_breakpoint(struct perf_event *bp)
  *
  *   - If attached to every cpus, check:
  *
- *       (per_cpu(nr_bp_flexible, *) || (max(per_cpu(nr_cpu_bp_pinned, *))
- *           + max(per_cpu(nr_task_bp_pinned, *)))) < HBP_NUM
+ *       (per_cpu(info->flexible, *) || (max(per_cpu(info->cpu_pinned, *))
+ *           + max(per_cpu(info->tsk_pinned, *)))) < HBP_NUM
  *
  *       -> This is roughly the same, except we check the number of per cpu
  *          bp for every cpu and we keep the max one. Same for the per tasks
@@ -284,16 +266,16 @@ __weak void arch_unregister_hw_breakpoint(struct perf_event *bp)
  *
  *   - If attached to a single cpu, check:
  *
- *       ((per_cpu(nr_bp_flexible, cpu) > 1) + per_cpu(nr_cpu_bp_pinned, cpu)
- *            + max(per_cpu(nr_task_bp_pinned, cpu))) < HBP_NUM
+ *       ((per_cpu(info->flexible, cpu) > 1) + per_cpu(info->cpu_pinned, cpu)
+ *            + max(per_cpu(info->tsk_pinned, cpu))) < HBP_NUM
  *
- *       -> Same checks as before. But now the nr_bp_flexible, if any, must keep
+ *       -> Same checks as before. But now the info->flexible, if any, must keep
  *          one register at least (or they will never be fed).
  *
  *   - If attached to every cpus, check:
  *
- *       ((per_cpu(nr_bp_flexible, *) > 1) + max(per_cpu(nr_cpu_bp_pinned, *))
- *            + max(per_cpu(nr_task_bp_pinned, *))) < HBP_NUM
+ *       ((per_cpu(info->flexible, *) > 1) + max(per_cpu(info->cpu_pinned, *))
+ *            + max(per_cpu(info->tsk_pinned, *))) < HBP_NUM
  */
 static int __reserve_bp_slot(struct perf_event *bp)
 {
@@ -518,8 +500,8 @@ register_wide_hw_breakpoint(struct perf_event_attr *attr,
                            perf_overflow_handler_t triggered,
                            void *context)
 {
-       struct perf_event * __percpu *cpu_events, **pevent, *bp;
-       long err;
+       struct perf_event * __percpu *cpu_events, *bp;
+       long err = 0;
        int cpu;
 
        cpu_events = alloc_percpu(typeof(*cpu_events));
@@ -528,31 +510,21 @@ register_wide_hw_breakpoint(struct perf_event_attr *attr,
 
        get_online_cpus();
        for_each_online_cpu(cpu) {
-               pevent = per_cpu_ptr(cpu_events, cpu);
                bp = perf_event_create_kernel_counter(attr, cpu, NULL,
                                                      triggered, context);
-
-               *pevent = bp;
-
                if (IS_ERR(bp)) {
                        err = PTR_ERR(bp);
-                       goto fail;
+                       break;
                }
-       }
-       put_online_cpus();
 
-       return cpu_events;
-
-fail:
-       for_each_online_cpu(cpu) {
-               pevent = per_cpu_ptr(cpu_events, cpu);
-               if (IS_ERR(*pevent))
-                       break;
-               unregister_hw_breakpoint(*pevent);
+               per_cpu(*cpu_events, cpu) = bp;
        }
        put_online_cpus();
 
-       free_percpu(cpu_events);
+       if (likely(!err))
+               return cpu_events;
+
+       unregister_wide_hw_breakpoint(cpu_events);
        return (void __percpu __force *)ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(register_wide_hw_breakpoint);
@@ -564,12 +536,10 @@ EXPORT_SYMBOL_GPL(register_wide_hw_breakpoint);
 void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events)
 {
        int cpu;
-       struct perf_event **pevent;
 
-       for_each_possible_cpu(cpu) {
-               pevent = per_cpu_ptr(cpu_events, cpu);
-               unregister_hw_breakpoint(*pevent);
-       }
+       for_each_possible_cpu(cpu)
+               unregister_hw_breakpoint(per_cpu(*cpu_events, cpu));
+
        free_percpu(cpu_events);
 }
 EXPORT_SYMBOL_GPL(unregister_wide_hw_breakpoint);
@@ -612,6 +582,11 @@ static int hw_breakpoint_add(struct perf_event *bp, int flags)
        if (!(flags & PERF_EF_START))
                bp->hw.state = PERF_HES_STOPPED;
 
+       if (is_sampling_event(bp)) {
+               bp->hw.last_period = bp->hw.sample_period;
+               perf_swevent_set_period(bp);
+       }
+
        return arch_install_hw_breakpoint(bp);
 }
 
@@ -650,7 +625,6 @@ static struct pmu perf_breakpoint = {
 
 int __init init_hw_breakpoint(void)
 {
-       unsigned int **task_bp_pinned;
        int cpu, err_cpu;
        int i;
 
@@ -659,10 +633,11 @@ int __init init_hw_breakpoint(void)
 
        for_each_possible_cpu(cpu) {
                for (i = 0; i < TYPE_MAX; i++) {
-                       task_bp_pinned = &per_cpu(nr_task_bp_pinned[i], cpu);
-                       *task_bp_pinned = kzalloc(sizeof(int) * nr_slots[i],
-                                                 GFP_KERNEL);
-                       if (!*task_bp_pinned)
+                       struct bp_cpuinfo *info = get_bp_info(cpu, i);
+
+                       info->tsk_pinned = kcalloc(nr_slots[i], sizeof(int),
+                                                       GFP_KERNEL);
+                       if (!info->tsk_pinned)
                                goto err_alloc;
                }
        }
@@ -676,7 +651,7 @@ int __init init_hw_breakpoint(void)
  err_alloc:
        for_each_possible_cpu(err_cpu) {
                for (i = 0; i < TYPE_MAX; i++)
-                       kfree(per_cpu(nr_task_bp_pinned[i], err_cpu));
+                       kfree(get_bp_info(err_cpu, i)->tsk_pinned);
                if (err_cpu == cpu)
                        break;
        }
index 7bb73f9d09dbeedcc6c07f6a8dc8257f76fc4963..fafe75d9e6f6fdfc0bab7ff7104d7e2ad97199ca 100644 (file)
@@ -312,17 +312,6 @@ kill_orphaned_pgrp(struct task_struct *tsk, struct task_struct *parent)
        }
 }
 
-void __set_special_pids(struct pid *pid)
-{
-       struct task_struct *curr = current->group_leader;
-
-       if (task_session(curr) != pid)
-               change_pid(curr, PIDTYPE_SID, pid);
-
-       if (task_pgrp(curr) != pid)
-               change_pid(curr, PIDTYPE_PGID, pid);
-}
-
 /*
  * Let kernel threads use this to say that they allow a certain signal.
  * Must not be used if kthread was cloned with CLONE_SIGHAND.
@@ -835,7 +824,7 @@ void do_exit(long code)
        /*
         * Make sure we are holding no locks:
         */
-       debug_check_no_locks_held(tsk);
+       debug_check_no_locks_held();
        /*
         * We can do this unlocked here. The futex code uses this flag
         * just to verify whether the pi state cleanup has been done
index 987b28a1f01b6c6ce5d554eb22d9c89e1cde1e7b..6e6a1c11b3e5939bda764882801a5dd28e904f30 100644 (file)
@@ -1121,6 +1121,12 @@ static void posix_cpu_timers_init(struct task_struct *tsk)
        INIT_LIST_HEAD(&tsk->cpu_timers[2]);
 }
 
+static inline void
+init_task_pid(struct task_struct *task, enum pid_type type, struct pid *pid)
+{
+        task->pids[type].pid = pid;
+}
+
 /*
  * This creates a new process as a copy of the old one,
  * but does not actually start it yet.
@@ -1199,8 +1205,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        retval = -EAGAIN;
        if (atomic_read(&p->real_cred->user->processes) >=
                        task_rlimit(p, RLIMIT_NPROC)) {
-               if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
-                   p->real_cred->user != INIT_USER)
+               if (p->real_cred->user != INIT_USER &&
+                   !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))
                        goto bad_fork_free;
        }
        current->flags &= ~PF_NPROC_EXCEEDED;
@@ -1354,11 +1360,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                        goto bad_fork_cleanup_io;
        }
 
-       p->pid = pid_nr(pid);
-       p->tgid = p->pid;
-       if (clone_flags & CLONE_THREAD)
-               p->tgid = current->tgid;
-
        p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
        /*
         * Clear TID on mm_release()?
@@ -1394,12 +1395,19 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        clear_all_latency_tracing(p);
 
        /* ok, now we should be set up.. */
-       if (clone_flags & CLONE_THREAD)
+       p->pid = pid_nr(pid);
+       if (clone_flags & CLONE_THREAD) {
                p->exit_signal = -1;
-       else if (clone_flags & CLONE_PARENT)
-               p->exit_signal = current->group_leader->exit_signal;
-       else
-               p->exit_signal = (clone_flags & CSIGNAL);
+               p->group_leader = current->group_leader;
+               p->tgid = current->tgid;
+       } else {
+               if (clone_flags & CLONE_PARENT)
+                       p->exit_signal = current->group_leader->exit_signal;
+               else
+                       p->exit_signal = (clone_flags & CSIGNAL);
+               p->group_leader = p;
+               p->tgid = p->pid;
+       }
 
        p->pdeath_signal = 0;
        p->exit_state = 0;
@@ -1408,15 +1416,13 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        p->nr_dirtied_pause = 128 >> (PAGE_SHIFT - 10);
        p->dirty_paused_when = 0;
 
-       /*
-        * Ok, make it visible to the rest of the system.
-        * We dont wake it up yet.
-        */
-       p->group_leader = p;
        INIT_LIST_HEAD(&p->thread_group);
        p->task_works = NULL;
 
-       /* Need tasklist lock for parent etc handling! */
+       /*
+        * Make it visible to the rest of the system, but dont wake it up yet.
+        * Need tasklist lock for parent etc handling!
+        */
        write_lock_irq(&tasklist_lock);
 
        /* CLONE_PARENT re-uses the old parent */
@@ -1446,18 +1452,14 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                goto bad_fork_free_pid;
        }
 
-       if (clone_flags & CLONE_THREAD) {
-               current->signal->nr_threads++;
-               atomic_inc(&current->signal->live);
-               atomic_inc(&current->signal->sigcnt);
-               p->group_leader = current->group_leader;
-               list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);
-       }
-
        if (likely(p->pid)) {
                ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);
 
+               init_task_pid(p, PIDTYPE_PID, pid);
                if (thread_group_leader(p)) {
+                       init_task_pid(p, PIDTYPE_PGID, task_pgrp(current));
+                       init_task_pid(p, PIDTYPE_SID, task_session(current));
+
                        if (is_child_reaper(pid)) {
                                ns_of_pid(pid)->child_reaper = p;
                                p->signal->flags |= SIGNAL_UNKILLABLE;
@@ -1465,13 +1467,19 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
                        p->signal->leader_pid = pid;
                        p->signal->tty = tty_kref_get(current->signal->tty);
-                       attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
-                       attach_pid(p, PIDTYPE_SID, task_session(current));
                        list_add_tail(&p->sibling, &p->real_parent->children);
                        list_add_tail_rcu(&p->tasks, &init_task.tasks);
+                       attach_pid(p, PIDTYPE_PGID);
+                       attach_pid(p, PIDTYPE_SID);
                        __this_cpu_inc(process_counts);
+               } else {
+                       current->signal->nr_threads++;
+                       atomic_inc(&current->signal->live);
+                       atomic_inc(&current->signal->sigcnt);
+                       list_add_tail_rcu(&p->thread_group,
+                                         &p->group_leader->thread_group);
                }
-               attach_pid(p, PIDTYPE_PID, pid);
+               attach_pid(p, PIDTYPE_PID);
                nr_threads++;
        }
 
index c38893b0efbaa39d770b11546dba9e97ec53ff51..8b2afc1c9df0c698eccd86664d25c33ed647fea7 100644 (file)
@@ -110,6 +110,18 @@ bool freeze_task(struct task_struct *p)
 {
        unsigned long flags;
 
+       /*
+        * This check can race with freezer_do_not_count, but worst case that
+        * will result in an extra wakeup being sent to the task.  It does not
+        * race with freezer_count(), the barriers in freezer_count() and
+        * freezer_should_skip() ensure that either freezer_count() sees
+        * freezing == true in try_to_freeze() and freezes, or
+        * freezer_should_skip() sees !PF_FREEZE_SKIP and freezes the task
+        * normally.
+        */
+       if (freezer_should_skip(p))
+               return false;
+
        spin_lock_irqsave(&freezer_lock, flags);
        if (!freezing(p) || frozen(p)) {
                spin_unlock_irqrestore(&freezer_lock, flags);
index b26dcfc02c9489b3ca00bfd076f2208bb4964366..c3a1a55a52141851630b91f2bff2aa789b508ace 100644 (file)
@@ -61,6 +61,8 @@
 #include <linux/nsproxy.h>
 #include <linux/ptrace.h>
 #include <linux/sched/rt.h>
+#include <linux/hugetlb.h>
+#include <linux/freezer.h>
 
 #include <asm/futex.h>
 
@@ -365,7 +367,7 @@ again:
        } else {
                key->both.offset |= FUT_OFF_INODE; /* inode-based key */
                key->shared.inode = page_head->mapping->host;
-               key->shared.pgoff = page_head->index;
+               key->shared.pgoff = basepage_index(page);
        }
 
        get_futex_key_refs(key);
@@ -1807,7 +1809,7 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
                 * is no timeout, or if it has yet to expire.
                 */
                if (!timeout || timeout->task)
-                       schedule();
+                       freezable_schedule();
        }
        __set_current_state(TASK_RUNNING);
 }
index fd4b13b131f8db23fb17055caf5d33e23bec7b50..3ee4d06c6fc20bda08fa052a1c42d70c7d094cb8 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/sched/sysctl.h>
 #include <linux/sched/rt.h>
 #include <linux/timer.h>
+#include <linux/freezer.h>
 
 #include <asm/uaccess.h>
 
@@ -1545,7 +1546,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
                        t->task = NULL;
 
                if (likely(t->task))
-                       schedule();
+                       freezable_schedule();
 
                hrtimer_cancel(&t->timer);
                mode = HRTIMER_MODE_ABS;
index cbd97ce0b0007c0daaa15255e3417bda9140b688..a3bb14fbe5c61fec344a166f8b542571dab4704c 100644 (file)
@@ -213,6 +213,19 @@ void irq_enable(struct irq_desc *desc)
        irq_state_clr_masked(desc);
 }
 
+/**
+ * irq_disable - Mark interupt disabled
+ * @desc:      irq descriptor which should be disabled
+ *
+ * If the chip does not implement the irq_disable callback, we
+ * use a lazy disable approach. That means we mark the interrupt
+ * disabled, but leave the hardware unmasked. That's an
+ * optimization because we avoid the hardware access for the
+ * common case where no interrupt happens after we marked it
+ * disabled. If an interrupt happens, then the interrupt flow
+ * handler masks the line at the hardware level and marks it
+ * pending.
+ */
 void irq_disable(struct irq_desc *desc)
 {
        irq_state_set_disabled(desc);
index c89295a8f6687098db746f9f81b99132a2f0c145..1c39eccc1eaf21225f00ae605f8b19db1c5c68b1 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/irq.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/irqdomain.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/syscore_ops.h>
 static LIST_HEAD(gc_list);
 static DEFINE_RAW_SPINLOCK(gc_lock);
 
-static inline struct irq_chip_regs *cur_regs(struct irq_data *d)
-{
-       return &container_of(d->chip, struct irq_chip_type, chip)->regs;
-}
-
 /**
  * irq_gc_noop - NOOP function
  * @d: irq_data
@@ -39,16 +35,17 @@ void irq_gc_noop(struct irq_data *d)
 void irq_gc_mask_disable_reg(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
-       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->disable);
-       gc->mask_cache &= ~mask;
+       irq_reg_writel(mask, gc->reg_base + ct->regs.disable);
+       *ct->mask_cache &= ~mask;
        irq_gc_unlock(gc);
 }
 
 /**
- * irq_gc_mask_set_mask_bit - Mask chip via setting bit in mask register
+ * irq_gc_mask_set_bit - Mask chip via setting bit in mask register
  * @d: irq_data
  *
  * Chip has a single mask register. Values of this register are cached
@@ -57,16 +54,18 @@ void irq_gc_mask_disable_reg(struct irq_data *d)
 void irq_gc_mask_set_bit(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
-       gc->mask_cache |= mask;
-       irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask);
+       *ct->mask_cache |= mask;
+       irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask);
        irq_gc_unlock(gc);
 }
+EXPORT_SYMBOL_GPL(irq_gc_mask_set_bit);
 
 /**
- * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register
+ * irq_gc_mask_clr_bit - Mask chip via clearing bit in mask register
  * @d: irq_data
  *
  * Chip has a single mask register. Values of this register are cached
@@ -75,13 +74,15 @@ void irq_gc_mask_set_bit(struct irq_data *d)
 void irq_gc_mask_clr_bit(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
-       gc->mask_cache &= ~mask;
-       irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask);
+       *ct->mask_cache &= ~mask;
+       irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask);
        irq_gc_unlock(gc);
 }
+EXPORT_SYMBOL_GPL(irq_gc_mask_clr_bit);
 
 /**
  * irq_gc_unmask_enable_reg - Unmask chip via enable register
@@ -93,11 +94,12 @@ void irq_gc_mask_clr_bit(struct irq_data *d)
 void irq_gc_unmask_enable_reg(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
-       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->enable);
-       gc->mask_cache |= mask;
+       irq_reg_writel(mask, gc->reg_base + ct->regs.enable);
+       *ct->mask_cache |= mask;
        irq_gc_unlock(gc);
 }
 
@@ -108,12 +110,14 @@ void irq_gc_unmask_enable_reg(struct irq_data *d)
 void irq_gc_ack_set_bit(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
-       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack);
+       irq_reg_writel(mask, gc->reg_base + ct->regs.ack);
        irq_gc_unlock(gc);
 }
+EXPORT_SYMBOL_GPL(irq_gc_ack_set_bit);
 
 /**
  * irq_gc_ack_clr_bit - Ack pending interrupt via clearing bit
@@ -122,10 +126,11 @@ void irq_gc_ack_set_bit(struct irq_data *d)
 void irq_gc_ack_clr_bit(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       u32 mask = ~(1 << (d->irq - gc->irq_base));
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       u32 mask = ~d->mask;
 
        irq_gc_lock(gc);
-       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack);
+       irq_reg_writel(mask, gc->reg_base + ct->regs.ack);
        irq_gc_unlock(gc);
 }
 
@@ -136,11 +141,12 @@ void irq_gc_ack_clr_bit(struct irq_data *d)
 void irq_gc_mask_disable_reg_and_ack(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
-       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->mask);
-       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack);
+       irq_reg_writel(mask, gc->reg_base + ct->regs.mask);
+       irq_reg_writel(mask, gc->reg_base + ct->regs.ack);
        irq_gc_unlock(gc);
 }
 
@@ -151,16 +157,18 @@ void irq_gc_mask_disable_reg_and_ack(struct irq_data *d)
 void irq_gc_eoi(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       u32 mask = d->mask;
 
        irq_gc_lock(gc);
-       irq_reg_writel(mask, gc->reg_base + cur_regs(d)->eoi);
+       irq_reg_writel(mask, gc->reg_base + ct->regs.eoi);
        irq_gc_unlock(gc);
 }
 
 /**
  * irq_gc_set_wake - Set/clr wake bit for an interrupt
- * @d: irq_data
+ * @d:  irq_data
+ * @on: Indicates whether the wake bit should be set or cleared
  *
  * For chips where the wake from suspend functionality is not
  * configured in a separate register and the wakeup active state is
@@ -169,7 +177,7 @@ void irq_gc_eoi(struct irq_data *d)
 int irq_gc_set_wake(struct irq_data *d, unsigned int on)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << (d->irq - gc->irq_base);
+       u32 mask = d->mask;
 
        if (!(mask & gc->wake_enabled))
                return -EINVAL;
@@ -183,6 +191,19 @@ int irq_gc_set_wake(struct irq_data *d, unsigned int on)
        return 0;
 }
 
+static void
+irq_init_generic_chip(struct irq_chip_generic *gc, const char *name,
+                     int num_ct, unsigned int irq_base,
+                     void __iomem *reg_base, irq_flow_handler_t handler)
+{
+       raw_spin_lock_init(&gc->lock);
+       gc->num_ct = num_ct;
+       gc->irq_base = irq_base;
+       gc->reg_base = reg_base;
+       gc->chip_types->chip.name = name;
+       gc->chip_types->handler = handler;
+}
+
 /**
  * irq_alloc_generic_chip - Allocate a generic chip and initialize it
  * @name:      Name of the irq chip
@@ -203,23 +224,185 @@ irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base,
 
        gc = kzalloc(sz, GFP_KERNEL);
        if (gc) {
-               raw_spin_lock_init(&gc->lock);
-               gc->num_ct = num_ct;
-               gc->irq_base = irq_base;
-               gc->reg_base = reg_base;
-               gc->chip_types->chip.name = name;
-               gc->chip_types->handler = handler;
+               irq_init_generic_chip(gc, name, num_ct, irq_base, reg_base,
+                                     handler);
        }
        return gc;
 }
 EXPORT_SYMBOL_GPL(irq_alloc_generic_chip);
 
+static void
+irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags)
+{
+       struct irq_chip_type *ct = gc->chip_types;
+       u32 *mskptr = &gc->mask_cache, mskreg = ct->regs.mask;
+       int i;
+
+       for (i = 0; i < gc->num_ct; i++) {
+               if (flags & IRQ_GC_MASK_CACHE_PER_TYPE) {
+                       mskptr = &ct[i].mask_cache_priv;
+                       mskreg = ct[i].regs.mask;
+               }
+               ct[i].mask_cache = mskptr;
+               if (flags & IRQ_GC_INIT_MASK_CACHE)
+                       *mskptr = irq_reg_readl(gc->reg_base + mskreg);
+       }
+}
+
+/**
+ * irq_alloc_domain_generic_chip - Allocate generic chips for an irq domain
+ * @d:                 irq domain for which to allocate chips
+ * @irqs_per_chip:     Number of interrupts each chip handles
+ * @num_ct:            Number of irq_chip_type instances associated with this
+ * @name:              Name of the irq chip
+ * @handler:           Default flow handler associated with these chips
+ * @clr:               IRQ_* bits to clear in the mapping function
+ * @set:               IRQ_* bits to set in the mapping function
+ * @gcflags:           Generic chip specific setup flags
+ */
+int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
+                                  int num_ct, const char *name,
+                                  irq_flow_handler_t handler,
+                                  unsigned int clr, unsigned int set,
+                                  enum irq_gc_flags gcflags)
+{
+       struct irq_domain_chip_generic *dgc;
+       struct irq_chip_generic *gc;
+       int numchips, sz, i;
+       unsigned long flags;
+       void *tmp;
+
+       if (d->gc)
+               return -EBUSY;
+
+       if (d->revmap_type != IRQ_DOMAIN_MAP_LINEAR)
+               return -EINVAL;
+
+       numchips = d->revmap_data.linear.size / irqs_per_chip;
+       if (!numchips)
+               return -EINVAL;
+
+       /* Allocate a pointer, generic chip and chiptypes for each chip */
+       sz = sizeof(*dgc) + numchips * sizeof(gc);
+       sz += numchips * (sizeof(*gc) + num_ct * sizeof(struct irq_chip_type));
+
+       tmp = dgc = kzalloc(sz, GFP_KERNEL);
+       if (!dgc)
+               return -ENOMEM;
+       dgc->irqs_per_chip = irqs_per_chip;
+       dgc->num_chips = numchips;
+       dgc->irq_flags_to_set = set;
+       dgc->irq_flags_to_clear = clr;
+       dgc->gc_flags = gcflags;
+       d->gc = dgc;
+
+       /* Calc pointer to the first generic chip */
+       tmp += sizeof(*dgc) + numchips * sizeof(gc);
+       for (i = 0; i < numchips; i++) {
+               /* Store the pointer to the generic chip */
+               dgc->gc[i] = gc = tmp;
+               irq_init_generic_chip(gc, name, num_ct, i * irqs_per_chip,
+                                     NULL, handler);
+               gc->domain = d;
+               raw_spin_lock_irqsave(&gc_lock, flags);
+               list_add_tail(&gc->list, &gc_list);
+               raw_spin_unlock_irqrestore(&gc_lock, flags);
+               /* Calc pointer to the next generic chip */
+               tmp += sizeof(*gc) + num_ct * sizeof(struct irq_chip_type);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(irq_alloc_domain_generic_chips);
+
+/**
+ * irq_get_domain_generic_chip - Get a pointer to the generic chip of a hw_irq
+ * @d:                 irq domain pointer
+ * @hw_irq:            Hardware interrupt number
+ */
+struct irq_chip_generic *
+irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq)
+{
+       struct irq_domain_chip_generic *dgc = d->gc;
+       int idx;
+
+       if (!dgc)
+               return NULL;
+       idx = hw_irq / dgc->irqs_per_chip;
+       if (idx >= dgc->num_chips)
+               return NULL;
+       return dgc->gc[idx];
+}
+EXPORT_SYMBOL_GPL(irq_get_domain_generic_chip);
+
 /*
  * Separate lockdep class for interrupt chip which can nest irq_desc
  * lock.
  */
 static struct lock_class_key irq_nested_lock_class;
 
+/*
+ * irq_map_generic_chip - Map a generic chip for an irq domain
+ */
+static int irq_map_generic_chip(struct irq_domain *d, unsigned int virq,
+                               irq_hw_number_t hw_irq)
+{
+       struct irq_data *data = irq_get_irq_data(virq);
+       struct irq_domain_chip_generic *dgc = d->gc;
+       struct irq_chip_generic *gc;
+       struct irq_chip_type *ct;
+       struct irq_chip *chip;
+       unsigned long flags;
+       int idx;
+
+       if (!d->gc)
+               return -ENODEV;
+
+       idx = hw_irq / dgc->irqs_per_chip;
+       if (idx >= dgc->num_chips)
+               return -EINVAL;
+       gc = dgc->gc[idx];
+
+       idx = hw_irq % dgc->irqs_per_chip;
+
+       if (test_bit(idx, &gc->unused))
+               return -ENOTSUPP;
+
+       if (test_bit(idx, &gc->installed))
+               return -EBUSY;
+
+       ct = gc->chip_types;
+       chip = &ct->chip;
+
+       /* We only init the cache for the first mapping of a generic chip */
+       if (!gc->installed) {
+               raw_spin_lock_irqsave(&gc->lock, flags);
+               irq_gc_init_mask_cache(gc, dgc->gc_flags);
+               raw_spin_unlock_irqrestore(&gc->lock, flags);
+       }
+
+       /* Mark the interrupt as installed */
+       set_bit(idx, &gc->installed);
+
+       if (dgc->gc_flags & IRQ_GC_INIT_NESTED_LOCK)
+               irq_set_lockdep_class(virq, &irq_nested_lock_class);
+
+       if (chip->irq_calc_mask)
+               chip->irq_calc_mask(data);
+       else
+               data->mask = 1 << idx;
+
+       irq_set_chip_and_handler(virq, chip, ct->handler);
+       irq_set_chip_data(virq, gc);
+       irq_modify_status(virq, dgc->irq_flags_to_clear, dgc->irq_flags_to_set);
+       return 0;
+}
+
+struct irq_domain_ops irq_generic_chip_ops = {
+       .map    = irq_map_generic_chip,
+       .xlate  = irq_domain_xlate_onetwocell,
+};
+EXPORT_SYMBOL_GPL(irq_generic_chip_ops);
+
 /**
  * irq_setup_generic_chip - Setup a range of interrupts with a generic chip
  * @gc:                Generic irq chip holding all data
@@ -237,15 +420,14 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
                            unsigned int set)
 {
        struct irq_chip_type *ct = gc->chip_types;
+       struct irq_chip *chip = &ct->chip;
        unsigned int i;
 
        raw_spin_lock(&gc_lock);
        list_add_tail(&gc->list, &gc_list);
        raw_spin_unlock(&gc_lock);
 
-       /* Init mask cache ? */
-       if (flags & IRQ_GC_INIT_MASK_CACHE)
-               gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask);
+       irq_gc_init_mask_cache(gc, flags);
 
        for (i = gc->irq_base; msk; msk >>= 1, i++) {
                if (!(msk & 0x01))
@@ -254,7 +436,15 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
                if (flags & IRQ_GC_INIT_NESTED_LOCK)
                        irq_set_lockdep_class(i, &irq_nested_lock_class);
 
-               irq_set_chip_and_handler(i, &ct->chip, ct->handler);
+               if (!(flags & IRQ_GC_NO_MASK)) {
+                       struct irq_data *d = irq_get_irq_data(i);
+
+                       if (chip->irq_calc_mask)
+                               chip->irq_calc_mask(d);
+                       else
+                               d->mask = 1 << (i - gc->irq_base);
+               }
+               irq_set_chip_and_handler(i, chip, ct->handler);
                irq_set_chip_data(i, gc);
                irq_modify_status(i, clr, set);
        }
@@ -265,7 +455,7 @@ EXPORT_SYMBOL_GPL(irq_setup_generic_chip);
 /**
  * irq_setup_alt_chip - Switch to alternative chip
  * @d:         irq_data for this interrupt
- * @type       Flow type to be initialized
+ * @type:      Flow type to be initialized
  *
  * Only to be called from chip->irq_set_type() callbacks.
  */
@@ -317,6 +507,24 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
 }
 EXPORT_SYMBOL_GPL(irq_remove_generic_chip);
 
+static struct irq_data *irq_gc_get_irq_data(struct irq_chip_generic *gc)
+{
+       unsigned int virq;
+
+       if (!gc->domain)
+               return irq_get_irq_data(gc->irq_base);
+
+       /*
+        * We don't know which of the irqs has been actually
+        * installed. Use the first one.
+        */
+       if (!gc->installed)
+               return NULL;
+
+       virq = irq_find_mapping(gc->domain, gc->irq_base + __ffs(gc->installed));
+       return virq ? irq_get_irq_data(virq) : NULL;
+}
+
 #ifdef CONFIG_PM
 static int irq_gc_suspend(void)
 {
@@ -325,8 +533,12 @@ static int irq_gc_suspend(void)
        list_for_each_entry(gc, &gc_list, list) {
                struct irq_chip_type *ct = gc->chip_types;
 
-               if (ct->chip.irq_suspend)
-                       ct->chip.irq_suspend(irq_get_irq_data(gc->irq_base));
+               if (ct->chip.irq_suspend) {
+                       struct irq_data *data = irq_gc_get_irq_data(gc);
+
+                       if (data)
+                               ct->chip.irq_suspend(data);
+               }
        }
        return 0;
 }
@@ -338,8 +550,12 @@ static void irq_gc_resume(void)
        list_for_each_entry(gc, &gc_list, list) {
                struct irq_chip_type *ct = gc->chip_types;
 
-               if (ct->chip.irq_resume)
-                       ct->chip.irq_resume(irq_get_irq_data(gc->irq_base));
+               if (ct->chip.irq_resume) {
+                       struct irq_data *data = irq_gc_get_irq_data(gc);
+
+                       if (data)
+                               ct->chip.irq_resume(data);
+               }
        }
 }
 #else
@@ -354,8 +570,12 @@ static void irq_gc_shutdown(void)
        list_for_each_entry(gc, &gc_list, list) {
                struct irq_chip_type *ct = gc->chip_types;
 
-               if (ct->chip.irq_pm_shutdown)
-                       ct->chip.irq_pm_shutdown(irq_get_irq_data(gc->irq_base));
+               if (ct->chip.irq_pm_shutdown) {
+                       struct irq_data *data = irq_gc_get_irq_data(gc);
+
+                       if (data)
+                               ct->chip.irq_pm_shutdown(data);
+               }
        }
 }
 
index 54a4d5223238e15843559d16386bc4cdc1e63f25..1ed8dff17eb9041e31e18829d6d86734f33fdc7d 100644 (file)
 #include <linux/smp.h>
 #include <linux/fs.h>
 
-#define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs.
-                                * ie. legacy 8259, gets irqs 1..15 */
-#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
-#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
-#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
-
 static LIST_HEAD(irq_domain_list);
 static DEFINE_MUTEX(irq_domain_mutex);
 
@@ -698,7 +692,7 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
 
        /* Set type if specified and different than the current one */
        if (type != IRQ_TYPE_NONE &&
-           type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
+           type != irq_get_trigger_type(virq))
                irq_set_irq_type(virq, type);
        return virq;
 }
index fa17855ca65a235bd5c1f9a7daa042b57722b924..514bcfd855a8f9c05ef2934f364f6c2d7b600e4e 100644 (file)
@@ -555,9 +555,9 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
                return 0;
 
        if (irq_settings_can_request(desc)) {
-               if (desc->action)
-                       if (irqflags & desc->action->flags & IRQF_SHARED)
-                               canrequest =1;
+               if (!desc->action ||
+                   irqflags & desc->action->flags & IRQF_SHARED)
+                       canrequest = 1;
        }
        irq_put_desc_unlock(desc, flags);
        return canrequest;
@@ -840,9 +840,6 @@ static void irq_thread_dtor(struct callback_head *unused)
 static int irq_thread(void *data)
 {
        struct callback_head on_exit_work;
-       static const struct sched_param param = {
-               .sched_priority = MAX_USER_RT_PRIO/2,
-       };
        struct irqaction *action = data;
        struct irq_desc *desc = irq_to_desc(action->irq);
        irqreturn_t (*handler_fn)(struct irq_desc *desc,
@@ -854,8 +851,6 @@ static int irq_thread(void *data)
        else
                handler_fn = irq_thread_fn;
 
-       sched_setscheduler(current, SCHED_FIFO, &param);
-
        init_task_work(&on_exit_work, irq_thread_dtor);
        task_work_add(current, &on_exit_work, false);
 
@@ -950,6 +945,9 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
         */
        if (new->thread_fn && !nested) {
                struct task_struct *t;
+               static const struct sched_param param = {
+                       .sched_priority = MAX_USER_RT_PRIO/2,
+               };
 
                t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
                                   new->name);
@@ -957,6 +955,9 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                        ret = PTR_ERR(t);
                        goto out_mput;
                }
+
+               sched_setscheduler(t, SCHED_FIFO, &param);
+
                /*
                 * We keep the reference to the task struct even if
                 * the thread dies to avoid that the interrupt code
index 8241906c4b61a0887304f6524516563707d1a876..fb326365b69466158b03b726e53c4fe15448fa89 100644 (file)
@@ -147,6 +147,9 @@ int __request_module(bool wait, const char *fmt, ...)
         */
        WARN_ON_ONCE(wait && current_is_async());
 
+       if (!modprobe_path[0])
+               return 0;
+
        va_start(args, fmt);
        ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
        va_end(args);
@@ -569,14 +572,6 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
        int retval = 0;
 
        helper_lock();
-       if (!sub_info->path) {
-               retval = -EINVAL;
-               goto out;
-       }
-
-       if (sub_info->path[0] == '\0')
-               goto out;
-
        if (!khelper_wq || usermodehelper_disabled) {
                retval = -EBUSY;
                goto out;
index bddf3b201a480015e2b1b15c217c43ea6796fcd0..6e33498d665c3caa35ac764a46dd27c7cec80685 100644 (file)
@@ -2332,6 +2332,7 @@ static ssize_t write_enabled_file_bool(struct file *file,
        if (copy_from_user(buf, user_buf, buf_size))
                return -EFAULT;
 
+       buf[buf_size] = '\0';
        switch (buf[0]) {
        case 'y':
        case 'Y':
@@ -2343,6 +2344,8 @@ static ssize_t write_enabled_file_bool(struct file *file,
        case '0':
                disarm_all_kprobes();
                break;
+       default:
+               return -EINVAL;
        }
 
        return count;
index 1f3186b37fd5390be1534f895eb413de19e0a6d7..e16c45b9ee77054f80becd37a51da00776f796c1 100644 (file)
@@ -4090,7 +4090,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len)
 }
 EXPORT_SYMBOL_GPL(debug_check_no_locks_freed);
 
-static void print_held_locks_bug(struct task_struct *curr)
+static void print_held_locks_bug(void)
 {
        if (!debug_locks_off())
                return;
@@ -4099,22 +4099,21 @@ static void print_held_locks_bug(struct task_struct *curr)
 
        printk("\n");
        printk("=====================================\n");
-       printk("[ BUG: lock held at task exit time! ]\n");
+       printk("[ BUG: %s/%d still has locks held! ]\n",
+              current->comm, task_pid_nr(current));
        print_kernel_ident();
        printk("-------------------------------------\n");
-       printk("%s/%d is exiting with locks still held!\n",
-               curr->comm, task_pid_nr(curr));
-       lockdep_print_held_locks(curr);
-
+       lockdep_print_held_locks(current);
        printk("\nstack backtrace:\n");
        dump_stack();
 }
 
-void debug_check_no_locks_held(struct task_struct *task)
+void debug_check_no_locks_held(void)
 {
-       if (unlikely(task->lockdep_depth > 0))
-               print_held_locks_bug(task);
+       if (unlikely(current->lockdep_depth > 0))
+               print_held_locks_bug();
 }
+EXPORT_SYMBOL_GPL(debug_check_no_locks_held);
 
 void debug_show_all_locks(void)
 {
index ad53a664f113b7036fc9abed4d7d73f0be5b2479..e581ada5faf42b7cad697a6a2a9522695f0210b1 100644 (file)
@@ -254,16 +254,165 @@ void __sched mutex_unlock(struct mutex *lock)
 
 EXPORT_SYMBOL(mutex_unlock);
 
+/**
+ * ww_mutex_unlock - release the w/w mutex
+ * @lock: the mutex to be released
+ *
+ * Unlock a mutex that has been locked by this task previously with any of the
+ * ww_mutex_lock* functions (with or without an acquire context). It is
+ * forbidden to release the locks after releasing the acquire context.
+ *
+ * This function must not be used in interrupt context. Unlocking
+ * of a unlocked mutex is not allowed.
+ */
+void __sched ww_mutex_unlock(struct ww_mutex *lock)
+{
+       /*
+        * The unlocking fastpath is the 0->1 transition from 'locked'
+        * into 'unlocked' state:
+        */
+       if (lock->ctx) {
+#ifdef CONFIG_DEBUG_MUTEXES
+               DEBUG_LOCKS_WARN_ON(!lock->ctx->acquired);
+#endif
+               if (lock->ctx->acquired > 0)
+                       lock->ctx->acquired--;
+               lock->ctx = NULL;
+       }
+
+#ifndef CONFIG_DEBUG_MUTEXES
+       /*
+        * When debugging is enabled we must not clear the owner before time,
+        * the slow path will always be taken, and that clears the owner field
+        * after verifying that it was indeed current.
+        */
+       mutex_clear_owner(&lock->base);
+#endif
+       __mutex_fastpath_unlock(&lock->base.count, __mutex_unlock_slowpath);
+}
+EXPORT_SYMBOL(ww_mutex_unlock);
+
+static inline int __sched
+__mutex_lock_check_stamp(struct mutex *lock, struct ww_acquire_ctx *ctx)
+{
+       struct ww_mutex *ww = container_of(lock, struct ww_mutex, base);
+       struct ww_acquire_ctx *hold_ctx = ACCESS_ONCE(ww->ctx);
+
+       if (!hold_ctx)
+               return 0;
+
+       if (unlikely(ctx == hold_ctx))
+               return -EALREADY;
+
+       if (ctx->stamp - hold_ctx->stamp <= LONG_MAX &&
+           (ctx->stamp != hold_ctx->stamp || ctx > hold_ctx)) {
+#ifdef CONFIG_DEBUG_MUTEXES
+               DEBUG_LOCKS_WARN_ON(ctx->contending_lock);
+               ctx->contending_lock = ww;
+#endif
+               return -EDEADLK;
+       }
+
+       return 0;
+}
+
+static __always_inline void ww_mutex_lock_acquired(struct ww_mutex *ww,
+                                                  struct ww_acquire_ctx *ww_ctx)
+{
+#ifdef CONFIG_DEBUG_MUTEXES
+       /*
+        * If this WARN_ON triggers, you used ww_mutex_lock to acquire,
+        * but released with a normal mutex_unlock in this call.
+        *
+        * This should never happen, always use ww_mutex_unlock.
+        */
+       DEBUG_LOCKS_WARN_ON(ww->ctx);
+
+       /*
+        * Not quite done after calling ww_acquire_done() ?
+        */
+       DEBUG_LOCKS_WARN_ON(ww_ctx->done_acquire);
+
+       if (ww_ctx->contending_lock) {
+               /*
+                * After -EDEADLK you tried to
+                * acquire a different ww_mutex? Bad!
+                */
+               DEBUG_LOCKS_WARN_ON(ww_ctx->contending_lock != ww);
+
+               /*
+                * You called ww_mutex_lock after receiving -EDEADLK,
+                * but 'forgot' to unlock everything else first?
+                */
+               DEBUG_LOCKS_WARN_ON(ww_ctx->acquired > 0);
+               ww_ctx->contending_lock = NULL;
+       }
+
+       /*
+        * Naughty, using a different class will lead to undefined behavior!
+        */
+       DEBUG_LOCKS_WARN_ON(ww_ctx->ww_class != ww->ww_class);
+#endif
+       ww_ctx->acquired++;
+}
+
+/*
+ * after acquiring lock with fastpath or when we lost out in contested
+ * slowpath, set ctx and wake up any waiters so they can recheck.
+ *
+ * This function is never called when CONFIG_DEBUG_LOCK_ALLOC is set,
+ * as the fastpath and opportunistic spinning are disabled in that case.
+ */
+static __always_inline void
+ww_mutex_set_context_fastpath(struct ww_mutex *lock,
+                              struct ww_acquire_ctx *ctx)
+{
+       unsigned long flags;
+       struct mutex_waiter *cur;
+
+       ww_mutex_lock_acquired(lock, ctx);
+
+       lock->ctx = ctx;
+
+       /*
+        * The lock->ctx update should be visible on all cores before
+        * the atomic read is done, otherwise contended waiters might be
+        * missed. The contended waiters will either see ww_ctx == NULL
+        * and keep spinning, or it will acquire wait_lock, add itself
+        * to waiter list and sleep.
+        */
+       smp_mb(); /* ^^^ */
+
+       /*
+        * Check if lock is contended, if not there is nobody to wake up
+        */
+       if (likely(atomic_read(&lock->base.count) == 0))
+               return;
+
+       /*
+        * Uh oh, we raced in fastpath, wake up everyone in this case,
+        * so they can see the new lock->ctx.
+        */
+       spin_lock_mutex(&lock->base.wait_lock, flags);
+       list_for_each_entry(cur, &lock->base.wait_list, list) {
+               debug_mutex_wake_waiter(&lock->base, cur);
+               wake_up_process(cur->task);
+       }
+       spin_unlock_mutex(&lock->base.wait_lock, flags);
+}
+
 /*
  * Lock a mutex (possibly interruptible), slowpath:
  */
-static inline int __sched
+static __always_inline int __sched
 __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
-                   struct lockdep_map *nest_lock, unsigned long ip)
+                   struct lockdep_map *nest_lock, unsigned long ip,
+                   struct ww_acquire_ctx *ww_ctx)
 {
        struct task_struct *task = current;
        struct mutex_waiter waiter;
        unsigned long flags;
+       int ret;
 
        preempt_disable();
        mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
@@ -298,6 +447,22 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                struct task_struct *owner;
                struct mspin_node  node;
 
+               if (!__builtin_constant_p(ww_ctx == NULL) && ww_ctx->acquired > 0) {
+                       struct ww_mutex *ww;
+
+                       ww = container_of(lock, struct ww_mutex, base);
+                       /*
+                        * If ww->ctx is set the contents are undefined, only
+                        * by acquiring wait_lock there is a guarantee that
+                        * they are not invalid when reading.
+                        *
+                        * As such, when deadlock detection needs to be
+                        * performed the optimistic spinning cannot be done.
+                        */
+                       if (ACCESS_ONCE(ww->ctx))
+                               break;
+               }
+
                /*
                 * If there's an owner, wait for it to either
                 * release the lock or go to sleep.
@@ -312,6 +477,13 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
                if ((atomic_read(&lock->count) == 1) &&
                    (atomic_cmpxchg(&lock->count, 1, 0) == 1)) {
                        lock_acquired(&lock->dep_map, ip);
+                       if (!__builtin_constant_p(ww_ctx == NULL)) {
+                               struct ww_mutex *ww;
+                               ww = container_of(lock, struct ww_mutex, base);
+
+                               ww_mutex_set_context_fastpath(ww, ww_ctx);
+                       }
+
                        mutex_set_owner(lock);
                        mspin_unlock(MLOCK(lock), &node);
                        preempt_enable();
@@ -371,15 +543,16 @@ slowpath:
                 * TASK_UNINTERRUPTIBLE case.)
                 */
                if (unlikely(signal_pending_state(state, task))) {
-                       mutex_remove_waiter(lock, &waiter,
-                                           task_thread_info(task));
-                       mutex_release(&lock->dep_map, 1, ip);
-                       spin_unlock_mutex(&lock->wait_lock, flags);
+                       ret = -EINTR;
+                       goto err;
+               }
 
-                       debug_mutex_free_waiter(&waiter);
-                       preempt_enable();
-                       return -EINTR;
+               if (!__builtin_constant_p(ww_ctx == NULL) && ww_ctx->acquired > 0) {
+                       ret = __mutex_lock_check_stamp(lock, ww_ctx);
+                       if (ret)
+                               goto err;
                }
+
                __set_task_state(task, state);
 
                /* didn't get the lock, go to sleep: */
@@ -394,6 +567,30 @@ done:
        mutex_remove_waiter(lock, &waiter, current_thread_info());
        mutex_set_owner(lock);
 
+       if (!__builtin_constant_p(ww_ctx == NULL)) {
+               struct ww_mutex *ww = container_of(lock,
+                                                     struct ww_mutex,
+                                                     base);
+               struct mutex_waiter *cur;
+
+               /*
+                * This branch gets optimized out for the common case,
+                * and is only important for ww_mutex_lock.
+                */
+
+               ww_mutex_lock_acquired(ww, ww_ctx);
+               ww->ctx = ww_ctx;
+
+               /*
+                * Give any possible sleeping processes the chance to wake up,
+                * so they can recheck if they have to back off.
+                */
+               list_for_each_entry(cur, &lock->wait_list, list) {
+                       debug_mutex_wake_waiter(lock, cur);
+                       wake_up_process(cur->task);
+               }
+       }
+
        /* set it to 0 if there are no waiters left: */
        if (likely(list_empty(&lock->wait_list)))
                atomic_set(&lock->count, 0);
@@ -404,6 +601,14 @@ done:
        preempt_enable();
 
        return 0;
+
+err:
+       mutex_remove_waiter(lock, &waiter, task_thread_info(task));
+       spin_unlock_mutex(&lock->wait_lock, flags);
+       debug_mutex_free_waiter(&waiter);
+       mutex_release(&lock->dep_map, 1, ip);
+       preempt_enable();
+       return ret;
 }
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -411,7 +616,8 @@ void __sched
 mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
-       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, NULL, _RET_IP_);
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE,
+                           subclass, NULL, _RET_IP_, NULL);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_nested);
@@ -420,7 +626,8 @@ void __sched
 _mutex_lock_nest_lock(struct mutex *lock, struct lockdep_map *nest)
 {
        might_sleep();
-       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, nest, _RET_IP_);
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE,
+                           0, nest, _RET_IP_, NULL);
 }
 
 EXPORT_SYMBOL_GPL(_mutex_lock_nest_lock);
@@ -429,7 +636,8 @@ int __sched
 mutex_lock_killable_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
-       return __mutex_lock_common(lock, TASK_KILLABLE, subclass, NULL, _RET_IP_);
+       return __mutex_lock_common(lock, TASK_KILLABLE,
+                                  subclass, NULL, _RET_IP_, NULL);
 }
 EXPORT_SYMBOL_GPL(mutex_lock_killable_nested);
 
@@ -438,10 +646,68 @@ mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
        return __mutex_lock_common(lock, TASK_INTERRUPTIBLE,
-                                  subclass, NULL, _RET_IP_);
+                                  subclass, NULL, _RET_IP_, NULL);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
+
+static inline int
+ww_mutex_deadlock_injection(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+       unsigned tmp;
+
+       if (ctx->deadlock_inject_countdown-- == 0) {
+               tmp = ctx->deadlock_inject_interval;
+               if (tmp > UINT_MAX/4)
+                       tmp = UINT_MAX;
+               else
+                       tmp = tmp*2 + tmp + tmp/2;
+
+               ctx->deadlock_inject_interval = tmp;
+               ctx->deadlock_inject_countdown = tmp;
+               ctx->contending_lock = lock;
+
+               ww_mutex_unlock(lock);
+
+               return -EDEADLK;
+       }
+#endif
+
+       return 0;
+}
+
+int __sched
+__ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+       int ret;
+
+       might_sleep();
+       ret =  __mutex_lock_common(&lock->base, TASK_UNINTERRUPTIBLE,
+                                  0, &ctx->dep_map, _RET_IP_, ctx);
+       if (!ret && ctx->acquired > 0)
+               return ww_mutex_deadlock_injection(lock, ctx);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__ww_mutex_lock);
+
+int __sched
+__ww_mutex_lock_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+       int ret;
+
+       might_sleep();
+       ret = __mutex_lock_common(&lock->base, TASK_INTERRUPTIBLE,
+                                 0, &ctx->dep_map, _RET_IP_, ctx);
+
+       if (!ret && ctx->acquired > 0)
+               return ww_mutex_deadlock_injection(lock, ctx);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__ww_mutex_lock_interruptible);
+
 #endif
 
 /*
@@ -494,10 +760,10 @@ __mutex_unlock_slowpath(atomic_t *lock_count)
  * mutex_lock_interruptible() and mutex_trylock().
  */
 static noinline int __sched
-__mutex_lock_killable_slowpath(atomic_t *lock_count);
+__mutex_lock_killable_slowpath(struct mutex *lock);
 
 static noinline int __sched
-__mutex_lock_interruptible_slowpath(atomic_t *lock_count);
+__mutex_lock_interruptible_slowpath(struct mutex *lock);
 
 /**
  * mutex_lock_interruptible - acquire the mutex, interruptible
@@ -515,12 +781,12 @@ int __sched mutex_lock_interruptible(struct mutex *lock)
        int ret;
 
        might_sleep();
-       ret =  __mutex_fastpath_lock_retval
-                       (&lock->count, __mutex_lock_interruptible_slowpath);
-       if (!ret)
+       ret =  __mutex_fastpath_lock_retval(&lock->count);
+       if (likely(!ret)) {
                mutex_set_owner(lock);
-
-       return ret;
+               return 0;
+       } else
+               return __mutex_lock_interruptible_slowpath(lock);
 }
 
 EXPORT_SYMBOL(mutex_lock_interruptible);
@@ -530,12 +796,12 @@ int __sched mutex_lock_killable(struct mutex *lock)
        int ret;
 
        might_sleep();
-       ret = __mutex_fastpath_lock_retval
-                       (&lock->count, __mutex_lock_killable_slowpath);
-       if (!ret)
+       ret = __mutex_fastpath_lock_retval(&lock->count);
+       if (likely(!ret)) {
                mutex_set_owner(lock);
-
-       return ret;
+               return 0;
+       } else
+               return __mutex_lock_killable_slowpath(lock);
 }
 EXPORT_SYMBOL(mutex_lock_killable);
 
@@ -544,24 +810,39 @@ __mutex_lock_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
 
-       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, NULL, _RET_IP_);
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0,
+                           NULL, _RET_IP_, NULL);
 }
 
 static noinline int __sched
-__mutex_lock_killable_slowpath(atomic_t *lock_count)
+__mutex_lock_killable_slowpath(struct mutex *lock)
 {
-       struct mutex *lock = container_of(lock_count, struct mutex, count);
+       return __mutex_lock_common(lock, TASK_KILLABLE, 0,
+                                  NULL, _RET_IP_, NULL);
+}
 
-       return __mutex_lock_common(lock, TASK_KILLABLE, 0, NULL, _RET_IP_);
+static noinline int __sched
+__mutex_lock_interruptible_slowpath(struct mutex *lock)
+{
+       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0,
+                                  NULL, _RET_IP_, NULL);
 }
 
 static noinline int __sched
-__mutex_lock_interruptible_slowpath(atomic_t *lock_count)
+__ww_mutex_lock_slowpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
 {
-       struct mutex *lock = container_of(lock_count, struct mutex, count);
+       return __mutex_lock_common(&lock->base, TASK_UNINTERRUPTIBLE, 0,
+                                  NULL, _RET_IP_, ctx);
+}
 
-       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0, NULL, _RET_IP_);
+static noinline int __sched
+__ww_mutex_lock_interruptible_slowpath(struct ww_mutex *lock,
+                                           struct ww_acquire_ctx *ctx)
+{
+       return __mutex_lock_common(&lock->base, TASK_INTERRUPTIBLE, 0,
+                                  NULL, _RET_IP_, ctx);
 }
+
 #endif
 
 /*
@@ -617,6 +898,45 @@ int __sched mutex_trylock(struct mutex *lock)
 }
 EXPORT_SYMBOL(mutex_trylock);
 
+#ifndef CONFIG_DEBUG_LOCK_ALLOC
+int __sched
+__ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+       int ret;
+
+       might_sleep();
+
+       ret = __mutex_fastpath_lock_retval(&lock->base.count);
+
+       if (likely(!ret)) {
+               ww_mutex_set_context_fastpath(lock, ctx);
+               mutex_set_owner(&lock->base);
+       } else
+               ret = __ww_mutex_lock_slowpath(lock, ctx);
+       return ret;
+}
+EXPORT_SYMBOL(__ww_mutex_lock);
+
+int __sched
+__ww_mutex_lock_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+       int ret;
+
+       might_sleep();
+
+       ret = __mutex_fastpath_lock_retval(&lock->base.count);
+
+       if (likely(!ret)) {
+               ww_mutex_set_context_fastpath(lock, ctx);
+               mutex_set_owner(&lock->base);
+       } else
+               ret = __ww_mutex_lock_interruptible_slowpath(lock, ctx);
+       return ret;
+}
+EXPORT_SYMBOL(__ww_mutex_lock_interruptible);
+
+#endif
+
 /**
  * atomic_dec_and_mutex_lock - return holding mutex if we dec to 0
  * @cnt: the atomic which we are to dec
index 0db3e791a06d48594606bc4789bc8fbe0fd5a4f0..66505c1dfc516f3985e2072029152291cd0bedf9 100644 (file)
@@ -75,6 +75,7 @@ struct pid_namespace init_pid_ns = {
                [ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL }
        },
        .last_pid = 0,
+       .nr_hashed = PIDNS_HASH_ADDING,
        .level = 0,
        .child_reaper = &init_task,
        .user_ns = &init_user_ns,
@@ -373,14 +374,10 @@ EXPORT_SYMBOL_GPL(find_vpid);
 /*
  * attach_pid() must be called with the tasklist_lock write-held.
  */
-void attach_pid(struct task_struct *task, enum pid_type type,
-               struct pid *pid)
+void attach_pid(struct task_struct *task, enum pid_type type)
 {
-       struct pid_link *link;
-
-       link = &task->pids[type];
-       link->pid = pid;
-       hlist_add_head_rcu(&link->node, &pid->tasks[type]);
+       struct pid_link *link = &task->pids[type];
+       hlist_add_head_rcu(&link->node, &link->pid->tasks[type]);
 }
 
 static void __change_pid(struct task_struct *task, enum pid_type type,
@@ -412,7 +409,7 @@ void change_pid(struct task_struct *task, enum pid_type type,
                struct pid *pid)
 {
        __change_pid(task, type, pid);
-       attach_pid(task, type, pid);
+       attach_pid(task, type);
 }
 
 /* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */
@@ -594,7 +591,6 @@ void __init pidmap_init(void)
        /* Reserve PID 0. We never call free_pidmap(0) */
        set_bit(0, init_pid_ns.pidmap[0].page);
        atomic_dec(&init_pid_ns.pidmap[0].nr_free);
-       init_pid_ns.nr_hashed = PIDNS_HASH_ADDING;
 
        init_pid_ns.pid_cachep = KMEM_CACHE(pid,
                        SLAB_HWCACHE_ALIGN | SLAB_PANIC);
index 9c39de095ba905558d2f032278f63efa9d3ad081..d444c4e834f4526ec318f71b1076a02c909e34a8 100644 (file)
@@ -262,6 +262,26 @@ config PM_GENERIC_DOMAINS
        bool
        depends on PM
 
+config WQ_POWER_EFFICIENT_DEFAULT
+       bool "Enable workqueue power-efficient mode by default"
+       depends on PM
+       default n
+       help
+         Per-cpu workqueues are generally preferred because they show
+         better performance thanks to cache locality; unfortunately,
+         per-cpu workqueues tend to be more power hungry than unbound
+         workqueues.
+
+         Enabling workqueue.power_efficient kernel parameter makes the
+         per-cpu workqueues which were observed to contribute
+         significantly to power consumption unbound, leading to measurably
+         lower power usage at the cost of small performance overhead.
+
+         This config option determines whether workqueue.power_efficient
+         is enabled by default.
+
+         If in doubt, say N.
+
 config PM_GENERIC_DOMAINS_SLEEP
        def_bool y
        depends on PM_SLEEP && PM_GENERIC_DOMAINS
index d77663bfedeb071370f584f2bf1e42cd8332e5a4..1d1bf630e6e900d5354413a6176b60b6a948a979 100644 (file)
@@ -424,6 +424,8 @@ static ssize_t wakeup_count_store(struct kobject *kobj,
        if (sscanf(buf, "%u", &val) == 1) {
                if (pm_save_wakeup_count(val))
                        error = n;
+               else
+                       pm_print_active_wakeup_sources();
        }
 
  out:
@@ -528,6 +530,10 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
 
        if (sscanf(buf, "%d", &val) == 1) {
                pm_trace_enabled = !!val;
+               if (pm_trace_enabled) {
+                       pr_warn("PM: Enabling pm_trace changes system date and time during resume.\n"
+                               "PM: Correct system time has to be restored manually after resume.\n");
+               }
                return n;
        }
        return -EINVAL;
index 98088e0e71e83a3b9cd157c5415f9e79083592c0..fc0df84864495f8c44261961cb6909e66d24a21e 100644 (file)
@@ -30,9 +30,10 @@ static int try_to_freeze_tasks(bool user_only)
        unsigned int todo;
        bool wq_busy = false;
        struct timeval start, end;
-       u64 elapsed_csecs64;
-       unsigned int elapsed_csecs;
+       u64 elapsed_msecs64;
+       unsigned int elapsed_msecs;
        bool wakeup = false;
+       int sleep_usecs = USEC_PER_MSEC;
 
        do_gettimeofday(&start);
 
@@ -68,22 +69,25 @@ static int try_to_freeze_tasks(bool user_only)
 
                /*
                 * We need to retry, but first give the freezing tasks some
-                * time to enter the refrigerator.
+                * time to enter the refrigerator.  Start with an initial
+                * 1 ms sleep followed by exponential backoff until 8 ms.
                 */
-               msleep(10);
+               usleep_range(sleep_usecs / 2, sleep_usecs);
+               if (sleep_usecs < 8 * USEC_PER_MSEC)
+                       sleep_usecs *= 2;
        }
 
        do_gettimeofday(&end);
-       elapsed_csecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);
-       do_div(elapsed_csecs64, NSEC_PER_SEC / 100);
-       elapsed_csecs = elapsed_csecs64;
+       elapsed_msecs64 = timeval_to_ns(&end) - timeval_to_ns(&start);
+       do_div(elapsed_msecs64, NSEC_PER_MSEC);
+       elapsed_msecs = elapsed_msecs64;
 
        if (todo) {
                printk("\n");
-               printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds "
+               printk(KERN_ERR "Freezing of tasks %s after %d.%03d seconds "
                       "(%d tasks refusing to freeze, wq_busy=%d):\n",
                       wakeup ? "aborted" : "failed",
-                      elapsed_csecs / 100, elapsed_csecs % 100,
+                      elapsed_msecs / 1000, elapsed_msecs % 1000,
                       todo - wq_busy, wq_busy);
 
                if (!wakeup) {
@@ -96,8 +100,8 @@ static int try_to_freeze_tasks(bool user_only)
                        read_unlock(&tasklist_lock);
                }
        } else {
-               printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100,
-                       elapsed_csecs % 100);
+               printk("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000,
+                       elapsed_msecs % 1000);
        }
 
        return todo ? -EBUSY : 0;
index 587dddeebf15610da6f93c35874381ea5156365a..06fe28589e9c9e88b014315dfab33a9e6cdfd0eb 100644 (file)
@@ -44,6 +44,7 @@
 
 #include <linux/uaccess.h>
 #include <linux/export.h>
+#include <trace/events/power.h>
 
 /*
  * locking rule: all changes to constraints or notifiers lists
@@ -202,6 +203,7 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
 
        spin_unlock_irqrestore(&pm_qos_lock, flags);
 
+       trace_pm_qos_update_target(action, prev_value, curr_value);
        if (prev_value != curr_value) {
                blocking_notifier_call_chain(c->notifiers,
                                             (unsigned long)curr_value,
@@ -272,6 +274,7 @@ bool pm_qos_update_flags(struct pm_qos_flags *pqf,
 
        spin_unlock_irqrestore(&pm_qos_lock, irqflags);
 
+       trace_pm_qos_update_flags(action, prev_value, curr_value);
        return prev_value != curr_value;
 }
 
@@ -333,6 +336,7 @@ void pm_qos_add_request(struct pm_qos_request *req,
        }
        req->pm_qos_class = pm_qos_class;
        INIT_DELAYED_WORK(&req->work, pm_qos_work_fn);
+       trace_pm_qos_add_request(pm_qos_class, value);
        pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
                             &req->node, PM_QOS_ADD_REQ, value);
 }
@@ -361,6 +365,7 @@ void pm_qos_update_request(struct pm_qos_request *req,
 
        cancel_delayed_work_sync(&req->work);
 
+       trace_pm_qos_update_request(req->pm_qos_class, new_value);
        if (new_value != req->node.prio)
                pm_qos_update_target(
                        pm_qos_array[req->pm_qos_class]->constraints,
@@ -387,6 +392,8 @@ void pm_qos_update_request_timeout(struct pm_qos_request *req, s32 new_value,
 
        cancel_delayed_work_sync(&req->work);
 
+       trace_pm_qos_update_request_timeout(req->pm_qos_class,
+                                           new_value, timeout_us);
        if (new_value != req->node.prio)
                pm_qos_update_target(
                        pm_qos_array[req->pm_qos_class]->constraints,
@@ -416,6 +423,7 @@ void pm_qos_remove_request(struct pm_qos_request *req)
 
        cancel_delayed_work_sync(&req->work);
 
+       trace_pm_qos_remove_request(req->pm_qos_class, PM_QOS_DEFAULT_VALUE);
        pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,
                             &req->node, PM_QOS_REMOVE_REQ,
                             PM_QOS_DEFAULT_VALUE);
@@ -477,7 +485,7 @@ static int find_pm_qos_object_by_minor(int minor)
 {
        int pm_qos_class;
 
-       for (pm_qos_class = 0;
+       for (pm_qos_class = PM_QOS_CPU_DMA_LATENCY;
                pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
                if (minor ==
                        pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
@@ -491,7 +499,7 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp)
        long pm_qos_class;
 
        pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
-       if (pm_qos_class >= 0) {
+       if (pm_qos_class >= PM_QOS_CPU_DMA_LATENCY) {
                struct pm_qos_request *req = kzalloc(sizeof(*req), GFP_KERNEL);
                if (!req)
                        return -ENOMEM;
@@ -584,7 +592,7 @@ static int __init pm_qos_power_init(void)
 
        BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES);
 
-       for (i = 1; i < PM_QOS_NUM_CLASSES; i++) {
+       for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) {
                ret = register_pm_qos_misc(pm_qos_array[i]);
                if (ret < 0) {
                        printk(KERN_ERR "pm_qos_param: %s setup failed\n",
index 0de28576807df9e7dc5be5f05d75a0faa937caf2..349587bb03e1edb64dc5609eee61fdf90a517af0 100644 (file)
@@ -642,8 +642,9 @@ __register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
        region->end_pfn = end_pfn;
        list_add_tail(&region->list, &nosave_regions);
  Report:
-       printk(KERN_INFO "PM: Registered nosave memory: %016lx - %016lx\n",
-               start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
+       printk(KERN_INFO "PM: Registered nosave memory: [mem %#010llx-%#010llx]\n",
+               (unsigned long long) start_pfn << PAGE_SHIFT,
+               ((unsigned long long) end_pfn << PAGE_SHIFT) - 1);
 }
 
 /*
@@ -1651,7 +1652,7 @@ unsigned long snapshot_get_image_size(void)
 static int init_header(struct swsusp_info *info)
 {
        memset(info, 0, sizeof(struct swsusp_info));
-       info->num_physpages = num_physpages;
+       info->num_physpages = get_num_physpages();
        info->image_pages = nr_copy_pages;
        info->pages = snapshot_get_image_size();
        info->size = info->pages;
@@ -1795,7 +1796,7 @@ static int check_header(struct swsusp_info *info)
        char *reason;
 
        reason = check_image_kernel(info);
-       if (!reason && info->num_physpages != num_physpages)
+       if (!reason && info->num_physpages != get_num_physpages())
                reason = "memory size";
        if (reason) {
                printk(KERN_ERR "PM: Image mismatch: %s\n", reason);
index bef86d121eb2ca5bcba2001a447f38e90476c5b5..ece04223bb1ebf99d08a1aa0aab99e14d0fbf994 100644 (file)
@@ -269,7 +269,7 @@ int suspend_devices_and_enter(suspend_state_t state)
        suspend_test_start();
        error = dpm_suspend_start(PMSG_SUSPEND);
        if (error) {
-               printk(KERN_ERR "PM: Some devices failed to suspend\n");
+               pr_err("PM: Some devices failed to suspend, or early wake event detected\n");
                goto Recover_platform;
        }
        suspend_test_finish("suspend devices");
index 335a7ae697f5986269d94a445fd27142fc75c09f..ba5e6cea181afecb583d567c38c23008142567c9 100644 (file)
@@ -844,6 +844,47 @@ int ptrace_request(struct task_struct *child, long request,
                        ret = ptrace_setsiginfo(child, &siginfo);
                break;
 
+       case PTRACE_GETSIGMASK:
+               if (addr != sizeof(sigset_t)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (copy_to_user(datavp, &child->blocked, sizeof(sigset_t)))
+                       ret = -EFAULT;
+               else
+                       ret = 0;
+
+               break;
+
+       case PTRACE_SETSIGMASK: {
+               sigset_t new_set;
+
+               if (addr != sizeof(sigset_t)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (copy_from_user(&new_set, datavp, sizeof(sigset_t))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));
+
+               /*
+                * Every thread does recalc_sigpending() after resume, so
+                * retarget_shared_pending() and recalc_sigpending() are not
+                * called here.
+                */
+               spin_lock_irq(&child->sighand->siglock);
+               child->blocked = new_set;
+               spin_unlock_irq(&child->sighand->siglock);
+
+               ret = 0;
+               break;
+       }
+
        case PTRACE_INTERRUPT:
                /*
                 * Stop tracee without any side-effect on signal or job
@@ -948,8 +989,7 @@ int ptrace_request(struct task_struct *child, long request,
 
 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
        case PTRACE_GETREGSET:
-       case PTRACE_SETREGSET:
-       {
+       case PTRACE_SETREGSET: {
                struct iovec kiov;
                struct iovec __user *uiov = datavp;
 
index 48ab70384a4cda7533a65c02915ef253ea767645..cce6ba8bbace7f0793d008c725c9599a5ba8c1d1 100644 (file)
@@ -104,31 +104,7 @@ void __rcu_read_unlock(void)
 }
 EXPORT_SYMBOL_GPL(__rcu_read_unlock);
 
-/*
- * Check for a task exiting while in a preemptible-RCU read-side
- * critical section, clean up if so.  No need to issue warnings,
- * as debug_check_no_locks_held() already does this if lockdep
- * is enabled.
- */
-void exit_rcu(void)
-{
-       struct task_struct *t = current;
-
-       if (likely(list_empty(&current->rcu_node_entry)))
-               return;
-       t->rcu_read_lock_nesting = 1;
-       barrier();
-       t->rcu_read_unlock_special = RCU_READ_UNLOCK_BLOCKED;
-       __rcu_read_unlock();
-}
-
-#else /* #ifdef CONFIG_PREEMPT_RCU */
-
-void exit_rcu(void)
-{
-}
-
-#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
+#endif /* #ifdef CONFIG_PREEMPT_RCU */
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key rcu_lock_key;
@@ -145,9 +121,6 @@ static struct lock_class_key rcu_sched_lock_key;
 struct lockdep_map rcu_sched_lock_map =
        STATIC_LOCKDEP_MAP_INIT("rcu_read_lock_sched", &rcu_sched_lock_key);
 EXPORT_SYMBOL_GPL(rcu_sched_lock_map);
-#endif
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
 
 int debug_lockdep_rcu_enabled(void)
 {
index a0714a51b6d710e8030c33ddaadffe73fe30e07c..aa344111de3efdf67777bf6be400a5d2018b22c0 100644 (file)
@@ -44,7 +44,6 @@
 
 /* Forward declarations for rcutiny_plugin.h. */
 struct rcu_ctrlblk;
-static void invoke_rcu_callbacks(void);
 static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp);
 static void rcu_process_callbacks(struct softirq_action *unused);
 static void __call_rcu(struct rcu_head *head,
@@ -205,7 +204,7 @@ static int rcu_is_cpu_rrupt_from_idle(void)
  */
 static int rcu_qsctr_help(struct rcu_ctrlblk *rcp)
 {
-       reset_cpu_stall_ticks(rcp);
+       RCU_TRACE(reset_cpu_stall_ticks(rcp));
        if (rcp->rcucblist != NULL &&
            rcp->donetail != rcp->curtail) {
                rcp->donetail = rcp->curtail;
@@ -227,7 +226,7 @@ void rcu_sched_qs(int cpu)
        local_irq_save(flags);
        if (rcu_qsctr_help(&rcu_sched_ctrlblk) +
            rcu_qsctr_help(&rcu_bh_ctrlblk))
-               invoke_rcu_callbacks();
+               raise_softirq(RCU_SOFTIRQ);
        local_irq_restore(flags);
 }
 
@@ -240,7 +239,7 @@ void rcu_bh_qs(int cpu)
 
        local_irq_save(flags);
        if (rcu_qsctr_help(&rcu_bh_ctrlblk))
-               invoke_rcu_callbacks();
+               raise_softirq(RCU_SOFTIRQ);
        local_irq_restore(flags);
 }
 
@@ -252,12 +251,11 @@ void rcu_bh_qs(int cpu)
  */
 void rcu_check_callbacks(int cpu, int user)
 {
-       check_cpu_stalls();
+       RCU_TRACE(check_cpu_stalls());
        if (user || rcu_is_cpu_rrupt_from_idle())
                rcu_sched_qs(cpu);
        else if (!in_softirq())
                rcu_bh_qs(cpu);
-       rcu_preempt_check_callbacks();
 }
 
 /*
@@ -278,7 +276,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
                                              ACCESS_ONCE(rcp->rcucblist),
                                              need_resched(),
                                              is_idle_task(current),
-                                             rcu_is_callbacks_kthread()));
+                                             false));
                return;
        }
 
@@ -290,7 +288,6 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
        *rcp->donetail = NULL;
        if (rcp->curtail == rcp->donetail)
                rcp->curtail = &rcp->rcucblist;
-       rcu_preempt_remove_callbacks(rcp);
        rcp->donetail = &rcp->rcucblist;
        local_irq_restore(flags);
 
@@ -309,14 +306,13 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
        RCU_TRACE(rcu_trace_sub_qlen(rcp, cb_count));
        RCU_TRACE(trace_rcu_batch_end(rcp->name, cb_count, 0, need_resched(),
                                      is_idle_task(current),
-                                     rcu_is_callbacks_kthread()));
+                                     false));
 }
 
 static void rcu_process_callbacks(struct softirq_action *unused)
 {
        __rcu_process_callbacks(&rcu_sched_ctrlblk);
        __rcu_process_callbacks(&rcu_bh_ctrlblk);
-       rcu_preempt_process_callbacks();
 }
 
 /*
@@ -382,3 +378,8 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
        __call_rcu(head, func, &rcu_bh_ctrlblk);
 }
 EXPORT_SYMBOL_GPL(call_rcu_bh);
+
+void rcu_init(void)
+{
+       open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
+}
index 8a233002faeba228d6195481f0812af703b7e9f3..0cd385acccfa19660072ee3550d89a461246aa72 100644 (file)
@@ -53,958 +53,10 @@ static struct rcu_ctrlblk rcu_bh_ctrlblk = {
 };
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
+#include <linux/kernel_stat.h>
+
 int rcu_scheduler_active __read_mostly;
 EXPORT_SYMBOL_GPL(rcu_scheduler_active);
-#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
-
-#ifdef CONFIG_RCU_TRACE
-
-static void check_cpu_stall(struct rcu_ctrlblk *rcp)
-{
-       unsigned long j;
-       unsigned long js;
-
-       if (rcu_cpu_stall_suppress)
-               return;
-       rcp->ticks_this_gp++;
-       j = jiffies;
-       js = rcp->jiffies_stall;
-       if (*rcp->curtail && ULONG_CMP_GE(j, js)) {
-               pr_err("INFO: %s stall on CPU (%lu ticks this GP) idle=%llx (t=%lu jiffies q=%ld)\n",
-                      rcp->name, rcp->ticks_this_gp, rcu_dynticks_nesting,
-                      jiffies - rcp->gp_start, rcp->qlen);
-               dump_stack();
-       }
-       if (*rcp->curtail && ULONG_CMP_GE(j, js))
-               rcp->jiffies_stall = jiffies +
-                       3 * rcu_jiffies_till_stall_check() + 3;
-       else if (ULONG_CMP_GE(j, js))
-               rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check();
-}
-
-static void check_cpu_stall_preempt(void);
-
-#endif /* #ifdef CONFIG_RCU_TRACE */
-
-static void reset_cpu_stall_ticks(struct rcu_ctrlblk *rcp)
-{
-#ifdef CONFIG_RCU_TRACE
-       rcp->ticks_this_gp = 0;
-       rcp->gp_start = jiffies;
-       rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check();
-#endif /* #ifdef CONFIG_RCU_TRACE */
-}
-
-static void check_cpu_stalls(void)
-{
-       RCU_TRACE(check_cpu_stall(&rcu_bh_ctrlblk));
-       RCU_TRACE(check_cpu_stall(&rcu_sched_ctrlblk));
-       RCU_TRACE(check_cpu_stall_preempt());
-}
-
-#ifdef CONFIG_TINY_PREEMPT_RCU
-
-#include <linux/delay.h>
-
-/* Global control variables for preemptible RCU. */
-struct rcu_preempt_ctrlblk {
-       struct rcu_ctrlblk rcb; /* curtail: ->next ptr of last CB for GP. */
-       struct rcu_head **nexttail;
-                               /* Tasks blocked in a preemptible RCU */
-                               /*  read-side critical section while an */
-                               /*  preemptible-RCU grace period is in */
-                               /*  progress must wait for a later grace */
-                               /*  period.  This pointer points to the */
-                               /*  ->next pointer of the last task that */
-                               /*  must wait for a later grace period, or */
-                               /*  to &->rcb.rcucblist if there is no */
-                               /*  such task. */
-       struct list_head blkd_tasks;
-                               /* Tasks blocked in RCU read-side critical */
-                               /*  section.  Tasks are placed at the head */
-                               /*  of this list and age towards the tail. */
-       struct list_head *gp_tasks;
-                               /* Pointer to the first task blocking the */
-                               /*  current grace period, or NULL if there */
-                               /*  is no such task. */
-       struct list_head *exp_tasks;
-                               /* Pointer to first task blocking the */
-                               /*  current expedited grace period, or NULL */
-                               /*  if there is no such task.  If there */
-                               /*  is no current expedited grace period, */
-                               /*  then there cannot be any such task. */
-#ifdef CONFIG_RCU_BOOST
-       struct list_head *boost_tasks;
-                               /* Pointer to first task that needs to be */
-                               /*  priority-boosted, or NULL if no priority */
-                               /*  boosting is needed.  If there is no */
-                               /*  current or expedited grace period, there */
-                               /*  can be no such task. */
-#endif /* #ifdef CONFIG_RCU_BOOST */
-       u8 gpnum;               /* Current grace period. */
-       u8 gpcpu;               /* Last grace period blocked by the CPU. */
-       u8 completed;           /* Last grace period completed. */
-                               /*  If all three are equal, RCU is idle. */
-#ifdef CONFIG_RCU_BOOST
-       unsigned long boost_time; /* When to start boosting (jiffies) */
-#endif /* #ifdef CONFIG_RCU_BOOST */
-#ifdef CONFIG_RCU_TRACE
-       unsigned long n_grace_periods;
-#ifdef CONFIG_RCU_BOOST
-       unsigned long n_tasks_boosted;
-                               /* Total number of tasks boosted. */
-       unsigned long n_exp_boosts;
-                               /* Number of tasks boosted for expedited GP. */
-       unsigned long n_normal_boosts;
-                               /* Number of tasks boosted for normal GP. */
-       unsigned long n_balk_blkd_tasks;
-                               /* Refused to boost: no blocked tasks. */
-       unsigned long n_balk_exp_gp_tasks;
-                               /* Refused to boost: nothing blocking GP. */
-       unsigned long n_balk_boost_tasks;
-                               /* Refused to boost: already boosting. */
-       unsigned long n_balk_notyet;
-                               /* Refused to boost: not yet time. */
-       unsigned long n_balk_nos;
-                               /* Refused to boost: not sure why, though. */
-                               /*  This can happen due to race conditions. */
-#endif /* #ifdef CONFIG_RCU_BOOST */
-#endif /* #ifdef CONFIG_RCU_TRACE */
-};
-
-static struct rcu_preempt_ctrlblk rcu_preempt_ctrlblk = {
-       .rcb.donetail = &rcu_preempt_ctrlblk.rcb.rcucblist,
-       .rcb.curtail = &rcu_preempt_ctrlblk.rcb.rcucblist,
-       .nexttail = &rcu_preempt_ctrlblk.rcb.rcucblist,
-       .blkd_tasks = LIST_HEAD_INIT(rcu_preempt_ctrlblk.blkd_tasks),
-       RCU_TRACE(.rcb.name = "rcu_preempt")
-};
-
-static int rcu_preempted_readers_exp(void);
-static void rcu_report_exp_done(void);
-
-/*
- * Return true if the CPU has not yet responded to the current grace period.
- */
-static int rcu_cpu_blocking_cur_gp(void)
-{
-       return rcu_preempt_ctrlblk.gpcpu != rcu_preempt_ctrlblk.gpnum;
-}
-
-/*
- * Check for a running RCU reader.  Because there is only one CPU,
- * there can be but one running RCU reader at a time.  ;-)
- *
- * Returns zero if there are no running readers.  Returns a positive
- * number if there is at least one reader within its RCU read-side
- * critical section.  Returns a negative number if an outermost reader
- * is in the midst of exiting from its RCU read-side critical section
- *
- * Returns zero if there are no running readers.  Returns a positive
- * number if there is at least one reader within its RCU read-side
- * critical section.  Returns a negative number if an outermost reader
- * is in the midst of exiting from its RCU read-side critical section.
- */
-static int rcu_preempt_running_reader(void)
-{
-       return current->rcu_read_lock_nesting;
-}
-
-/*
- * Check for preempted RCU readers blocking any grace period.
- * If the caller needs a reliable answer, it must disable hard irqs.
- */
-static int rcu_preempt_blocked_readers_any(void)
-{
-       return !list_empty(&rcu_preempt_ctrlblk.blkd_tasks);
-}
-
-/*
- * Check for preempted RCU readers blocking the current grace period.
- * If the caller needs a reliable answer, it must disable hard irqs.
- */
-static int rcu_preempt_blocked_readers_cgp(void)
-{
-       return rcu_preempt_ctrlblk.gp_tasks != NULL;
-}
-
-/*
- * Return true if another preemptible-RCU grace period is needed.
- */
-static int rcu_preempt_needs_another_gp(void)
-{
-       return *rcu_preempt_ctrlblk.rcb.curtail != NULL;
-}
-
-/*
- * Return true if a preemptible-RCU grace period is in progress.
- * The caller must disable hardirqs.
- */
-static int rcu_preempt_gp_in_progress(void)
-{
-       return rcu_preempt_ctrlblk.completed != rcu_preempt_ctrlblk.gpnum;
-}
-
-/*
- * Advance a ->blkd_tasks-list pointer to the next entry, instead
- * returning NULL if at the end of the list.
- */
-static struct list_head *rcu_next_node_entry(struct task_struct *t)
-{
-       struct list_head *np;
-
-       np = t->rcu_node_entry.next;
-       if (np == &rcu_preempt_ctrlblk.blkd_tasks)
-               np = NULL;
-       return np;
-}
-
-#ifdef CONFIG_RCU_TRACE
-
-#ifdef CONFIG_RCU_BOOST
-static void rcu_initiate_boost_trace(void);
-#endif /* #ifdef CONFIG_RCU_BOOST */
-
-/*
- * Dump additional statistice for TINY_PREEMPT_RCU.
- */
-static void show_tiny_preempt_stats(struct seq_file *m)
-{
-       seq_printf(m, "rcu_preempt: qlen=%ld gp=%lu g%u/p%u/c%u tasks=%c%c%c\n",
-                  rcu_preempt_ctrlblk.rcb.qlen,
-                  rcu_preempt_ctrlblk.n_grace_periods,
-                  rcu_preempt_ctrlblk.gpnum,
-                  rcu_preempt_ctrlblk.gpcpu,
-                  rcu_preempt_ctrlblk.completed,
-                  "T."[list_empty(&rcu_preempt_ctrlblk.blkd_tasks)],
-                  "N."[!rcu_preempt_ctrlblk.gp_tasks],
-                  "E."[!rcu_preempt_ctrlblk.exp_tasks]);
-#ifdef CONFIG_RCU_BOOST
-       seq_printf(m, "%sttb=%c ntb=%lu neb=%lu nnb=%lu j=%04x bt=%04x\n",
-                  "             ",
-                  "B."[!rcu_preempt_ctrlblk.boost_tasks],
-                  rcu_preempt_ctrlblk.n_tasks_boosted,
-                  rcu_preempt_ctrlblk.n_exp_boosts,
-                  rcu_preempt_ctrlblk.n_normal_boosts,
-                  (int)(jiffies & 0xffff),
-                  (int)(rcu_preempt_ctrlblk.boost_time & 0xffff));
-       seq_printf(m, "%s: nt=%lu egt=%lu bt=%lu ny=%lu nos=%lu\n",
-                  "             balk",
-                  rcu_preempt_ctrlblk.n_balk_blkd_tasks,
-                  rcu_preempt_ctrlblk.n_balk_exp_gp_tasks,
-                  rcu_preempt_ctrlblk.n_balk_boost_tasks,
-                  rcu_preempt_ctrlblk.n_balk_notyet,
-                  rcu_preempt_ctrlblk.n_balk_nos);
-#endif /* #ifdef CONFIG_RCU_BOOST */
-}
-
-#endif /* #ifdef CONFIG_RCU_TRACE */
-
-#ifdef CONFIG_RCU_BOOST
-
-#include "rtmutex_common.h"
-
-#define RCU_BOOST_PRIO CONFIG_RCU_BOOST_PRIO
-
-/* Controls for rcu_kthread() kthread. */
-static struct task_struct *rcu_kthread_task;
-static DECLARE_WAIT_QUEUE_HEAD(rcu_kthread_wq);
-static unsigned long have_rcu_kthread_work;
-
-/*
- * Carry out RCU priority boosting on the task indicated by ->boost_tasks,
- * and advance ->boost_tasks to the next task in the ->blkd_tasks list.
- */
-static int rcu_boost(void)
-{
-       unsigned long flags;
-       struct rt_mutex mtx;
-       struct task_struct *t;
-       struct list_head *tb;
-
-       if (rcu_preempt_ctrlblk.boost_tasks == NULL &&
-           rcu_preempt_ctrlblk.exp_tasks == NULL)
-               return 0;  /* Nothing to boost. */
-
-       local_irq_save(flags);
-
-       /*
-        * Recheck with irqs disabled: all tasks in need of boosting
-        * might exit their RCU read-side critical sections on their own
-        * if we are preempted just before disabling irqs.
-        */
-       if (rcu_preempt_ctrlblk.boost_tasks == NULL &&
-           rcu_preempt_ctrlblk.exp_tasks == NULL) {
-               local_irq_restore(flags);
-               return 0;
-       }
-
-       /*
-        * Preferentially boost tasks blocking expedited grace periods.
-        * This cannot starve the normal grace periods because a second
-        * expedited grace period must boost all blocked tasks, including
-        * those blocking the pre-existing normal grace period.
-        */
-       if (rcu_preempt_ctrlblk.exp_tasks != NULL) {
-               tb = rcu_preempt_ctrlblk.exp_tasks;
-               RCU_TRACE(rcu_preempt_ctrlblk.n_exp_boosts++);
-       } else {
-               tb = rcu_preempt_ctrlblk.boost_tasks;
-               RCU_TRACE(rcu_preempt_ctrlblk.n_normal_boosts++);
-       }
-       RCU_TRACE(rcu_preempt_ctrlblk.n_tasks_boosted++);
-
-       /*
-        * We boost task t by manufacturing an rt_mutex that appears to
-        * be held by task t.  We leave a pointer to that rt_mutex where
-        * task t can find it, and task t will release the mutex when it
-        * exits its outermost RCU read-side critical section.  Then
-        * simply acquiring this artificial rt_mutex will boost task
-        * t's priority.  (Thanks to tglx for suggesting this approach!)
-        */
-       t = container_of(tb, struct task_struct, rcu_node_entry);
-       rt_mutex_init_proxy_locked(&mtx, t);
-       t->rcu_boost_mutex = &mtx;
-       local_irq_restore(flags);
-       rt_mutex_lock(&mtx);
-       rt_mutex_unlock(&mtx);  /* Keep lockdep happy. */
-
-       return ACCESS_ONCE(rcu_preempt_ctrlblk.boost_tasks) != NULL ||
-              ACCESS_ONCE(rcu_preempt_ctrlblk.exp_tasks) != NULL;
-}
-
-/*
- * Check to see if it is now time to start boosting RCU readers blocking
- * the current grace period, and, if so, tell the rcu_kthread_task to
- * start boosting them.  If there is an expedited boost in progress,
- * we wait for it to complete.
- *
- * If there are no blocked readers blocking the current grace period,
- * return 0 to let the caller know, otherwise return 1.  Note that this
- * return value is independent of whether or not boosting was done.
- */
-static int rcu_initiate_boost(void)
-{
-       if (!rcu_preempt_blocked_readers_cgp() &&
-           rcu_preempt_ctrlblk.exp_tasks == NULL) {
-               RCU_TRACE(rcu_preempt_ctrlblk.n_balk_exp_gp_tasks++);
-               return 0;
-       }
-       if (rcu_preempt_ctrlblk.exp_tasks != NULL ||
-           (rcu_preempt_ctrlblk.gp_tasks != NULL &&
-            rcu_preempt_ctrlblk.boost_tasks == NULL &&
-            ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time))) {
-               if (rcu_preempt_ctrlblk.exp_tasks == NULL)
-                       rcu_preempt_ctrlblk.boost_tasks =
-                               rcu_preempt_ctrlblk.gp_tasks;
-               invoke_rcu_callbacks();
-       } else {
-               RCU_TRACE(rcu_initiate_boost_trace());
-       }
-       return 1;
-}
-
-#define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000)
-
-/*
- * Do priority-boost accounting for the start of a new grace period.
- */
-static void rcu_preempt_boost_start_gp(void)
-{
-       rcu_preempt_ctrlblk.boost_time = jiffies + RCU_BOOST_DELAY_JIFFIES;
-}
-
-#else /* #ifdef CONFIG_RCU_BOOST */
-
-/*
- * If there is no RCU priority boosting, we don't initiate boosting,
- * but we do indicate whether there are blocked readers blocking the
- * current grace period.
- */
-static int rcu_initiate_boost(void)
-{
-       return rcu_preempt_blocked_readers_cgp();
-}
-
-/*
- * If there is no RCU priority boosting, nothing to do at grace-period start.
- */
-static void rcu_preempt_boost_start_gp(void)
-{
-}
-
-#endif /* else #ifdef CONFIG_RCU_BOOST */
-
-/*
- * Record a preemptible-RCU quiescent state for the specified CPU.  Note
- * that this just means that the task currently running on the CPU is
- * in a quiescent state.  There might be any number of tasks blocked
- * while in an RCU read-side critical section.
- *
- * Unlike the other rcu_*_qs() functions, callers to this function
- * must disable irqs in order to protect the assignment to
- * ->rcu_read_unlock_special.
- *
- * Because this is a single-CPU implementation, the only way a grace
- * period can end is if the CPU is in a quiescent state.  The reason is
- * that a blocked preemptible-RCU reader can exit its critical section
- * only if the CPU is running it at the time.  Therefore, when the
- * last task blocking the current grace period exits its RCU read-side
- * critical section, neither the CPU nor blocked tasks will be stopping
- * the current grace period.  (In contrast, SMP implementations
- * might have CPUs running in RCU read-side critical sections that
- * block later grace periods -- but this is not possible given only
- * one CPU.)
- */
-static void rcu_preempt_cpu_qs(void)
-{
-       /* Record both CPU and task as having responded to current GP. */
-       rcu_preempt_ctrlblk.gpcpu = rcu_preempt_ctrlblk.gpnum;
-       current->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_NEED_QS;
-
-       /* If there is no GP then there is nothing more to do.  */
-       if (!rcu_preempt_gp_in_progress())
-               return;
-       /*
-        * Check up on boosting.  If there are readers blocking the
-        * current grace period, leave.
-        */
-       if (rcu_initiate_boost())
-               return;
-
-       /* Advance callbacks. */
-       rcu_preempt_ctrlblk.completed = rcu_preempt_ctrlblk.gpnum;
-       rcu_preempt_ctrlblk.rcb.donetail = rcu_preempt_ctrlblk.rcb.curtail;
-       rcu_preempt_ctrlblk.rcb.curtail = rcu_preempt_ctrlblk.nexttail;
-
-       /* If there are no blocked readers, next GP is done instantly. */
-       if (!rcu_preempt_blocked_readers_any())
-               rcu_preempt_ctrlblk.rcb.donetail = rcu_preempt_ctrlblk.nexttail;
-
-       /* If there are done callbacks, cause them to be invoked. */
-       if (*rcu_preempt_ctrlblk.rcb.donetail != NULL)
-               invoke_rcu_callbacks();
-}
-
-/*
- * Start a new RCU grace period if warranted.  Hard irqs must be disabled.
- */
-static void rcu_preempt_start_gp(void)
-{
-       if (!rcu_preempt_gp_in_progress() && rcu_preempt_needs_another_gp()) {
-
-               /* Official start of GP. */
-               rcu_preempt_ctrlblk.gpnum++;
-               RCU_TRACE(rcu_preempt_ctrlblk.n_grace_periods++);
-               reset_cpu_stall_ticks(&rcu_preempt_ctrlblk.rcb);
-
-               /* Any blocked RCU readers block new GP. */
-               if (rcu_preempt_blocked_readers_any())
-                       rcu_preempt_ctrlblk.gp_tasks =
-                               rcu_preempt_ctrlblk.blkd_tasks.next;
-
-               /* Set up for RCU priority boosting. */
-               rcu_preempt_boost_start_gp();
-
-               /* If there is no running reader, CPU is done with GP. */
-               if (!rcu_preempt_running_reader())
-                       rcu_preempt_cpu_qs();
-       }
-}
-
-/*
- * We have entered the scheduler, and the current task might soon be
- * context-switched away from.  If this task is in an RCU read-side
- * critical section, we will no longer be able to rely on the CPU to
- * record that fact, so we enqueue the task on the blkd_tasks list.
- * If the task started after the current grace period began, as recorded
- * by ->gpcpu, we enqueue at the beginning of the list.  Otherwise
- * before the element referenced by ->gp_tasks (or at the tail if
- * ->gp_tasks is NULL) and point ->gp_tasks at the newly added element.
- * The task will dequeue itself when it exits the outermost enclosing
- * RCU read-side critical section.  Therefore, the current grace period
- * cannot be permitted to complete until the ->gp_tasks pointer becomes
- * NULL.
- *
- * Caller must disable preemption.
- */
-void rcu_preempt_note_context_switch(void)
-{
-       struct task_struct *t = current;
-       unsigned long flags;
-
-       local_irq_save(flags); /* must exclude scheduler_tick(). */
-       if (rcu_preempt_running_reader() > 0 &&
-           (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) {
-
-               /* Possibly blocking in an RCU read-side critical section. */
-               t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED;
-
-               /*
-                * If this CPU has already checked in, then this task
-                * will hold up the next grace period rather than the
-                * current grace period.  Queue the task accordingly.
-                * If the task is queued for the current grace period
-                * (i.e., this CPU has not yet passed through a quiescent
-                * state for the current grace period), then as long
-                * as that task remains queued, the current grace period
-                * cannot end.
-                */
-               list_add(&t->rcu_node_entry, &rcu_preempt_ctrlblk.blkd_tasks);
-               if (rcu_cpu_blocking_cur_gp())
-                       rcu_preempt_ctrlblk.gp_tasks = &t->rcu_node_entry;
-       } else if (rcu_preempt_running_reader() < 0 &&
-                  t->rcu_read_unlock_special) {
-               /*
-                * Complete exit from RCU read-side critical section on
-                * behalf of preempted instance of __rcu_read_unlock().
-                */
-               rcu_read_unlock_special(t);
-       }
-
-       /*
-        * Either we were not in an RCU read-side critical section to
-        * begin with, or we have now recorded that critical section
-        * globally.  Either way, we can now note a quiescent state
-        * for this CPU.  Again, if we were in an RCU read-side critical
-        * section, and if that critical section was blocking the current
-        * grace period, then the fact that the task has been enqueued
-        * means that current grace period continues to be blocked.
-        */
-       rcu_preempt_cpu_qs();
-       local_irq_restore(flags);
-}
-
-/*
- * Handle special cases during rcu_read_unlock(), such as needing to
- * notify RCU core processing or task having blocked during the RCU
- * read-side critical section.
- */
-void rcu_read_unlock_special(struct task_struct *t)
-{
-       int empty;
-       int empty_exp;
-       unsigned long flags;
-       struct list_head *np;
-#ifdef CONFIG_RCU_BOOST
-       struct rt_mutex *rbmp = NULL;
-#endif /* #ifdef CONFIG_RCU_BOOST */
-       int special;
-
-       /*
-        * NMI handlers cannot block and cannot safely manipulate state.
-        * They therefore cannot possibly be special, so just leave.
-        */
-       if (in_nmi())
-               return;
-
-       local_irq_save(flags);
-
-       /*
-        * If RCU core is waiting for this CPU to exit critical section,
-        * let it know that we have done so.
-        */
-       special = t->rcu_read_unlock_special;
-       if (special & RCU_READ_UNLOCK_NEED_QS)
-               rcu_preempt_cpu_qs();
-
-       /* Hardware IRQ handlers cannot block. */
-       if (in_irq() || in_serving_softirq()) {
-               local_irq_restore(flags);
-               return;
-       }
-
-       /* Clean up if blocked during RCU read-side critical section. */
-       if (special & RCU_READ_UNLOCK_BLOCKED) {
-               t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BLOCKED;
-
-               /*
-                * Remove this task from the ->blkd_tasks list and adjust
-                * any pointers that might have been referencing it.
-                */
-               empty = !rcu_preempt_blocked_readers_cgp();
-               empty_exp = rcu_preempt_ctrlblk.exp_tasks == NULL;
-               np = rcu_next_node_entry(t);
-               list_del_init(&t->rcu_node_entry);
-               if (&t->rcu_node_entry == rcu_preempt_ctrlblk.gp_tasks)
-                       rcu_preempt_ctrlblk.gp_tasks = np;
-               if (&t->rcu_node_entry == rcu_preempt_ctrlblk.exp_tasks)
-                       rcu_preempt_ctrlblk.exp_tasks = np;
-#ifdef CONFIG_RCU_BOOST
-               if (&t->rcu_node_entry == rcu_preempt_ctrlblk.boost_tasks)
-                       rcu_preempt_ctrlblk.boost_tasks = np;
-#endif /* #ifdef CONFIG_RCU_BOOST */
-
-               /*
-                * If this was the last task on the current list, and if
-                * we aren't waiting on the CPU, report the quiescent state
-                * and start a new grace period if needed.
-                */
-               if (!empty && !rcu_preempt_blocked_readers_cgp()) {
-                       rcu_preempt_cpu_qs();
-                       rcu_preempt_start_gp();
-               }
-
-               /*
-                * If this was the last task on the expedited lists,
-                * then we need wake up the waiting task.
-                */
-               if (!empty_exp && rcu_preempt_ctrlblk.exp_tasks == NULL)
-                       rcu_report_exp_done();
-       }
-#ifdef CONFIG_RCU_BOOST
-       /* Unboost self if was boosted. */
-       if (t->rcu_boost_mutex != NULL) {
-               rbmp = t->rcu_boost_mutex;
-               t->rcu_boost_mutex = NULL;
-               rt_mutex_unlock(rbmp);
-       }
-#endif /* #ifdef CONFIG_RCU_BOOST */
-       local_irq_restore(flags);
-}
-
-/*
- * Check for a quiescent state from the current CPU.  When a task blocks,
- * the task is recorded in the rcu_preempt_ctrlblk structure, which is
- * checked elsewhere.  This is called from the scheduling-clock interrupt.
- *
- * Caller must disable hard irqs.
- */
-static void rcu_preempt_check_callbacks(void)
-{
-       struct task_struct *t = current;
-
-       if (rcu_preempt_gp_in_progress() &&
-           (!rcu_preempt_running_reader() ||
-            !rcu_cpu_blocking_cur_gp()))
-               rcu_preempt_cpu_qs();
-       if (&rcu_preempt_ctrlblk.rcb.rcucblist !=
-           rcu_preempt_ctrlblk.rcb.donetail)
-               invoke_rcu_callbacks();
-       if (rcu_preempt_gp_in_progress() &&
-           rcu_cpu_blocking_cur_gp() &&
-           rcu_preempt_running_reader() > 0)
-               t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS;
-}
-
-/*
- * TINY_PREEMPT_RCU has an extra callback-list tail pointer to
- * update, so this is invoked from rcu_process_callbacks() to
- * handle that case.  Of course, it is invoked for all flavors of
- * RCU, but RCU callbacks can appear only on one of the lists, and
- * neither ->nexttail nor ->donetail can possibly be NULL, so there
- * is no need for an explicit check.
- */
-static void rcu_preempt_remove_callbacks(struct rcu_ctrlblk *rcp)
-{
-       if (rcu_preempt_ctrlblk.nexttail == rcp->donetail)
-               rcu_preempt_ctrlblk.nexttail = &rcp->rcucblist;
-}
-
-/*
- * Process callbacks for preemptible RCU.
- */
-static void rcu_preempt_process_callbacks(void)
-{
-       __rcu_process_callbacks(&rcu_preempt_ctrlblk.rcb);
-}
-
-/*
- * Queue a preemptible -RCU callback for invocation after a grace period.
- */
-void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
-{
-       unsigned long flags;
-
-       debug_rcu_head_queue(head);
-       head->func = func;
-       head->next = NULL;
-
-       local_irq_save(flags);
-       *rcu_preempt_ctrlblk.nexttail = head;
-       rcu_preempt_ctrlblk.nexttail = &head->next;
-       RCU_TRACE(rcu_preempt_ctrlblk.rcb.qlen++);
-       rcu_preempt_start_gp();  /* checks to see if GP needed. */
-       local_irq_restore(flags);
-}
-EXPORT_SYMBOL_GPL(call_rcu);
-
-/*
- * synchronize_rcu - wait until a grace period has elapsed.
- *
- * Control will return to the caller some time after a full grace
- * period has elapsed, in other words after all currently executing RCU
- * read-side critical sections have completed.  RCU read-side critical
- * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
- * and may be nested.
- */
-void synchronize_rcu(void)
-{
-       rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) &&
-                          !lock_is_held(&rcu_lock_map) &&
-                          !lock_is_held(&rcu_sched_lock_map),
-                          "Illegal synchronize_rcu() in RCU read-side critical section");
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       if (!rcu_scheduler_active)
-               return;
-#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
-
-       WARN_ON_ONCE(rcu_preempt_running_reader());
-       if (!rcu_preempt_blocked_readers_any())
-               return;
-
-       /* Once we get past the fastpath checks, same code as rcu_barrier(). */
-       if (rcu_expedited)
-               synchronize_rcu_expedited();
-       else
-               rcu_barrier();
-}
-EXPORT_SYMBOL_GPL(synchronize_rcu);
-
-static DECLARE_WAIT_QUEUE_HEAD(sync_rcu_preempt_exp_wq);
-static unsigned long sync_rcu_preempt_exp_count;
-static DEFINE_MUTEX(sync_rcu_preempt_exp_mutex);
-
-/*
- * Return non-zero if there are any tasks in RCU read-side critical
- * sections blocking the current preemptible-RCU expedited grace period.
- * If there is no preemptible-RCU expedited grace period currently in
- * progress, returns zero unconditionally.
- */
-static int rcu_preempted_readers_exp(void)
-{
-       return rcu_preempt_ctrlblk.exp_tasks != NULL;
-}
-
-/*
- * Report the exit from RCU read-side critical section for the last task
- * that queued itself during or before the current expedited preemptible-RCU
- * grace period.
- */
-static void rcu_report_exp_done(void)
-{
-       wake_up(&sync_rcu_preempt_exp_wq);
-}
-
-/*
- * Wait for an rcu-preempt grace period, but expedite it.  The basic idea
- * is to rely in the fact that there is but one CPU, and that it is
- * illegal for a task to invoke synchronize_rcu_expedited() while in a
- * preemptible-RCU read-side critical section.  Therefore, any such
- * critical sections must correspond to blocked tasks, which must therefore
- * be on the ->blkd_tasks list.  So just record the current head of the
- * list in the ->exp_tasks pointer, and wait for all tasks including and
- * after the task pointed to by ->exp_tasks to drain.
- */
-void synchronize_rcu_expedited(void)
-{
-       unsigned long flags;
-       struct rcu_preempt_ctrlblk *rpcp = &rcu_preempt_ctrlblk;
-       unsigned long snap;
-
-       barrier(); /* ensure prior action seen before grace period. */
-
-       WARN_ON_ONCE(rcu_preempt_running_reader());
-
-       /*
-        * Acquire lock so that there is only one preemptible RCU grace
-        * period in flight.  Of course, if someone does the expedited
-        * grace period for us while we are acquiring the lock, just leave.
-        */
-       snap = sync_rcu_preempt_exp_count + 1;
-       mutex_lock(&sync_rcu_preempt_exp_mutex);
-       if (ULONG_CMP_LT(snap, sync_rcu_preempt_exp_count))
-               goto unlock_mb_ret; /* Others did our work for us. */
-
-       local_irq_save(flags);
-
-       /*
-        * All RCU readers have to already be on blkd_tasks because
-        * we cannot legally be executing in an RCU read-side critical
-        * section.
-        */
-
-       /* Snapshot current head of ->blkd_tasks list. */
-       rpcp->exp_tasks = rpcp->blkd_tasks.next;
-       if (rpcp->exp_tasks == &rpcp->blkd_tasks)
-               rpcp->exp_tasks = NULL;
-
-       /* Wait for tail of ->blkd_tasks list to drain. */
-       if (!rcu_preempted_readers_exp()) {
-               local_irq_restore(flags);
-       } else {
-               rcu_initiate_boost();
-               local_irq_restore(flags);
-               wait_event(sync_rcu_preempt_exp_wq,
-                          !rcu_preempted_readers_exp());
-       }
-
-       /* Clean up and exit. */
-       barrier(); /* ensure expedited GP seen before counter increment. */
-       sync_rcu_preempt_exp_count++;
-unlock_mb_ret:
-       mutex_unlock(&sync_rcu_preempt_exp_mutex);
-       barrier(); /* ensure subsequent action seen after grace period. */
-}
-EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
-
-/*
- * Does preemptible RCU need the CPU to stay out of dynticks mode?
- */
-int rcu_preempt_needs_cpu(void)
-{
-       return rcu_preempt_ctrlblk.rcb.rcucblist != NULL;
-}
-
-#else /* #ifdef CONFIG_TINY_PREEMPT_RCU */
-
-#ifdef CONFIG_RCU_TRACE
-
-/*
- * Because preemptible RCU does not exist, it is not necessary to
- * dump out its statistics.
- */
-static void show_tiny_preempt_stats(struct seq_file *m)
-{
-}
-
-#endif /* #ifdef CONFIG_RCU_TRACE */
-
-/*
- * Because preemptible RCU does not exist, it never has any callbacks
- * to check.
- */
-static void rcu_preempt_check_callbacks(void)
-{
-}
-
-/*
- * Because preemptible RCU does not exist, it never has any callbacks
- * to remove.
- */
-static void rcu_preempt_remove_callbacks(struct rcu_ctrlblk *rcp)
-{
-}
-
-/*
- * Because preemptible RCU does not exist, it never has any callbacks
- * to process.
- */
-static void rcu_preempt_process_callbacks(void)
-{
-}
-
-#endif /* #else #ifdef CONFIG_TINY_PREEMPT_RCU */
-
-#ifdef CONFIG_RCU_BOOST
-
-/*
- * Wake up rcu_kthread() to process callbacks now eligible for invocation
- * or to boost readers.
- */
-static void invoke_rcu_callbacks(void)
-{
-       have_rcu_kthread_work = 1;
-       if (rcu_kthread_task != NULL)
-               wake_up(&rcu_kthread_wq);
-}
-
-#ifdef CONFIG_RCU_TRACE
-
-/*
- * Is the current CPU running the RCU-callbacks kthread?
- * Caller must have preemption disabled.
- */
-static bool rcu_is_callbacks_kthread(void)
-{
-       return rcu_kthread_task == current;
-}
-
-#endif /* #ifdef CONFIG_RCU_TRACE */
-
-/*
- * This kthread invokes RCU callbacks whose grace periods have
- * elapsed.  It is awakened as needed, and takes the place of the
- * RCU_SOFTIRQ that is used for this purpose when boosting is disabled.
- * This is a kthread, but it is never stopped, at least not until
- * the system goes down.
- */
-static int rcu_kthread(void *arg)
-{
-       unsigned long work;
-       unsigned long morework;
-       unsigned long flags;
-
-       for (;;) {
-               wait_event_interruptible(rcu_kthread_wq,
-                                        have_rcu_kthread_work != 0);
-               morework = rcu_boost();
-               local_irq_save(flags);
-               work = have_rcu_kthread_work;
-               have_rcu_kthread_work = morework;
-               local_irq_restore(flags);
-               if (work)
-                       rcu_process_callbacks(NULL);
-               schedule_timeout_interruptible(1); /* Leave CPU for others. */
-       }
-
-       return 0;  /* Not reached, but needed to shut gcc up. */
-}
-
-/*
- * Spawn the kthread that invokes RCU callbacks.
- */
-static int __init rcu_spawn_kthreads(void)
-{
-       struct sched_param sp;
-
-       rcu_kthread_task = kthread_run(rcu_kthread, NULL, "rcu_kthread");
-       sp.sched_priority = RCU_BOOST_PRIO;
-       sched_setscheduler_nocheck(rcu_kthread_task, SCHED_FIFO, &sp);
-       return 0;
-}
-early_initcall(rcu_spawn_kthreads);
-
-#else /* #ifdef CONFIG_RCU_BOOST */
-
-/* Hold off callback invocation until early_initcall() time. */
-static int rcu_scheduler_fully_active __read_mostly;
-
-/*
- * Start up softirq processing of callbacks.
- */
-void invoke_rcu_callbacks(void)
-{
-       if (rcu_scheduler_fully_active)
-               raise_softirq(RCU_SOFTIRQ);
-}
-
-#ifdef CONFIG_RCU_TRACE
-
-/*
- * There is no callback kthread, so this thread is never it.
- */
-static bool rcu_is_callbacks_kthread(void)
-{
-       return false;
-}
-
-#endif /* #ifdef CONFIG_RCU_TRACE */
-
-static int __init rcu_scheduler_really_started(void)
-{
-       rcu_scheduler_fully_active = 1;
-       open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
-       raise_softirq(RCU_SOFTIRQ);  /* Invoke any callbacks from early boot. */
-       return 0;
-}
-early_initcall(rcu_scheduler_really_started);
-
-#endif /* #else #ifdef CONFIG_RCU_BOOST */
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-#include <linux/kernel_stat.h>
 
 /*
  * During boot, we forgive RCU lockdep issues.  After this function is
@@ -1020,25 +72,6 @@ void __init rcu_scheduler_starting(void)
 
 #ifdef CONFIG_RCU_TRACE
 
-#ifdef CONFIG_RCU_BOOST
-
-static void rcu_initiate_boost_trace(void)
-{
-       if (list_empty(&rcu_preempt_ctrlblk.blkd_tasks))
-               rcu_preempt_ctrlblk.n_balk_blkd_tasks++;
-       else if (rcu_preempt_ctrlblk.gp_tasks == NULL &&
-                rcu_preempt_ctrlblk.exp_tasks == NULL)
-               rcu_preempt_ctrlblk.n_balk_exp_gp_tasks++;
-       else if (rcu_preempt_ctrlblk.boost_tasks != NULL)
-               rcu_preempt_ctrlblk.n_balk_boost_tasks++;
-       else if (!ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time))
-               rcu_preempt_ctrlblk.n_balk_notyet++;
-       else
-               rcu_preempt_ctrlblk.n_balk_nos++;
-}
-
-#endif /* #ifdef CONFIG_RCU_BOOST */
-
 static void rcu_trace_sub_qlen(struct rcu_ctrlblk *rcp, int n)
 {
        unsigned long flags;
@@ -1053,7 +86,6 @@ static void rcu_trace_sub_qlen(struct rcu_ctrlblk *rcp, int n)
  */
 static int show_tiny_stats(struct seq_file *m, void *unused)
 {
-       show_tiny_preempt_stats(m);
        seq_printf(m, "rcu_sched: qlen: %ld\n", rcu_sched_ctrlblk.qlen);
        seq_printf(m, "rcu_bh: qlen: %ld\n", rcu_bh_ctrlblk.qlen);
        return 0;
@@ -1103,11 +135,40 @@ MODULE_AUTHOR("Paul E. McKenney");
 MODULE_DESCRIPTION("Read-Copy Update tracing for tiny implementation");
 MODULE_LICENSE("GPL");
 
-static void check_cpu_stall_preempt(void)
+static void check_cpu_stall(struct rcu_ctrlblk *rcp)
 {
-#ifdef CONFIG_TINY_PREEMPT_RCU
-       check_cpu_stall(&rcu_preempt_ctrlblk.rcb);
-#endif /* #ifdef CONFIG_TINY_PREEMPT_RCU */
+       unsigned long j;
+       unsigned long js;
+
+       if (rcu_cpu_stall_suppress)
+               return;
+       rcp->ticks_this_gp++;
+       j = jiffies;
+       js = rcp->jiffies_stall;
+       if (*rcp->curtail && ULONG_CMP_GE(j, js)) {
+               pr_err("INFO: %s stall on CPU (%lu ticks this GP) idle=%llx (t=%lu jiffies q=%ld)\n",
+                      rcp->name, rcp->ticks_this_gp, rcu_dynticks_nesting,
+                      jiffies - rcp->gp_start, rcp->qlen);
+               dump_stack();
+       }
+       if (*rcp->curtail && ULONG_CMP_GE(j, js))
+               rcp->jiffies_stall = jiffies +
+                       3 * rcu_jiffies_till_stall_check() + 3;
+       else if (ULONG_CMP_GE(j, js))
+               rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check();
+}
+
+static void reset_cpu_stall_ticks(struct rcu_ctrlblk *rcp)
+{
+       rcp->ticks_this_gp = 0;
+       rcp->gp_start = jiffies;
+       rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check();
+}
+
+static void check_cpu_stalls(void)
+{
+       RCU_TRACE(check_cpu_stall(&rcu_bh_ctrlblk));
+       RCU_TRACE(check_cpu_stall(&rcu_sched_ctrlblk));
 }
 
 #endif /* #ifdef CONFIG_RCU_TRACE */
index e1f3a8c96724374be64e1cf252a40f2e9eac5a70..b1fa5510388d12ff95afa6f38a090956551a5907 100644 (file)
@@ -695,44 +695,6 @@ static struct rcu_torture_ops srcu_sync_ops = {
        .name           = "srcu_sync"
 };
 
-static int srcu_torture_read_lock_raw(void) __acquires(&srcu_ctl)
-{
-       return srcu_read_lock_raw(&srcu_ctl);
-}
-
-static void srcu_torture_read_unlock_raw(int idx) __releases(&srcu_ctl)
-{
-       srcu_read_unlock_raw(&srcu_ctl, idx);
-}
-
-static struct rcu_torture_ops srcu_raw_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = srcu_torture_read_lock_raw,
-       .read_delay     = srcu_read_delay,
-       .readunlock     = srcu_torture_read_unlock_raw,
-       .completed      = srcu_torture_completed,
-       .deferred_free  = srcu_torture_deferred_free,
-       .sync           = srcu_torture_synchronize,
-       .call           = NULL,
-       .cb_barrier     = NULL,
-       .stats          = srcu_torture_stats,
-       .name           = "srcu_raw"
-};
-
-static struct rcu_torture_ops srcu_raw_sync_ops = {
-       .init           = rcu_sync_torture_init,
-       .readlock       = srcu_torture_read_lock_raw,
-       .read_delay     = srcu_read_delay,
-       .readunlock     = srcu_torture_read_unlock_raw,
-       .completed      = srcu_torture_completed,
-       .deferred_free  = rcu_sync_torture_deferred_free,
-       .sync           = srcu_torture_synchronize,
-       .call           = NULL,
-       .cb_barrier     = NULL,
-       .stats          = srcu_torture_stats,
-       .name           = "srcu_raw_sync"
-};
-
 static void srcu_torture_synchronize_expedited(void)
 {
        synchronize_srcu_expedited(&srcu_ctl);
@@ -1983,7 +1945,6 @@ rcu_torture_init(void)
                { &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,
                  &rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops,
                  &srcu_ops, &srcu_sync_ops, &srcu_expedited_ops,
-                 &srcu_raw_ops, &srcu_raw_sync_ops,
                  &sched_ops, &sched_sync_ops, &sched_expedited_ops, };
 
        mutex_lock(&fullstop_mutex);
index 35380019f0fc101df423dab03d3b418ec2291eac..e08abb9461acc13dda0a7c4901d228554c12443e 100644 (file)
@@ -218,8 +218,8 @@ module_param(blimit, long, 0444);
 module_param(qhimark, long, 0444);
 module_param(qlowmark, long, 0444);
 
-static ulong jiffies_till_first_fqs = RCU_JIFFIES_TILL_FORCE_QS;
-static ulong jiffies_till_next_fqs = RCU_JIFFIES_TILL_FORCE_QS;
+static ulong jiffies_till_first_fqs = ULONG_MAX;
+static ulong jiffies_till_next_fqs = ULONG_MAX;
 
 module_param(jiffies_till_first_fqs, ulong, 0644);
 module_param(jiffies_till_next_fqs, ulong, 0644);
@@ -866,7 +866,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
         * See Documentation/RCU/stallwarn.txt for info on how to debug
         * RCU CPU stall warnings.
         */
-       printk(KERN_ERR "INFO: %s detected stalls on CPUs/tasks:",
+       pr_err("INFO: %s detected stalls on CPUs/tasks:",
               rsp->name);
        print_cpu_stall_info_begin();
        rcu_for_each_leaf_node(rsp, rnp) {
@@ -899,7 +899,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
               smp_processor_id(), (long)(jiffies - rsp->gp_start),
               rsp->gpnum, rsp->completed, totqlen);
        if (ndetected == 0)
-               printk(KERN_ERR "INFO: Stall ended before state dump start\n");
+               pr_err("INFO: Stall ended before state dump start\n");
        else if (!trigger_all_cpu_backtrace())
                rcu_dump_cpu_stacks(rsp);
 
@@ -922,7 +922,7 @@ static void print_cpu_stall(struct rcu_state *rsp)
         * See Documentation/RCU/stallwarn.txt for info on how to debug
         * RCU CPU stall warnings.
         */
-       printk(KERN_ERR "INFO: %s self-detected stall on CPU", rsp->name);
+       pr_err("INFO: %s self-detected stall on CPU", rsp->name);
        print_cpu_stall_info_begin();
        print_cpu_stall_info(rsp, smp_processor_id());
        print_cpu_stall_info_end();
@@ -984,65 +984,6 @@ void rcu_cpu_stall_reset(void)
                rsp->jiffies_stall = jiffies + ULONG_MAX / 2;
 }
 
-/*
- * Update CPU-local rcu_data state to record the newly noticed grace period.
- * This is used both when we started the grace period and when we notice
- * that someone else started the grace period.  The caller must hold the
- * ->lock of the leaf rcu_node structure corresponding to the current CPU,
- *  and must have irqs disabled.
- */
-static void __note_new_gpnum(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp)
-{
-       if (rdp->gpnum != rnp->gpnum) {
-               /*
-                * If the current grace period is waiting for this CPU,
-                * set up to detect a quiescent state, otherwise don't
-                * go looking for one.
-                */
-               rdp->gpnum = rnp->gpnum;
-               trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpustart");
-               rdp->passed_quiesce = 0;
-               rdp->qs_pending = !!(rnp->qsmask & rdp->grpmask);
-               zero_cpu_stall_ticks(rdp);
-       }
-}
-
-static void note_new_gpnum(struct rcu_state *rsp, struct rcu_data *rdp)
-{
-       unsigned long flags;
-       struct rcu_node *rnp;
-
-       local_irq_save(flags);
-       rnp = rdp->mynode;
-       if (rdp->gpnum == ACCESS_ONCE(rnp->gpnum) || /* outside lock. */
-           !raw_spin_trylock(&rnp->lock)) { /* irqs already off, so later. */
-               local_irq_restore(flags);
-               return;
-       }
-       __note_new_gpnum(rsp, rnp, rdp);
-       raw_spin_unlock_irqrestore(&rnp->lock, flags);
-}
-
-/*
- * Did someone else start a new RCU grace period start since we last
- * checked?  Update local state appropriately if so.  Must be called
- * on the CPU corresponding to rdp.
- */
-static int
-check_for_new_grace_period(struct rcu_state *rsp, struct rcu_data *rdp)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       local_irq_save(flags);
-       if (rdp->gpnum != rsp->gpnum) {
-               note_new_gpnum(rsp, rdp);
-               ret = 1;
-       }
-       local_irq_restore(flags);
-       return ret;
-}
-
 /*
  * Initialize the specified rcu_data structure's callback list to empty.
  */
@@ -1313,18 +1254,16 @@ static void rcu_advance_cbs(struct rcu_state *rsp, struct rcu_node *rnp,
 }
 
 /*
- * Advance this CPU's callbacks, but only if the current grace period
- * has ended.  This may be called only from the CPU to whom the rdp
- * belongs.  In addition, the corresponding leaf rcu_node structure's
- * ->lock must be held by the caller, with irqs disabled.
+ * Update CPU-local rcu_data state to record the beginnings and ends of
+ * grace periods.  The caller must hold the ->lock of the leaf rcu_node
+ * structure corresponding to the current CPU, and must have irqs disabled.
  */
-static void
-__rcu_process_gp_end(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp)
+static void __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp)
 {
-       /* Did another grace period end? */
+       /* Handle the ends of any preceding grace periods first. */
        if (rdp->completed == rnp->completed) {
 
-               /* No, so just accelerate recent callbacks. */
+               /* No grace period end, so just accelerate recent callbacks. */
                rcu_accelerate_cbs(rsp, rnp, rdp);
 
        } else {
@@ -1335,67 +1274,39 @@ __rcu_process_gp_end(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_dat
                /* Remember that we saw this grace-period completion. */
                rdp->completed = rnp->completed;
                trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpuend");
+       }
 
+       if (rdp->gpnum != rnp->gpnum) {
                /*
-                * If we were in an extended quiescent state, we may have
-                * missed some grace periods that others CPUs handled on
-                * our behalf. Catch up with this state to avoid noting
-                * spurious new grace periods.  If another grace period
-                * has started, then rnp->gpnum will have advanced, so
-                * we will detect this later on.  Of course, any quiescent
-                * states we found for the old GP are now invalid.
-                */
-               if (ULONG_CMP_LT(rdp->gpnum, rdp->completed)) {
-                       rdp->gpnum = rdp->completed;
-                       rdp->passed_quiesce = 0;
-               }
-
-               /*
-                * If RCU does not need a quiescent state from this CPU,
-                * then make sure that this CPU doesn't go looking for one.
+                * If the current grace period is waiting for this CPU,
+                * set up to detect a quiescent state, otherwise don't
+                * go looking for one.
                 */
-               if ((rnp->qsmask & rdp->grpmask) == 0)
-                       rdp->qs_pending = 0;
+               rdp->gpnum = rnp->gpnum;
+               trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpustart");
+               rdp->passed_quiesce = 0;
+               rdp->qs_pending = !!(rnp->qsmask & rdp->grpmask);
+               zero_cpu_stall_ticks(rdp);
        }
 }
 
-/*
- * Advance this CPU's callbacks, but only if the current grace period
- * has ended.  This may be called only from the CPU to whom the rdp
- * belongs.
- */
-static void
-rcu_process_gp_end(struct rcu_state *rsp, struct rcu_data *rdp)
+static void note_gp_changes(struct rcu_state *rsp, struct rcu_data *rdp)
 {
        unsigned long flags;
        struct rcu_node *rnp;
 
        local_irq_save(flags);
        rnp = rdp->mynode;
-       if (rdp->completed == ACCESS_ONCE(rnp->completed) || /* outside lock. */
+       if ((rdp->gpnum == ACCESS_ONCE(rnp->gpnum) &&
+            rdp->completed == ACCESS_ONCE(rnp->completed)) || /* w/out lock. */
            !raw_spin_trylock(&rnp->lock)) { /* irqs already off, so later. */
                local_irq_restore(flags);
                return;
        }
-       __rcu_process_gp_end(rsp, rnp, rdp);
+       __note_gp_changes(rsp, rnp, rdp);
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
 }
 
-/*
- * Do per-CPU grace-period initialization for running CPU.  The caller
- * must hold the lock of the leaf rcu_node structure corresponding to
- * this CPU.
- */
-static void
-rcu_start_gp_per_cpu(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp)
-{
-       /* Prior grace period ended, so advance callbacks for current CPU. */
-       __rcu_process_gp_end(rsp, rnp, rdp);
-
-       /* Set state so that this CPU will detect the next quiescent state. */
-       __note_new_gpnum(rsp, rnp, rdp);
-}
-
 /*
  * Initialize a new grace period.
  */
@@ -1444,7 +1355,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
                WARN_ON_ONCE(rnp->completed != rsp->completed);
                ACCESS_ONCE(rnp->completed) = rsp->completed;
                if (rnp == rdp->mynode)
-                       rcu_start_gp_per_cpu(rsp, rnp, rdp);
+                       __note_gp_changes(rsp, rnp, rdp);
                rcu_preempt_boost_start_gp(rnp);
                trace_rcu_grace_period_init(rsp->name, rnp->gpnum,
                                            rnp->level, rnp->grplo,
@@ -1527,7 +1438,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
                ACCESS_ONCE(rnp->completed) = rsp->gpnum;
                rdp = this_cpu_ptr(rsp->rda);
                if (rnp == rdp->mynode)
-                       __rcu_process_gp_end(rsp, rnp, rdp);
+                       __note_gp_changes(rsp, rnp, rdp);
                nocb += rcu_future_gp_cleanup(rsp, rnp);
                raw_spin_unlock_irq(&rnp->lock);
                cond_resched();
@@ -1805,9 +1716,8 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp)
 static void
 rcu_check_quiescent_state(struct rcu_state *rsp, struct rcu_data *rdp)
 {
-       /* If there is now a new grace period, record and return. */
-       if (check_for_new_grace_period(rsp, rdp))
-               return;
+       /* Check for grace-period ends and beginnings. */
+       note_gp_changes(rsp, rdp);
 
        /*
         * Does this CPU still need to do its part for current grace period?
@@ -2271,9 +2181,6 @@ __rcu_process_callbacks(struct rcu_state *rsp)
 
        WARN_ON_ONCE(rdp->beenonline == 0);
 
-       /* Handle the end of a grace period that some other CPU ended.  */
-       rcu_process_gp_end(rsp, rdp);
-
        /* Update RCU state based on any recent quiescent states. */
        rcu_check_quiescent_state(rsp, rdp);
 
@@ -2358,8 +2265,7 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
        if (unlikely(rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) {
 
                /* Are we ignoring a completed grace period? */
-               rcu_process_gp_end(rsp, rdp);
-               check_for_new_grace_period(rsp, rdp);
+               note_gp_changes(rsp, rdp);
 
                /* Start a new grace period if one not already started. */
                if (!rcu_gp_in_progress(rsp)) {
@@ -3120,7 +3026,7 @@ static int __init rcu_spawn_gp_kthread(void)
        struct task_struct *t;
 
        for_each_rcu_flavor(rsp) {
-               t = kthread_run(rcu_gp_kthread, rsp, rsp->name);
+               t = kthread_run(rcu_gp_kthread, rsp, "%s", rsp->name);
                BUG_ON(IS_ERR(t));
                rnp = rcu_get_root(rsp);
                raw_spin_lock_irqsave(&rnp->lock, flags);
@@ -3265,11 +3171,25 @@ static void __init rcu_init_one(struct rcu_state *rsp,
  */
 static void __init rcu_init_geometry(void)
 {
+       ulong d;
        int i;
        int j;
        int n = nr_cpu_ids;
        int rcu_capacity[MAX_RCU_LVLS + 1];
 
+       /*
+        * Initialize any unspecified boot parameters.
+        * The default values of jiffies_till_first_fqs and
+        * jiffies_till_next_fqs are set to the RCU_JIFFIES_TILL_FORCE_QS
+        * value, which is a function of HZ, then adding one for each
+        * RCU_JIFFIES_FQS_DIV CPUs that might be on the system.
+        */
+       d = RCU_JIFFIES_TILL_FORCE_QS + nr_cpu_ids / RCU_JIFFIES_FQS_DIV;
+       if (jiffies_till_first_fqs == ULONG_MAX)
+               jiffies_till_first_fqs = d;
+       if (jiffies_till_next_fqs == ULONG_MAX)
+               jiffies_till_next_fqs = d;
+
        /* If the compile-time values are accurate, just leave. */
        if (rcu_fanout_leaf == CONFIG_RCU_FANOUT_LEAF &&
            nr_cpu_ids == NR_CPUS)
index 4df503470e420a24420edaf5d836d6aae508a155..4a39d364493cf66bf64c161d46c2bc3fd089978f 100644 (file)
@@ -343,12 +343,17 @@ struct rcu_data {
 #define RCU_FORCE_QS           3       /* Need to force quiescent state. */
 #define RCU_SIGNAL_INIT                RCU_SAVE_DYNTICK
 
-#define RCU_JIFFIES_TILL_FORCE_QS       3      /* for rsp->jiffies_force_qs */
+#define RCU_JIFFIES_TILL_FORCE_QS (1 + (HZ > 250) + (HZ > 500))
+                                       /* For jiffies_till_first_fqs and */
+                                       /*  and jiffies_till_next_fqs. */
 
-#define RCU_STALL_RAT_DELAY            2       /* Allow other CPUs time */
-                                               /*  to take at least one */
-                                               /*  scheduling clock irq */
-                                               /*  before ratting on them. */
+#define RCU_JIFFIES_FQS_DIV    256     /* Very large systems need more */
+                                       /*  delay between bouts of */
+                                       /*  quiescent-state forcing. */
+
+#define RCU_STALL_RAT_DELAY    2       /* Allow other CPUs time to take */
+                                       /*  at least one scheduling clock */
+                                       /*  irq before ratting on them. */
 
 #define rcu_wait(cond)                                                 \
 do {                                                                   \
index 3db5a375d8dd52a93f64b48a5d0d7cad5a59559a..63098a59216e5957c27b5f20d57ca58591e46426 100644 (file)
@@ -53,38 +53,37 @@ static char __initdata nocb_buf[NR_CPUS * 5];
 static void __init rcu_bootup_announce_oddness(void)
 {
 #ifdef CONFIG_RCU_TRACE
-       printk(KERN_INFO "\tRCU debugfs-based tracing is enabled.\n");
+       pr_info("\tRCU debugfs-based tracing is enabled.\n");
 #endif
 #if (defined(CONFIG_64BIT) && CONFIG_RCU_FANOUT != 64) || (!defined(CONFIG_64BIT) && CONFIG_RCU_FANOUT != 32)
-       printk(KERN_INFO "\tCONFIG_RCU_FANOUT set to non-default value of %d\n",
+       pr_info("\tCONFIG_RCU_FANOUT set to non-default value of %d\n",
               CONFIG_RCU_FANOUT);
 #endif
 #ifdef CONFIG_RCU_FANOUT_EXACT
-       printk(KERN_INFO "\tHierarchical RCU autobalancing is disabled.\n");
+       pr_info("\tHierarchical RCU autobalancing is disabled.\n");
 #endif
 #ifdef CONFIG_RCU_FAST_NO_HZ
-       printk(KERN_INFO
-              "\tRCU dyntick-idle grace-period acceleration is enabled.\n");
+       pr_info("\tRCU dyntick-idle grace-period acceleration is enabled.\n");
 #endif
 #ifdef CONFIG_PROVE_RCU
-       printk(KERN_INFO "\tRCU lockdep checking is enabled.\n");
+       pr_info("\tRCU lockdep checking is enabled.\n");
 #endif
 #ifdef CONFIG_RCU_TORTURE_TEST_RUNNABLE
-       printk(KERN_INFO "\tRCU torture testing starts during boot.\n");
+       pr_info("\tRCU torture testing starts during boot.\n");
 #endif
 #if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE)
-       printk(KERN_INFO "\tDump stacks of tasks blocking RCU-preempt GP.\n");
+       pr_info("\tDump stacks of tasks blocking RCU-preempt GP.\n");
 #endif
 #if defined(CONFIG_RCU_CPU_STALL_INFO)
-       printk(KERN_INFO "\tAdditional per-CPU info printed with stalls.\n");
+       pr_info("\tAdditional per-CPU info printed with stalls.\n");
 #endif
 #if NUM_RCU_LVL_4 != 0
-       printk(KERN_INFO "\tFour-level hierarchy is enabled.\n");
+       pr_info("\tFour-level hierarchy is enabled.\n");
 #endif
        if (rcu_fanout_leaf != CONFIG_RCU_FANOUT_LEAF)
-               printk(KERN_INFO "\tExperimental boot-time adjustment of leaf fanout to %d.\n", rcu_fanout_leaf);
+               pr_info("\tBoot-time adjustment of leaf fanout to %d.\n", rcu_fanout_leaf);
        if (nr_cpu_ids != NR_CPUS)
-               printk(KERN_INFO "\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids);
+               pr_info("\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids);
 #ifdef CONFIG_RCU_NOCB_CPU
 #ifndef CONFIG_RCU_NOCB_CPU_NONE
        if (!have_rcu_nocb_mask) {
@@ -92,19 +91,19 @@ static void __init rcu_bootup_announce_oddness(void)
                have_rcu_nocb_mask = true;
        }
 #ifdef CONFIG_RCU_NOCB_CPU_ZERO
-       pr_info("\tExperimental no-CBs CPU 0\n");
+       pr_info("\tOffload RCU callbacks from CPU 0\n");
        cpumask_set_cpu(0, rcu_nocb_mask);
 #endif /* #ifdef CONFIG_RCU_NOCB_CPU_ZERO */
 #ifdef CONFIG_RCU_NOCB_CPU_ALL
-       pr_info("\tExperimental no-CBs for all CPUs\n");
+       pr_info("\tOffload RCU callbacks from all CPUs\n");
        cpumask_setall(rcu_nocb_mask);
 #endif /* #ifdef CONFIG_RCU_NOCB_CPU_ALL */
 #endif /* #ifndef CONFIG_RCU_NOCB_CPU_NONE */
        if (have_rcu_nocb_mask) {
                cpulist_scnprintf(nocb_buf, sizeof(nocb_buf), rcu_nocb_mask);
-               pr_info("\tExperimental no-CBs CPUs: %s.\n", nocb_buf);
+               pr_info("\tOffload RCU callbacks from CPUs: %s.\n", nocb_buf);
                if (rcu_nocb_poll)
-                       pr_info("\tExperimental polled no-CBs CPUs.\n");
+                       pr_info("\tPoll for callbacks from no-CBs CPUs.\n");
        }
 #endif /* #ifdef CONFIG_RCU_NOCB_CPU */
 }
@@ -123,7 +122,7 @@ static int rcu_preempted_readers_exp(struct rcu_node *rnp);
  */
 static void __init rcu_bootup_announce(void)
 {
-       printk(KERN_INFO "Preemptible hierarchical RCU implementation.\n");
+       pr_info("Preemptible hierarchical RCU implementation.\n");
        rcu_bootup_announce_oddness();
 }
 
@@ -490,13 +489,13 @@ static void rcu_print_detail_task_stall(struct rcu_state *rsp)
 
 static void rcu_print_task_stall_begin(struct rcu_node *rnp)
 {
-       printk(KERN_ERR "\tTasks blocked on level-%d rcu_node (CPUs %d-%d):",
+       pr_err("\tTasks blocked on level-%d rcu_node (CPUs %d-%d):",
               rnp->level, rnp->grplo, rnp->grphi);
 }
 
 static void rcu_print_task_stall_end(void)
 {
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
 }
 
 #else /* #ifdef CONFIG_RCU_CPU_STALL_INFO */
@@ -526,7 +525,7 @@ static int rcu_print_task_stall(struct rcu_node *rnp)
        t = list_entry(rnp->gp_tasks,
                       struct task_struct, rcu_node_entry);
        list_for_each_entry_continue(t, &rnp->blkd_tasks, rcu_node_entry) {
-               printk(KERN_CONT " P%d", t->pid);
+               pr_cont(" P%d", t->pid);
                ndetected++;
        }
        rcu_print_task_stall_end();
@@ -933,6 +932,24 @@ static void __init __rcu_init_preempt(void)
        rcu_init_one(&rcu_preempt_state, &rcu_preempt_data);
 }
 
+/*
+ * Check for a task exiting while in a preemptible-RCU read-side
+ * critical section, clean up if so.  No need to issue warnings,
+ * as debug_check_no_locks_held() already does this if lockdep
+ * is enabled.
+ */
+void exit_rcu(void)
+{
+       struct task_struct *t = current;
+
+       if (likely(list_empty(&current->rcu_node_entry)))
+               return;
+       t->rcu_read_lock_nesting = 1;
+       barrier();
+       t->rcu_read_unlock_special = RCU_READ_UNLOCK_BLOCKED;
+       __rcu_read_unlock();
+}
+
 #else /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 
 static struct rcu_state *rcu_state = &rcu_sched_state;
@@ -942,7 +959,7 @@ static struct rcu_state *rcu_state = &rcu_sched_state;
  */
 static void __init rcu_bootup_announce(void)
 {
-       printk(KERN_INFO "Hierarchical RCU implementation.\n");
+       pr_info("Hierarchical RCU implementation.\n");
        rcu_bootup_announce_oddness();
 }
 
@@ -1101,6 +1118,14 @@ static void __init __rcu_init_preempt(void)
 {
 }
 
+/*
+ * Because preemptible RCU does not exist, tasks cannot possibly exit
+ * while in preemptible RCU read-side critical sections.
+ */
+void exit_rcu(void)
+{
+}
+
 #endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */
 
 #ifdef CONFIG_RCU_BOOST
@@ -1629,7 +1654,7 @@ static bool rcu_try_advance_all_cbs(void)
                 */
                if (rdp->completed != rnp->completed &&
                    rdp->nxttail[RCU_DONE_TAIL] != rdp->nxttail[RCU_NEXT_TAIL])
-                       rcu_process_gp_end(rsp, rdp);
+                       note_gp_changes(rsp, rdp);
 
                if (cpu_has_callbacks_ready_to_invoke(rdp))
                        cbs_ready = true;
@@ -1883,7 +1908,7 @@ static void print_cpu_stall_fast_no_hz(char *cp, int cpu)
 /* Initiate the stall-info list. */
 static void print_cpu_stall_info_begin(void)
 {
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
 }
 
 /*
@@ -1914,7 +1939,7 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)
                ticks_value = rsp->gpnum - rdp->gpnum;
        }
        print_cpu_stall_fast_no_hz(fast_no_hz, cpu);
-       printk(KERN_ERR "\t%d: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u %s\n",
+       pr_err("\t%d: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u %s\n",
               cpu, ticks_value, ticks_title,
               atomic_read(&rdtp->dynticks) & 0xfff,
               rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting,
@@ -1925,7 +1950,7 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)
 /* Terminate the stall-info list. */
 static void print_cpu_stall_info_end(void)
 {
-       printk(KERN_ERR "\t");
+       pr_err("\t");
 }
 
 /* Zero ->ticks_this_gp for all flavors of RCU. */
@@ -1948,17 +1973,17 @@ static void increment_cpu_stall_ticks(void)
 
 static void print_cpu_stall_info_begin(void)
 {
-       printk(KERN_CONT " {");
+       pr_cont(" {");
 }
 
 static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)
 {
-       printk(KERN_CONT " %d", cpu);
+       pr_cont(" %d", cpu);
 }
 
 static void print_cpu_stall_info_end(void)
 {
-       printk(KERN_CONT "} ");
+       pr_cont("} ");
 }
 
 static void zero_cpu_stall_ticks(struct rcu_data *rdp)
index d7386986e10e31edda59fcb15c4b83b236d52993..3f285dce9347191537b8d13f8db53f869d4744ad 100644 (file)
@@ -409,6 +409,7 @@ int __weak page_is_ram(unsigned long pfn)
 {
        return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1;
 }
+EXPORT_SYMBOL_GPL(page_is_ram);
 
 void __weak arch_remove_reservations(struct resource *avail)
 {
@@ -448,7 +449,6 @@ static int __find_resource(struct resource *root, struct resource *old,
        struct resource *this = root->child;
        struct resource tmp = *new, avail, alloc;
 
-       tmp.flags = new->flags;
        tmp.start = root->start;
        /*
         * Skip past an allocated resource that starts at 0, since the assignment
index 1e09308bf2a1e5f46c3f68d02bc4bcb346b42ec5..0dd6aec1cb6ad8bb41a44ba74f770ca4439fc022 100644 (file)
@@ -145,6 +145,19 @@ int max_lock_depth = 1024;
 /*
  * Adjust the priority chain. Also used for deadlock detection.
  * Decreases task's usage by one - may thus free the task.
+ *
+ * @task: the task owning the mutex (owner) for which a chain walk is probably
+ *       needed
+ * @deadlock_detect: do we have to carry out deadlock detection?
+ * @orig_lock: the mutex (can be NULL if we are walking the chain to recheck
+ *            things for a task that has just got its priority adjusted, and
+ *            is waiting on a mutex)
+ * @orig_waiter: rt_mutex_waiter struct for the task that has just donated
+ *              its priority to the mutex owner (can be NULL in the case
+ *              depicted above or if the top waiter is gone away and we are
+ *              actually deboosting the owner)
+ * @top_task: the current top waiter
+ *
  * Returns 0 or -EDEADLK.
  */
 static int rt_mutex_adjust_prio_chain(struct task_struct *task,
index deaf90e4a1dece3fd6b5092f17f8c8564e477d55..54adcf35f49526ef29bde1bfa79fbc97d37738c5 100644 (file)
@@ -11,7 +11,7 @@ ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer
 endif
 
-obj-y += core.o clock.o cputime.o idle_task.o fair.o rt.o stop_task.o
+obj-y += core.o proc.o clock.o cputime.o idle_task.o fair.o rt.o stop_task.o
 obj-$(CONFIG_SMP) += cpupri.o
 obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
 obj-$(CONFIG_SCHEDSTATS) += stats.o
index 64de5f8b0c9ed654ec475c2cae33fe539a1d43ca..4a073539c58e69992ed2133a73444ceffc9cd3fa 100644 (file)
@@ -77,8 +77,6 @@ static inline struct autogroup *autogroup_create(void)
        if (IS_ERR(tg))
                goto out_free;
 
-       sched_online_group(tg, &root_task_group);
-
        kref_init(&ag->kref);
        init_rwsem(&ag->lock);
        ag->id = atomic_inc_return(&autogroup_seq_nr);
@@ -98,6 +96,7 @@ static inline struct autogroup *autogroup_create(void)
 #endif
        tg->autogroup = ag;
 
+       sched_online_group(tg, &root_task_group);
        return ag;
 
 out_free:
index e8b335016c526594cd910a030c962099907d8518..9b1f2e533b95cf2532ffcadfc62476b18d9e27f5 100644 (file)
@@ -679,7 +679,7 @@ void sched_avg_update(struct rq *rq)
 {
        s64 period = sched_avg_period();
 
-       while ((s64)(rq->clock - rq->age_stamp) > period) {
+       while ((s64)(rq_clock(rq) - rq->age_stamp) > period) {
                /*
                 * Inline assembly required to prevent the compiler
                 * optimising this loop into a divmod call.
@@ -1340,7 +1340,7 @@ ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
                p->sched_class->task_woken(rq, p);
 
        if (rq->idle_stamp) {
-               u64 delta = rq->clock - rq->idle_stamp;
+               u64 delta = rq_clock(rq) - rq->idle_stamp;
                u64 max = 2*sysctl_sched_migration_cost;
 
                if (delta > max)
@@ -1377,6 +1377,8 @@ static int ttwu_remote(struct task_struct *p, int wake_flags)
 
        rq = __task_rq_lock(p);
        if (p->on_rq) {
+               /* check_preempt_curr() may use rq clock */
+               update_rq_clock(rq);
                ttwu_do_wakeup(rq, p, wake_flags);
                ret = 1;
        }
@@ -1609,15 +1611,6 @@ static void __sched_fork(struct task_struct *p)
        p->se.vruntime                  = 0;
        INIT_LIST_HEAD(&p->se.group_node);
 
-/*
- * Load-tracking only depends on SMP, FAIR_GROUP_SCHED dependency below may be
- * removed when useful for applications beyond shares distribution (e.g.
- * load-balance).
- */
-#if defined(CONFIG_SMP) && defined(CONFIG_FAIR_GROUP_SCHED)
-       p->se.avg.runnable_avg_period = 0;
-       p->se.avg.runnable_avg_sum = 0;
-#endif
 #ifdef CONFIG_SCHEDSTATS
        memset(&p->se.statistics, 0, sizeof(p->se.statistics));
 #endif
@@ -1761,6 +1754,8 @@ void wake_up_new_task(struct task_struct *p)
        set_task_cpu(p, select_task_rq(p, SD_BALANCE_FORK, 0));
 #endif
 
+       /* Initialize new task's runnable average */
+       init_task_runnable_average(p);
        rq = __task_rq_lock(p);
        activate_task(rq, p, 0);
        p->on_rq = 1;
@@ -2069,575 +2064,6 @@ unsigned long nr_iowait_cpu(int cpu)
        return atomic_read(&this->nr_iowait);
 }
 
-unsigned long this_cpu_load(void)
-{
-       struct rq *this = this_rq();
-       return this->cpu_load[0];
-}
-
-
-/*
- * Global load-average calculations
- *
- * We take a distributed and async approach to calculating the global load-avg
- * in order to minimize overhead.
- *
- * The global load average is an exponentially decaying average of nr_running +
- * nr_uninterruptible.
- *
- * Once every LOAD_FREQ:
- *
- *   nr_active = 0;
- *   for_each_possible_cpu(cpu)
- *     nr_active += cpu_of(cpu)->nr_running + cpu_of(cpu)->nr_uninterruptible;
- *
- *   avenrun[n] = avenrun[0] * exp_n + nr_active * (1 - exp_n)
- *
- * Due to a number of reasons the above turns in the mess below:
- *
- *  - for_each_possible_cpu() is prohibitively expensive on machines with
- *    serious number of cpus, therefore we need to take a distributed approach
- *    to calculating nr_active.
- *
- *        \Sum_i x_i(t) = \Sum_i x_i(t) - x_i(t_0) | x_i(t_0) := 0
- *                      = \Sum_i { \Sum_j=1 x_i(t_j) - x_i(t_j-1) }
- *
- *    So assuming nr_active := 0 when we start out -- true per definition, we
- *    can simply take per-cpu deltas and fold those into a global accumulate
- *    to obtain the same result. See calc_load_fold_active().
- *
- *    Furthermore, in order to avoid synchronizing all per-cpu delta folding
- *    across the machine, we assume 10 ticks is sufficient time for every
- *    cpu to have completed this task.
- *
- *    This places an upper-bound on the IRQ-off latency of the machine. Then
- *    again, being late doesn't loose the delta, just wrecks the sample.
- *
- *  - cpu_rq()->nr_uninterruptible isn't accurately tracked per-cpu because
- *    this would add another cross-cpu cacheline miss and atomic operation
- *    to the wakeup path. Instead we increment on whatever cpu the task ran
- *    when it went into uninterruptible state and decrement on whatever cpu
- *    did the wakeup. This means that only the sum of nr_uninterruptible over
- *    all cpus yields the correct result.
- *
- *  This covers the NO_HZ=n code, for extra head-aches, see the comment below.
- */
-
-/* Variables and functions for calc_load */
-static atomic_long_t calc_load_tasks;
-static unsigned long calc_load_update;
-unsigned long avenrun[3];
-EXPORT_SYMBOL(avenrun); /* should be removed */
-
-/**
- * get_avenrun - get the load average array
- * @loads:     pointer to dest load array
- * @offset:    offset to add
- * @shift:     shift count to shift the result left
- *
- * These values are estimates at best, so no need for locking.
- */
-void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
-{
-       loads[0] = (avenrun[0] + offset) << shift;
-       loads[1] = (avenrun[1] + offset) << shift;
-       loads[2] = (avenrun[2] + offset) << shift;
-}
-
-static long calc_load_fold_active(struct rq *this_rq)
-{
-       long nr_active, delta = 0;
-
-       nr_active = this_rq->nr_running;
-       nr_active += (long) this_rq->nr_uninterruptible;
-
-       if (nr_active != this_rq->calc_load_active) {
-               delta = nr_active - this_rq->calc_load_active;
-               this_rq->calc_load_active = nr_active;
-       }
-
-       return delta;
-}
-
-/*
- * a1 = a0 * e + a * (1 - e)
- */
-static unsigned long
-calc_load(unsigned long load, unsigned long exp, unsigned long active)
-{
-       load *= exp;
-       load += active * (FIXED_1 - exp);
-       load += 1UL << (FSHIFT - 1);
-       return load >> FSHIFT;
-}
-
-#ifdef CONFIG_NO_HZ_COMMON
-/*
- * Handle NO_HZ for the global load-average.
- *
- * Since the above described distributed algorithm to compute the global
- * load-average relies on per-cpu sampling from the tick, it is affected by
- * NO_HZ.
- *
- * The basic idea is to fold the nr_active delta into a global idle-delta upon
- * entering NO_HZ state such that we can include this as an 'extra' cpu delta
- * when we read the global state.
- *
- * Obviously reality has to ruin such a delightfully simple scheme:
- *
- *  - When we go NO_HZ idle during the window, we can negate our sample
- *    contribution, causing under-accounting.
- *
- *    We avoid this by keeping two idle-delta counters and flipping them
- *    when the window starts, thus separating old and new NO_HZ load.
- *
- *    The only trick is the slight shift in index flip for read vs write.
- *
- *        0s            5s            10s           15s
- *          +10           +10           +10           +10
- *        |-|-----------|-|-----------|-|-----------|-|
- *    r:0 0 1           1 0           0 1           1 0
- *    w:0 1 1           0 0           1 1           0 0
- *
- *    This ensures we'll fold the old idle contribution in this window while
- *    accumlating the new one.
- *
- *  - When we wake up from NO_HZ idle during the window, we push up our
- *    contribution, since we effectively move our sample point to a known
- *    busy state.
- *
- *    This is solved by pushing the window forward, and thus skipping the
- *    sample, for this cpu (effectively using the idle-delta for this cpu which
- *    was in effect at the time the window opened). This also solves the issue
- *    of having to deal with a cpu having been in NOHZ idle for multiple
- *    LOAD_FREQ intervals.
- *
- * When making the ILB scale, we should try to pull this in as well.
- */
-static atomic_long_t calc_load_idle[2];
-static int calc_load_idx;
-
-static inline int calc_load_write_idx(void)
-{
-       int idx = calc_load_idx;
-
-       /*
-        * See calc_global_nohz(), if we observe the new index, we also
-        * need to observe the new update time.
-        */
-       smp_rmb();
-
-       /*
-        * If the folding window started, make sure we start writing in the
-        * next idle-delta.
-        */
-       if (!time_before(jiffies, calc_load_update))
-               idx++;
-
-       return idx & 1;
-}
-
-static inline int calc_load_read_idx(void)
-{
-       return calc_load_idx & 1;
-}
-
-void calc_load_enter_idle(void)
-{
-       struct rq *this_rq = this_rq();
-       long delta;
-
-       /*
-        * We're going into NOHZ mode, if there's any pending delta, fold it
-        * into the pending idle delta.
-        */
-       delta = calc_load_fold_active(this_rq);
-       if (delta) {
-               int idx = calc_load_write_idx();
-               atomic_long_add(delta, &calc_load_idle[idx]);
-       }
-}
-
-void calc_load_exit_idle(void)
-{
-       struct rq *this_rq = this_rq();
-
-       /*
-        * If we're still before the sample window, we're done.
-        */
-       if (time_before(jiffies, this_rq->calc_load_update))
-               return;
-
-       /*
-        * We woke inside or after the sample window, this means we're already
-        * accounted through the nohz accounting, so skip the entire deal and
-        * sync up for the next window.
-        */
-       this_rq->calc_load_update = calc_load_update;
-       if (time_before(jiffies, this_rq->calc_load_update + 10))
-               this_rq->calc_load_update += LOAD_FREQ;
-}
-
-static long calc_load_fold_idle(void)
-{
-       int idx = calc_load_read_idx();
-       long delta = 0;
-
-       if (atomic_long_read(&calc_load_idle[idx]))
-               delta = atomic_long_xchg(&calc_load_idle[idx], 0);
-
-       return delta;
-}
-
-/**
- * fixed_power_int - compute: x^n, in O(log n) time
- *
- * @x:         base of the power
- * @frac_bits: fractional bits of @x
- * @n:         power to raise @x to.
- *
- * By exploiting the relation between the definition of the natural power
- * function: x^n := x*x*...*x (x multiplied by itself for n times), and
- * the binary encoding of numbers used by computers: n := \Sum n_i * 2^i,
- * (where: n_i \elem {0, 1}, the binary vector representing n),
- * we find: x^n := x^(\Sum n_i * 2^i) := \Prod x^(n_i * 2^i), which is
- * of course trivially computable in O(log_2 n), the length of our binary
- * vector.
- */
-static unsigned long
-fixed_power_int(unsigned long x, unsigned int frac_bits, unsigned int n)
-{
-       unsigned long result = 1UL << frac_bits;
-
-       if (n) for (;;) {
-               if (n & 1) {
-                       result *= x;
-                       result += 1UL << (frac_bits - 1);
-                       result >>= frac_bits;
-               }
-               n >>= 1;
-               if (!n)
-                       break;
-               x *= x;
-               x += 1UL << (frac_bits - 1);
-               x >>= frac_bits;
-       }
-
-       return result;
-}
-
-/*
- * a1 = a0 * e + a * (1 - e)
- *
- * a2 = a1 * e + a * (1 - e)
- *    = (a0 * e + a * (1 - e)) * e + a * (1 - e)
- *    = a0 * e^2 + a * (1 - e) * (1 + e)
- *
- * a3 = a2 * e + a * (1 - e)
- *    = (a0 * e^2 + a * (1 - e) * (1 + e)) * e + a * (1 - e)
- *    = a0 * e^3 + a * (1 - e) * (1 + e + e^2)
- *
- *  ...
- *
- * an = a0 * e^n + a * (1 - e) * (1 + e + ... + e^n-1) [1]
- *    = a0 * e^n + a * (1 - e) * (1 - e^n)/(1 - e)
- *    = a0 * e^n + a * (1 - e^n)
- *
- * [1] application of the geometric series:
- *
- *              n         1 - x^(n+1)
- *     S_n := \Sum x^i = -------------
- *             i=0          1 - x
- */
-static unsigned long
-calc_load_n(unsigned long load, unsigned long exp,
-           unsigned long active, unsigned int n)
-{
-
-       return calc_load(load, fixed_power_int(exp, FSHIFT, n), active);
-}
-
-/*
- * NO_HZ can leave us missing all per-cpu ticks calling
- * calc_load_account_active(), but since an idle CPU folds its delta into
- * calc_load_tasks_idle per calc_load_account_idle(), all we need to do is fold
- * in the pending idle delta if our idle period crossed a load cycle boundary.
- *
- * Once we've updated the global active value, we need to apply the exponential
- * weights adjusted to the number of cycles missed.
- */
-static void calc_global_nohz(void)
-{
-       long delta, active, n;
-
-       if (!time_before(jiffies, calc_load_update + 10)) {
-               /*
-                * Catch-up, fold however many we are behind still
-                */
-               delta = jiffies - calc_load_update - 10;
-               n = 1 + (delta / LOAD_FREQ);
-
-               active = atomic_long_read(&calc_load_tasks);
-               active = active > 0 ? active * FIXED_1 : 0;
-
-               avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
-               avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
-               avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
-
-               calc_load_update += n * LOAD_FREQ;
-       }
-
-       /*
-        * Flip the idle index...
-        *
-        * Make sure we first write the new time then flip the index, so that
-        * calc_load_write_idx() will see the new time when it reads the new
-        * index, this avoids a double flip messing things up.
-        */
-       smp_wmb();
-       calc_load_idx++;
-}
-#else /* !CONFIG_NO_HZ_COMMON */
-
-static inline long calc_load_fold_idle(void) { return 0; }
-static inline void calc_global_nohz(void) { }
-
-#endif /* CONFIG_NO_HZ_COMMON */
-
-/*
- * calc_load - update the avenrun load estimates 10 ticks after the
- * CPUs have updated calc_load_tasks.
- */
-void calc_global_load(unsigned long ticks)
-{
-       long active, delta;
-
-       if (time_before(jiffies, calc_load_update + 10))
-               return;
-
-       /*
-        * Fold the 'old' idle-delta to include all NO_HZ cpus.
-        */
-       delta = calc_load_fold_idle();
-       if (delta)
-               atomic_long_add(delta, &calc_load_tasks);
-
-       active = atomic_long_read(&calc_load_tasks);
-       active = active > 0 ? active * FIXED_1 : 0;
-
-       avenrun[0] = calc_load(avenrun[0], EXP_1, active);
-       avenrun[1] = calc_load(avenrun[1], EXP_5, active);
-       avenrun[2] = calc_load(avenrun[2], EXP_15, active);
-
-       calc_load_update += LOAD_FREQ;
-
-       /*
-        * In case we idled for multiple LOAD_FREQ intervals, catch up in bulk.
-        */
-       calc_global_nohz();
-}
-
-/*
- * Called from update_cpu_load() to periodically update this CPU's
- * active count.
- */
-static void calc_load_account_active(struct rq *this_rq)
-{
-       long delta;
-
-       if (time_before(jiffies, this_rq->calc_load_update))
-               return;
-
-       delta  = calc_load_fold_active(this_rq);
-       if (delta)
-               atomic_long_add(delta, &calc_load_tasks);
-
-       this_rq->calc_load_update += LOAD_FREQ;
-}
-
-/*
- * End of global load-average stuff
- */
-
-/*
- * 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
- *
- * 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
- *
- * 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
- *
- * 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} };
-
-/*
- * Update cpu_load for any missed ticks, due to tickless idle. The backlog
- * would be when CPU is idle and so we just decay the old load without
- * adding any new load.
- */
-static unsigned long
-decay_load_missed(unsigned long load, unsigned long missed_updates, int idx)
-{
-       int j = 0;
-
-       if (!missed_updates)
-               return load;
-
-       if (missed_updates >= degrade_zero_ticks[idx])
-               return 0;
-
-       if (idx == 1)
-               return load >> missed_updates;
-
-       while (missed_updates) {
-               if (missed_updates % 2)
-                       load = (load * degrade_factor[idx][j]) >> DEGRADE_SHIFT;
-
-               missed_updates >>= 1;
-               j++;
-       }
-       return load;
-}
-
-/*
- * 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.
- */
-static void __update_cpu_load(struct rq *this_rq, unsigned long this_load,
-                             unsigned long pending_updates)
-{
-       int i, scale;
-
-       this_rq->nr_load_updates++;
-
-       /* Update our load: */
-       this_rq->cpu_load[0] = this_load; /* Fasttrack for idx 0 */
-       for (i = 1, scale = 2; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
-               unsigned long old_load, new_load;
-
-               /* scale is effectively 1 << i now, and >> i divides by scale */
-
-               old_load = this_rq->cpu_load[i];
-               old_load = decay_load_missed(old_load, pending_updates - 1, i);
-               new_load = this_load;
-               /*
-                * Round up the averaging division if load is increasing. This
-                * prevents us from getting stuck on 9 if the load is 10, for
-                * example.
-                */
-               if (new_load > old_load)
-                       new_load += scale - 1;
-
-               this_rq->cpu_load[i] = (old_load * (scale - 1) + new_load) >> i;
-       }
-
-       sched_avg_update(this_rq);
-}
-
-#ifdef CONFIG_NO_HZ_COMMON
-/*
- * There is no sane way to deal with nohz on smp when using jiffies because the
- * cpu doing the jiffies update might drift wrt the cpu doing the jiffy reading
- * causing off-by-one errors in observed deltas; {0,2} instead of {1,1}.
- *
- * Therefore we cannot use the delta approach from the regular tick since that
- * would seriously skew the load calculation. However we'll make do for those
- * updates happening while idle (nohz_idle_balance) or coming out of idle
- * (tick_nohz_idle_exit).
- *
- * This means we might still be one tick off for nohz periods.
- */
-
-/*
- * Called from nohz_idle_balance() to update the load ratings before doing the
- * idle balance.
- */
-void update_idle_cpu_load(struct rq *this_rq)
-{
-       unsigned long curr_jiffies = ACCESS_ONCE(jiffies);
-       unsigned long load = this_rq->load.weight;
-       unsigned long pending_updates;
-
-       /*
-        * bail if there's load or we're actually up-to-date.
-        */
-       if (load || curr_jiffies == this_rq->last_load_update_tick)
-               return;
-
-       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);
-}
-
-/*
- * Called from tick_nohz_idle_exit() -- try and fix up the ticks we missed.
- */
-void update_cpu_load_nohz(void)
-{
-       struct rq *this_rq = this_rq();
-       unsigned long curr_jiffies = ACCESS_ONCE(jiffies);
-       unsigned long pending_updates;
-
-       if (curr_jiffies == this_rq->last_load_update_tick)
-               return;
-
-       raw_spin_lock(&this_rq->lock);
-       pending_updates = curr_jiffies - this_rq->last_load_update_tick;
-       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.
-                */
-               __update_cpu_load(this_rq, 0, pending_updates);
-       }
-       raw_spin_unlock(&this_rq->lock);
-}
-#endif /* CONFIG_NO_HZ_COMMON */
-
-/*
- * Called from scheduler_tick()
- */
-static 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, this_rq->load.weight, 1);
-
-       calc_load_account_active(this_rq);
-}
-
 #ifdef CONFIG_SMP
 
 /*
@@ -2686,7 +2112,7 @@ static u64 do_task_delta_exec(struct task_struct *p, struct rq *rq)
 
        if (task_current(rq, p)) {
                update_rq_clock(rq);
-               ns = rq->clock_task - p->se.exec_start;
+               ns = rq_clock_task(rq) - p->se.exec_start;
                if ((s64)ns < 0)
                        ns = 0;
        }
@@ -2739,8 +2165,8 @@ void scheduler_tick(void)
 
        raw_spin_lock(&rq->lock);
        update_rq_clock(rq);
-       update_cpu_load_active(rq);
        curr->sched_class->task_tick(rq, curr, 0);
+       update_cpu_load_active(rq);
        raw_spin_unlock(&rq->lock);
 
        perf_event_task_tick();
@@ -4960,6 +4386,13 @@ static void migrate_tasks(unsigned int dead_cpu)
         */
        rq->stop = NULL;
 
+       /*
+        * put_prev_task() and pick_next_task() sched
+        * class method both need to have an up-to-date
+        * value of rq->clock[_task]
+        */
+       update_rq_clock(rq);
+
        for ( ; ; ) {
                /*
                 * There's this thread running, bail when that's the only
@@ -5093,7 +4526,7 @@ sd_alloc_ctl_domain_table(struct sched_domain *sd)
        return table;
 }
 
-static ctl_table *sd_alloc_ctl_cpu_table(int cpu)
+static struct ctl_table *sd_alloc_ctl_cpu_table(int cpu)
 {
        struct ctl_table *entry, *table;
        struct sched_domain *sd;
@@ -5907,7 +5340,7 @@ build_sched_groups(struct sched_domain *sd, int cpu)
        get_group(cpu, sdd, &sd->groups);
        atomic_inc(&sd->groups->ref);
 
-       if (cpu != cpumask_first(sched_domain_span(sd)))
+       if (cpu != cpumask_first(span))
                return 0;
 
        lockdep_assert_held(&sched_domains_mutex);
@@ -5917,12 +5350,12 @@ build_sched_groups(struct sched_domain *sd, int cpu)
 
        for_each_cpu(i, span) {
                struct sched_group *sg;
-               int group = get_group(i, sdd, &sg);
-               int j;
+               int group, j;
 
                if (cpumask_test_cpu(i, covered))
                        continue;
 
+               group = get_group(i, sdd, &sg);
                cpumask_clear(sched_group_cpus(sg));
                sg->sgp->power = 0;
                cpumask_setall(sched_group_mask(sg));
@@ -5960,7 +5393,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd)
 {
        struct sched_group *sg = sd->groups;
 
-       WARN_ON(!sd || !sg);
+       WARN_ON(!sg);
 
        do {
                sg->group_weight = cpumask_weight(sched_group_cpus(sg));
@@ -6125,6 +5558,9 @@ static struct sched_domain_topology_level default_topology[] = {
 
 static struct sched_domain_topology_level *sched_domain_topology = default_topology;
 
+#define for_each_sd_topology(tl)                       \
+       for (tl = sched_domain_topology; tl->init; tl++)
+
 #ifdef CONFIG_NUMA
 
 static int sched_domains_numa_levels;
@@ -6422,7 +5858,7 @@ static int __sdt_alloc(const struct cpumask *cpu_map)
        struct sched_domain_topology_level *tl;
        int j;
 
-       for (tl = sched_domain_topology; tl->init; tl++) {
+       for_each_sd_topology(tl) {
                struct sd_data *sdd = &tl->data;
 
                sdd->sd = alloc_percpu(struct sched_domain *);
@@ -6475,7 +5911,7 @@ static void __sdt_free(const struct cpumask *cpu_map)
        struct sched_domain_topology_level *tl;
        int j;
 
-       for (tl = sched_domain_topology; tl->init; tl++) {
+       for_each_sd_topology(tl) {
                struct sd_data *sdd = &tl->data;
 
                for_each_cpu(j, cpu_map) {
@@ -6503,9 +5939,8 @@ static void __sdt_free(const struct cpumask *cpu_map)
 }
 
 struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl,
-               struct s_data *d, const struct cpumask *cpu_map,
-               struct sched_domain_attr *attr, struct sched_domain *child,
-               int cpu)
+               const struct cpumask *cpu_map, struct sched_domain_attr *attr,
+               struct sched_domain *child, int cpu)
 {
        struct sched_domain *sd = tl->init(tl, cpu);
        if (!sd)
@@ -6516,8 +5951,8 @@ struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl,
                sd->level = child->level + 1;
                sched_domain_level_max = max(sched_domain_level_max, sd->level);
                child->parent = sd;
+               sd->child = child;
        }
-       sd->child = child;
        set_domain_attribute(sd, attr);
 
        return sd;
@@ -6530,7 +5965,7 @@ struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl,
 static int build_sched_domains(const struct cpumask *cpu_map,
                               struct sched_domain_attr *attr)
 {
-       enum s_alloc alloc_state = sa_none;
+       enum s_alloc alloc_state;
        struct sched_domain *sd;
        struct s_data d;
        int i, ret = -ENOMEM;
@@ -6544,18 +5979,15 @@ static int build_sched_domains(const struct cpumask *cpu_map,
                struct sched_domain_topology_level *tl;
 
                sd = NULL;
-               for (tl = sched_domain_topology; tl->init; tl++) {
-                       sd = build_sched_domain(tl, &d, cpu_map, attr, sd, i);
+               for_each_sd_topology(tl) {
+                       sd = build_sched_domain(tl, cpu_map, attr, sd, i);
+                       if (tl == sched_domain_topology)
+                               *per_cpu_ptr(d.sd, i) = sd;
                        if (tl->flags & SDTL_OVERLAP || sched_feat(FORCE_SD_OVERLAP))
                                sd->flags |= SD_OVERLAP;
                        if (cpumask_equal(cpu_map, sched_domain_span(sd)))
                                break;
                }
-
-               while (sd->child)
-                       sd = sd->child;
-
-               *per_cpu_ptr(d.sd, i) = sd;
        }
 
        /* Build the groups for the domains */
@@ -6867,9 +6299,6 @@ void __init sched_init_smp(void)
        hotcpu_notifier(cpuset_cpu_active, CPU_PRI_CPUSET_ACTIVE);
        hotcpu_notifier(cpuset_cpu_inactive, CPU_PRI_CPUSET_INACTIVE);
 
-       /* RT runtime code needs to handle some hotplug events */
-       hotcpu_notifier(update_runtime, 0);
-
        init_hrtick();
 
        /* Move init over to a non-isolated CPU */
index b5ccba22603b51a92c2aa1f0ef647a878dd4e2c3..a7959e05a9d56ff1f53ef43cb97f2b127c018d30 100644 (file)
@@ -515,9 +515,8 @@ static cputime_t scale_stime(u64 stime, u64 rtime, u64 total)
 
        for (;;) {
                /* Make sure "rtime" is the bigger of stime/rtime */
-               if (stime > rtime) {
-                       u64 tmp = rtime; rtime = stime; stime = tmp;
-               }
+               if (stime > rtime)
+                       swap(rtime, stime);
 
                /* Make sure 'total' fits in 32 bits */
                if (total >> 32)
index 75024a673520b9c5e0e506b1e0963d782cc84c5d..e076bddd4c66f4a007db513954c3f41240525fe2 100644 (file)
@@ -209,22 +209,24 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
                        cfs_rq->nr_spread_over);
        SEQ_printf(m, "  .%-30s: %d\n", "nr_running", cfs_rq->nr_running);
        SEQ_printf(m, "  .%-30s: %ld\n", "load", cfs_rq->load.weight);
-#ifdef CONFIG_FAIR_GROUP_SCHED
 #ifdef CONFIG_SMP
-       SEQ_printf(m, "  .%-30s: %lld\n", "runnable_load_avg",
+       SEQ_printf(m, "  .%-30s: %ld\n", "runnable_load_avg",
                        cfs_rq->runnable_load_avg);
-       SEQ_printf(m, "  .%-30s: %lld\n", "blocked_load_avg",
+       SEQ_printf(m, "  .%-30s: %ld\n", "blocked_load_avg",
                        cfs_rq->blocked_load_avg);
-       SEQ_printf(m, "  .%-30s: %lld\n", "tg_load_avg",
-                       (unsigned long long)atomic64_read(&cfs_rq->tg->load_avg));
-       SEQ_printf(m, "  .%-30s: %lld\n", "tg_load_contrib",
+#ifdef CONFIG_FAIR_GROUP_SCHED
+       SEQ_printf(m, "  .%-30s: %ld\n", "tg_load_contrib",
                        cfs_rq->tg_load_contrib);
        SEQ_printf(m, "  .%-30s: %d\n", "tg_runnable_contrib",
                        cfs_rq->tg_runnable_contrib);
+       SEQ_printf(m, "  .%-30s: %ld\n", "tg_load_avg",
+                       atomic_long_read(&cfs_rq->tg->load_avg));
        SEQ_printf(m, "  .%-30s: %d\n", "tg->runnable_avg",
                        atomic_read(&cfs_rq->tg->runnable_avg));
 #endif
+#endif
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
        print_cfs_group_stats(m, cpu, cfs_rq->tg);
 #endif
 }
@@ -493,15 +495,16 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
        SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid,
                                                get_nr_threads(p));
        SEQ_printf(m,
-               "---------------------------------------------------------\n");
+               "---------------------------------------------------------"
+               "----------\n");
 #define __P(F) \
-       SEQ_printf(m, "%-35s:%21Ld\n", #F, (long long)F)
+       SEQ_printf(m, "%-45s:%21Ld\n", #F, (long long)F)
 #define P(F) \
-       SEQ_printf(m, "%-35s:%21Ld\n", #F, (long long)p->F)
+       SEQ_printf(m, "%-45s:%21Ld\n", #F, (long long)p->F)
 #define __PN(F) \
-       SEQ_printf(m, "%-35s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)F))
+       SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)F))
 #define PN(F) \
-       SEQ_printf(m, "%-35s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)p->F))
+       SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)p->F))
 
        PN(se.exec_start);
        PN(se.vruntime);
@@ -560,12 +563,18 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
        }
 #endif
        __P(nr_switches);
-       SEQ_printf(m, "%-35s:%21Ld\n",
+       SEQ_printf(m, "%-45s:%21Ld\n",
                   "nr_voluntary_switches", (long long)p->nvcsw);
-       SEQ_printf(m, "%-35s:%21Ld\n",
+       SEQ_printf(m, "%-45s:%21Ld\n",
                   "nr_involuntary_switches", (long long)p->nivcsw);
 
        P(se.load.weight);
+#ifdef CONFIG_SMP
+       P(se.avg.runnable_avg_sum);
+       P(se.avg.runnable_avg_period);
+       P(se.avg.load_avg_contrib);
+       P(se.avg.decay_count);
+#endif
        P(policy);
        P(prio);
 #undef PN
@@ -579,7 +588,7 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
 
                t0 = cpu_clock(this_cpu);
                t1 = cpu_clock(this_cpu);
-               SEQ_printf(m, "%-35s:%21Ld\n",
+               SEQ_printf(m, "%-45s:%21Ld\n",
                           "clock-delta", (long long)(t1-t0));
        }
 }
index c61a614465c8ebf13b5f71aabf23a78c9e8533a6..f77f9c5274494f22b15bade21163a685e80a14e1 100644 (file)
@@ -113,6 +113,24 @@ unsigned int __read_mostly sysctl_sched_shares_window = 10000000UL;
 unsigned int sysctl_sched_cfs_bandwidth_slice = 5000UL;
 #endif
 
+static inline void update_load_add(struct load_weight *lw, unsigned long inc)
+{
+       lw->weight += inc;
+       lw->inv_weight = 0;
+}
+
+static inline void update_load_sub(struct load_weight *lw, unsigned long dec)
+{
+       lw->weight -= dec;
+       lw->inv_weight = 0;
+}
+
+static inline void update_load_set(struct load_weight *lw, unsigned long w)
+{
+       lw->weight = w;
+       lw->inv_weight = 0;
+}
+
 /*
  * Increase the granularity value when there are more CPUs,
  * because with more CPUs the 'effective latency' as visible
@@ -662,6 +680,26 @@ static u64 sched_vslice(struct cfs_rq *cfs_rq, struct sched_entity *se)
        return calc_delta_fair(sched_slice(cfs_rq, se), se);
 }
 
+#ifdef CONFIG_SMP
+static inline void __update_task_entity_contrib(struct sched_entity *se);
+
+/* Give new task start runnable values to heavy its load in infant time */
+void init_task_runnable_average(struct task_struct *p)
+{
+       u32 slice;
+
+       p->se.avg.decay_count = 0;
+       slice = sched_slice(task_cfs_rq(p), &p->se) >> 10;
+       p->se.avg.runnable_avg_sum = slice;
+       p->se.avg.runnable_avg_period = slice;
+       __update_task_entity_contrib(&p->se);
+}
+#else
+void init_task_runnable_average(struct task_struct *p)
+{
+}
+#endif
+
 /*
  * Update the current task's runtime statistics. Skip current tasks that
  * are not in our scheduling class.
@@ -686,7 +724,7 @@ __update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr,
 static void update_curr(struct cfs_rq *cfs_rq)
 {
        struct sched_entity *curr = cfs_rq->curr;
-       u64 now = rq_of(cfs_rq)->clock_task;
+       u64 now = rq_clock_task(rq_of(cfs_rq));
        unsigned long delta_exec;
 
        if (unlikely(!curr))
@@ -718,7 +756,7 @@ static void update_curr(struct cfs_rq *cfs_rq)
 static inline void
 update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       schedstat_set(se->statistics.wait_start, rq_of(cfs_rq)->clock);
+       schedstat_set(se->statistics.wait_start, rq_clock(rq_of(cfs_rq)));
 }
 
 /*
@@ -738,14 +776,14 @@ 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_of(cfs_rq)->clock - se->statistics.wait_start));
+                       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_of(cfs_rq)->clock - se->statistics.wait_start);
+                       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_of(cfs_rq)->clock - se->statistics.wait_start);
+                       rq_clock(rq_of(cfs_rq)) - se->statistics.wait_start);
        }
 #endif
        schedstat_set(se->statistics.wait_start, 0);
@@ -771,7 +809,7 @@ update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
        /*
         * We are starting a new run period:
         */
-       se->exec_start = rq_of(cfs_rq)->clock_task;
+       se->exec_start = rq_clock_task(rq_of(cfs_rq));
 }
 
 /**************************************************
@@ -1037,7 +1075,7 @@ static inline long calc_tg_weight(struct task_group *tg, struct cfs_rq *cfs_rq)
         * to gain a more accurate current total weight. See
         * update_cfs_rq_load_contribution().
         */
-       tg_weight = atomic64_read(&tg->load_avg);
+       tg_weight = atomic_long_read(&tg->load_avg);
        tg_weight -= cfs_rq->tg_load_contrib;
        tg_weight += cfs_rq->load.weight;
 
@@ -1110,8 +1148,7 @@ static inline void update_cfs_shares(struct cfs_rq *cfs_rq)
 }
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
-/* Only depends on SMP, FAIR_GROUP_SCHED may be removed when useful in lb */
-#if defined(CONFIG_SMP) && defined(CONFIG_FAIR_GROUP_SCHED)
+#ifdef CONFIG_SMP
 /*
  * We choose a half-life close to 1 scheduling period.
  * Note: The tables below are dependent on this value.
@@ -1319,13 +1356,13 @@ static inline void __update_cfs_rq_tg_load_contrib(struct cfs_rq *cfs_rq,
                                                 int force_update)
 {
        struct task_group *tg = cfs_rq->tg;
-       s64 tg_contrib;
+       long tg_contrib;
 
        tg_contrib = cfs_rq->runnable_load_avg + cfs_rq->blocked_load_avg;
        tg_contrib -= cfs_rq->tg_load_contrib;
 
-       if (force_update || abs64(tg_contrib) > cfs_rq->tg_load_contrib / 8) {
-               atomic64_add(tg_contrib, &tg->load_avg);
+       if (force_update || abs(tg_contrib) > cfs_rq->tg_load_contrib / 8) {
+               atomic_long_add(tg_contrib, &tg->load_avg);
                cfs_rq->tg_load_contrib += tg_contrib;
        }
 }
@@ -1360,8 +1397,8 @@ static inline void __update_group_entity_contrib(struct sched_entity *se)
        u64 contrib;
 
        contrib = cfs_rq->tg_load_contrib * tg->shares;
-       se->avg.load_avg_contrib = div64_u64(contrib,
-                                            atomic64_read(&tg->load_avg) + 1);
+       se->avg.load_avg_contrib = div_u64(contrib,
+                                    atomic_long_read(&tg->load_avg) + 1);
 
        /*
         * For group entities we need to compute a correction term in the case
@@ -1480,8 +1517,9 @@ static void update_cfs_rq_blocked_load(struct cfs_rq *cfs_rq, int force_update)
        if (!decays && !force_update)
                return;
 
-       if (atomic64_read(&cfs_rq->removed_load)) {
-               u64 removed_load = atomic64_xchg(&cfs_rq->removed_load, 0);
+       if (atomic_long_read(&cfs_rq->removed_load)) {
+               unsigned long removed_load;
+               removed_load = atomic_long_xchg(&cfs_rq->removed_load, 0);
                subtract_blocked_load_contrib(cfs_rq, removed_load);
        }
 
@@ -1497,7 +1535,7 @@ static void update_cfs_rq_blocked_load(struct cfs_rq *cfs_rq, int force_update)
 
 static inline void update_rq_runnable_avg(struct rq *rq, int runnable)
 {
-       __update_entity_runnable_avg(rq->clock_task, &rq->avg, runnable);
+       __update_entity_runnable_avg(rq_clock_task(rq), &rq->avg, runnable);
        __update_tg_runnable_avg(&rq->avg, &rq->cfs);
 }
 
@@ -1510,9 +1548,13 @@ static inline void enqueue_entity_load_avg(struct cfs_rq *cfs_rq,
         * We track migrations using entity decay_count <= 0, on a wake-up
         * migration we use a negative decay count to track the remote decays
         * accumulated while sleeping.
+        *
+        * Newly forked tasks are enqueued with se->avg.decay_count == 0, they
+        * are seen by enqueue_entity_load_avg() as a migration with an already
+        * constructed load_avg_contrib.
         */
        if (unlikely(se->avg.decay_count <= 0)) {
-               se->avg.last_runnable_update = rq_of(cfs_rq)->clock_task;
+               se->avg.last_runnable_update = rq_clock_task(rq_of(cfs_rq));
                if (se->avg.decay_count) {
                        /*
                         * In a wake-up migration we have to approximate the
@@ -1530,7 +1572,13 @@ static inline void enqueue_entity_load_avg(struct cfs_rq *cfs_rq,
                }
                wakeup = 0;
        } else {
-               __synchronize_entity_decay(se);
+               /*
+                * Task re-woke on same cpu (or else migrate_task_rq_fair()
+                * would have made count negative); we must be careful to avoid
+                * double-accounting blocked time after synchronizing decays.
+                */
+               se->avg.last_runnable_update += __synchronize_entity_decay(se)
+                                                       << 20;
        }
 
        /* migrated tasks did not contribute to our blocked load */
@@ -1607,7 +1655,7 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
                tsk = task_of(se);
 
        if (se->statistics.sleep_start) {
-               u64 delta = rq_of(cfs_rq)->clock - se->statistics.sleep_start;
+               u64 delta = rq_clock(rq_of(cfs_rq)) - se->statistics.sleep_start;
 
                if ((s64)delta < 0)
                        delta = 0;
@@ -1624,7 +1672,7 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
                }
        }
        if (se->statistics.block_start) {
-               u64 delta = rq_of(cfs_rq)->clock - se->statistics.block_start;
+               u64 delta = rq_clock(rq_of(cfs_rq)) - se->statistics.block_start;
 
                if ((s64)delta < 0)
                        delta = 0;
@@ -1712,7 +1760,7 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 {
        /*
         * Update the normalized vruntime before updating min_vruntime
-        * through callig update_curr().
+        * through calling update_curr().
         */
        if (!(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_WAKING))
                se->vruntime += cfs_rq->min_vruntime;
@@ -1805,9 +1853,9 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
                        struct task_struct *tsk = task_of(se);
 
                        if (tsk->state & TASK_INTERRUPTIBLE)
-                               se->statistics.sleep_start = rq_of(cfs_rq)->clock;
+                               se->statistics.sleep_start = rq_clock(rq_of(cfs_rq));
                        if (tsk->state & TASK_UNINTERRUPTIBLE)
-                               se->statistics.block_start = rq_of(cfs_rq)->clock;
+                               se->statistics.block_start = rq_clock(rq_of(cfs_rq));
                }
 #endif
        }
@@ -2082,7 +2130,7 @@ static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq)
        if (unlikely(cfs_rq->throttle_count))
                return cfs_rq->throttled_clock_task;
 
-       return rq_of(cfs_rq)->clock_task - cfs_rq->throttled_clock_task_time;
+       return rq_clock_task(rq_of(cfs_rq)) - cfs_rq->throttled_clock_task_time;
 }
 
 /* returns 0 on failure to allocate runtime */
@@ -2138,10 +2186,9 @@ static int assign_cfs_rq_runtime(struct cfs_rq *cfs_rq)
 static void expire_cfs_rq_runtime(struct cfs_rq *cfs_rq)
 {
        struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg);
-       struct rq *rq = rq_of(cfs_rq);
 
        /* if the deadline is ahead of our clock, nothing to do */
-       if (likely((s64)(rq->clock - cfs_rq->runtime_expires) < 0))
+       if (likely((s64)(rq_clock(rq_of(cfs_rq)) - cfs_rq->runtime_expires) < 0))
                return;
 
        if (cfs_rq->runtime_remaining < 0)
@@ -2230,7 +2277,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data)
 #ifdef CONFIG_SMP
        if (!cfs_rq->throttle_count) {
                /* adjust cfs_rq_clock_task() */
-               cfs_rq->throttled_clock_task_time += rq->clock_task -
+               cfs_rq->throttled_clock_task_time += rq_clock_task(rq) -
                                             cfs_rq->throttled_clock_task;
        }
 #endif
@@ -2245,7 +2292,7 @@ static int tg_throttle_down(struct task_group *tg, void *data)
 
        /* group is entering throttled state, stop time */
        if (!cfs_rq->throttle_count)
-               cfs_rq->throttled_clock_task = rq->clock_task;
+               cfs_rq->throttled_clock_task = rq_clock_task(rq);
        cfs_rq->throttle_count++;
 
        return 0;
@@ -2284,7 +2331,7 @@ static void throttle_cfs_rq(struct cfs_rq *cfs_rq)
                rq->nr_running -= task_delta;
 
        cfs_rq->throttled = 1;
-       cfs_rq->throttled_clock = rq->clock;
+       cfs_rq->throttled_clock = rq_clock(rq);
        raw_spin_lock(&cfs_b->lock);
        list_add_tail_rcu(&cfs_rq->throttled_list, &cfs_b->throttled_cfs_rq);
        raw_spin_unlock(&cfs_b->lock);
@@ -2298,15 +2345,17 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
        int enqueue = 1;
        long task_delta;
 
-       se = cfs_rq->tg->se[cpu_of(rq_of(cfs_rq))];
+       se = cfs_rq->tg->se[cpu_of(rq)];
 
        cfs_rq->throttled = 0;
+
+       update_rq_clock(rq);
+
        raw_spin_lock(&cfs_b->lock);
-       cfs_b->throttled_time += rq->clock - cfs_rq->throttled_clock;
+       cfs_b->throttled_time += rq_clock(rq) - cfs_rq->throttled_clock;
        list_del_rcu(&cfs_rq->throttled_list);
        raw_spin_unlock(&cfs_b->lock);
 
-       update_rq_clock(rq);
        /* update hierarchical throttle state */
        walk_tg_tree_from(cfs_rq->tg, tg_nop, tg_unthrottle_up, (void *)rq);
 
@@ -2599,10 +2648,6 @@ static void check_cfs_rq_runtime(struct cfs_rq *cfs_rq)
        throttle_cfs_rq(cfs_rq);
 }
 
-static inline u64 default_cfs_period(void);
-static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun);
-static void do_sched_cfs_slack_timer(struct cfs_bandwidth *cfs_b);
-
 static enum hrtimer_restart sched_cfs_slack_timer(struct hrtimer *timer)
 {
        struct cfs_bandwidth *cfs_b =
@@ -2706,7 +2751,7 @@ static void __maybe_unused unthrottle_offline_cfs_rqs(struct rq *rq)
 #else /* CONFIG_CFS_BANDWIDTH */
 static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq)
 {
-       return rq_of(cfs_rq)->clock_task;
+       return rq_clock_task(rq_of(cfs_rq));
 }
 
 static void account_cfs_rq_runtime(struct cfs_rq *cfs_rq,
@@ -2919,7 +2964,7 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
 /* Used instead of source_load when we know the type == 0 */
 static unsigned long weighted_cpuload(const int cpu)
 {
-       return cpu_rq(cpu)->load.weight;
+       return cpu_rq(cpu)->cfs.runnable_load_avg;
 }
 
 /*
@@ -2964,9 +3009,10 @@ static unsigned long cpu_avg_load_per_task(int cpu)
 {
        struct rq *rq = cpu_rq(cpu);
        unsigned long nr_running = ACCESS_ONCE(rq->nr_running);
+       unsigned long load_avg = rq->cfs.runnable_load_avg;
 
        if (nr_running)
-               return rq->load.weight / nr_running;
+               return load_avg / nr_running;
 
        return 0;
 }
@@ -3415,12 +3461,6 @@ unlock:
        return new_cpu;
 }
 
-/*
- * Load-tracking only depends on SMP, FAIR_GROUP_SCHED dependency below may be
- * removed when useful for applications beyond shares distribution (e.g.
- * load-balance).
- */
-#ifdef CONFIG_FAIR_GROUP_SCHED
 /*
  * 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
@@ -3441,10 +3481,10 @@ migrate_task_rq_fair(struct task_struct *p, int next_cpu)
         */
        if (se->avg.decay_count) {
                se->avg.decay_count = -__synchronize_entity_decay(se);
-               atomic64_add(se->avg.load_avg_contrib, &cfs_rq->removed_load);
+               atomic_long_add(se->avg.load_avg_contrib,
+                                               &cfs_rq->removed_load);
        }
 }
-#endif
 #endif /* CONFIG_SMP */
 
 static unsigned long
@@ -3946,7 +3986,7 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
         * 2) too many balance attempts have failed.
         */
 
-       tsk_cache_hot = task_hot(p, env->src_rq->clock_task, env->sd);
+       tsk_cache_hot = task_hot(p, rq_clock_task(env->src_rq), env->sd);
        if (!tsk_cache_hot ||
                env->sd->nr_balance_failed > env->sd->cache_nice_tries) {
 
@@ -4141,11 +4181,11 @@ static int tg_load_down(struct task_group *tg, void *data)
        long cpu = (long)data;
 
        if (!tg->parent) {
-               load = cpu_rq(cpu)->load.weight;
+               load = cpu_rq(cpu)->avg.load_avg_contrib;
        } else {
                load = tg->parent->cfs_rq[cpu]->h_load;
-               load *= tg->se[cpu]->load.weight;
-               load /= tg->parent->cfs_rq[cpu]->load.weight + 1;
+               load = div64_ul(load * tg->se[cpu]->avg.load_avg_contrib,
+                               tg->parent->cfs_rq[cpu]->runnable_load_avg + 1);
        }
 
        tg->cfs_rq[cpu]->h_load = load;
@@ -4171,12 +4211,9 @@ static void update_h_load(long cpu)
 static unsigned long task_h_load(struct task_struct *p)
 {
        struct cfs_rq *cfs_rq = task_cfs_rq(p);
-       unsigned long load;
-
-       load = p->se.load.weight;
-       load = div_u64(load * cfs_rq->h_load, cfs_rq->load.weight + 1);
 
-       return load;
+       return div64_ul(p->se.avg.load_avg_contrib * cfs_rq->h_load,
+                       cfs_rq->runnable_load_avg + 1);
 }
 #else
 static inline void update_blocked_averages(int cpu)
@@ -4189,7 +4226,7 @@ static inline void update_h_load(long cpu)
 
 static unsigned long task_h_load(struct task_struct *p)
 {
-       return p->se.load.weight;
+       return p->se.avg.load_avg_contrib;
 }
 #endif
 
@@ -4302,7 +4339,7 @@ static unsigned long scale_rt_power(int cpu)
        age_stamp = ACCESS_ONCE(rq->age_stamp);
        avg = ACCESS_ONCE(rq->rt_avg);
 
-       total = sched_avg_period() + (rq->clock - age_stamp);
+       total = sched_avg_period() + (rq_clock(rq) - age_stamp);
 
        if (unlikely(total < avg)) {
                /* Ensures that power won't end up being negative */
@@ -5241,7 +5278,7 @@ void idle_balance(int this_cpu, struct rq *this_rq)
        int pulled_task = 0;
        unsigned long next_balance = jiffies + HZ;
 
-       this_rq->idle_stamp = this_rq->clock;
+       this_rq->idle_stamp = rq_clock(this_rq);
 
        if (this_rq->avg_idle < sysctl_sched_migration_cost)
                return;
@@ -5418,10 +5455,9 @@ static inline void nohz_balance_exit_idle(int cpu)
 static inline void set_cpu_sd_state_busy(void)
 {
        struct sched_domain *sd;
-       int cpu = smp_processor_id();
 
        rcu_read_lock();
-       sd = rcu_dereference_check_sched_domain(cpu_rq(cpu)->sd);
+       sd = rcu_dereference_check_sched_domain(this_rq()->sd);
 
        if (!sd || !sd->nohz_idle)
                goto unlock;
@@ -5436,10 +5472,9 @@ unlock:
 void set_cpu_sd_state_idle(void)
 {
        struct sched_domain *sd;
-       int cpu = smp_processor_id();
 
        rcu_read_lock();
-       sd = rcu_dereference_check_sched_domain(cpu_rq(cpu)->sd);
+       sd = rcu_dereference_check_sched_domain(this_rq()->sd);
 
        if (!sd || sd->nohz_idle)
                goto unlock;
@@ -5848,7 +5883,7 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
                se->vruntime -= cfs_rq->min_vruntime;
        }
 
-#if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_SMP)
+#ifdef CONFIG_SMP
        /*
        * Remove our load from contribution when we leave sched_fair
        * and ensure we don't carry in an old decay_count if we
@@ -5907,9 +5942,9 @@ void init_cfs_rq(struct cfs_rq *cfs_rq)
 #ifndef CONFIG_64BIT
        cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime;
 #endif
-#if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_SMP)
+#ifdef CONFIG_SMP
        atomic64_set(&cfs_rq->decay_counter, 1);
-       atomic64_set(&cfs_rq->removed_load, 0);
+       atomic_long_set(&cfs_rq->removed_load, 0);
 #endif
 }
 
@@ -6091,6 +6126,9 @@ int sched_group_set_shares(struct task_group *tg, unsigned long shares)
                se = tg->se[i];
                /* Propagate contribution to hierarchy */
                raw_spin_lock_irqsave(&rq->lock, flags);
+
+               /* Possible calls to update_curr() need rq clock */
+               update_rq_clock(rq);
                for_each_sched_entity(se)
                        update_cfs_shares(group_cfs_rq(se));
                raw_spin_unlock_irqrestore(&rq->lock, flags);
@@ -6146,9 +6184,8 @@ const struct sched_class fair_sched_class = {
 
 #ifdef CONFIG_SMP
        .select_task_rq         = select_task_rq_fair,
-#ifdef CONFIG_FAIR_GROUP_SCHED
        .migrate_task_rq        = migrate_task_rq_fair,
-#endif
+
        .rq_online              = rq_online_fair,
        .rq_offline             = rq_offline_fair,
 
diff --git a/kernel/sched/proc.c b/kernel/sched/proc.c
new file mode 100644 (file)
index 0000000..16f5a30
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ *  kernel/sched/proc.c
+ *
+ *  Kernel load calculations, forked from sched/core.c
+ */
+
+#include <linux/export.h>
+
+#include "sched.h"
+
+unsigned long this_cpu_load(void)
+{
+       struct rq *this = this_rq();
+       return this->cpu_load[0];
+}
+
+
+/*
+ * Global load-average calculations
+ *
+ * We take a distributed and async approach to calculating the global load-avg
+ * in order to minimize overhead.
+ *
+ * The global load average is an exponentially decaying average of nr_running +
+ * nr_uninterruptible.
+ *
+ * Once every LOAD_FREQ:
+ *
+ *   nr_active = 0;
+ *   for_each_possible_cpu(cpu)
+ *     nr_active += cpu_of(cpu)->nr_running + cpu_of(cpu)->nr_uninterruptible;
+ *
+ *   avenrun[n] = avenrun[0] * exp_n + nr_active * (1 - exp_n)
+ *
+ * Due to a number of reasons the above turns in the mess below:
+ *
+ *  - for_each_possible_cpu() is prohibitively expensive on machines with
+ *    serious number of cpus, therefore we need to take a distributed approach
+ *    to calculating nr_active.
+ *
+ *        \Sum_i x_i(t) = \Sum_i x_i(t) - x_i(t_0) | x_i(t_0) := 0
+ *                      = \Sum_i { \Sum_j=1 x_i(t_j) - x_i(t_j-1) }
+ *
+ *    So assuming nr_active := 0 when we start out -- true per definition, we
+ *    can simply take per-cpu deltas and fold those into a global accumulate
+ *    to obtain the same result. See calc_load_fold_active().
+ *
+ *    Furthermore, in order to avoid synchronizing all per-cpu delta folding
+ *    across the machine, we assume 10 ticks is sufficient time for every
+ *    cpu to have completed this task.
+ *
+ *    This places an upper-bound on the IRQ-off latency of the machine. Then
+ *    again, being late doesn't loose the delta, just wrecks the sample.
+ *
+ *  - cpu_rq()->nr_uninterruptible isn't accurately tracked per-cpu because
+ *    this would add another cross-cpu cacheline miss and atomic operation
+ *    to the wakeup path. Instead we increment on whatever cpu the task ran
+ *    when it went into uninterruptible state and decrement on whatever cpu
+ *    did the wakeup. This means that only the sum of nr_uninterruptible over
+ *    all cpus yields the correct result.
+ *
+ *  This covers the NO_HZ=n code, for extra head-aches, see the comment below.
+ */
+
+/* Variables and functions for calc_load */
+atomic_long_t calc_load_tasks;
+unsigned long calc_load_update;
+unsigned long avenrun[3];
+EXPORT_SYMBOL(avenrun); /* should be removed */
+
+/**
+ * get_avenrun - get the load average array
+ * @loads:     pointer to dest load array
+ * @offset:    offset to add
+ * @shift:     shift count to shift the result left
+ *
+ * These values are estimates at best, so no need for locking.
+ */
+void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
+{
+       loads[0] = (avenrun[0] + offset) << shift;
+       loads[1] = (avenrun[1] + offset) << shift;
+       loads[2] = (avenrun[2] + offset) << shift;
+}
+
+long calc_load_fold_active(struct rq *this_rq)
+{
+       long nr_active, delta = 0;
+
+       nr_active = this_rq->nr_running;
+       nr_active += (long) this_rq->nr_uninterruptible;
+
+       if (nr_active != this_rq->calc_load_active) {
+               delta = nr_active - this_rq->calc_load_active;
+               this_rq->calc_load_active = nr_active;
+       }
+
+       return delta;
+}
+
+/*
+ * a1 = a0 * e + a * (1 - e)
+ */
+static unsigned long
+calc_load(unsigned long load, unsigned long exp, unsigned long active)
+{
+       load *= exp;
+       load += active * (FIXED_1 - exp);
+       load += 1UL << (FSHIFT - 1);
+       return load >> FSHIFT;
+}
+
+#ifdef CONFIG_NO_HZ_COMMON
+/*
+ * Handle NO_HZ for the global load-average.
+ *
+ * Since the above described distributed algorithm to compute the global
+ * load-average relies on per-cpu sampling from the tick, it is affected by
+ * NO_HZ.
+ *
+ * The basic idea is to fold the nr_active delta into a global idle-delta upon
+ * entering NO_HZ state such that we can include this as an 'extra' cpu delta
+ * when we read the global state.
+ *
+ * Obviously reality has to ruin such a delightfully simple scheme:
+ *
+ *  - When we go NO_HZ idle during the window, we can negate our sample
+ *    contribution, causing under-accounting.
+ *
+ *    We avoid this by keeping two idle-delta counters and flipping them
+ *    when the window starts, thus separating old and new NO_HZ load.
+ *
+ *    The only trick is the slight shift in index flip for read vs write.
+ *
+ *        0s            5s            10s           15s
+ *          +10           +10           +10           +10
+ *        |-|-----------|-|-----------|-|-----------|-|
+ *    r:0 0 1           1 0           0 1           1 0
+ *    w:0 1 1           0 0           1 1           0 0
+ *
+ *    This ensures we'll fold the old idle contribution in this window while
+ *    accumlating the new one.
+ *
+ *  - When we wake up from NO_HZ idle during the window, we push up our
+ *    contribution, since we effectively move our sample point to a known
+ *    busy state.
+ *
+ *    This is solved by pushing the window forward, and thus skipping the
+ *    sample, for this cpu (effectively using the idle-delta for this cpu which
+ *    was in effect at the time the window opened). This also solves the issue
+ *    of having to deal with a cpu having been in NOHZ idle for multiple
+ *    LOAD_FREQ intervals.
+ *
+ * When making the ILB scale, we should try to pull this in as well.
+ */
+static atomic_long_t calc_load_idle[2];
+static int calc_load_idx;
+
+static inline int calc_load_write_idx(void)
+{
+       int idx = calc_load_idx;
+
+       /*
+        * See calc_global_nohz(), if we observe the new index, we also
+        * need to observe the new update time.
+        */
+       smp_rmb();
+
+       /*
+        * If the folding window started, make sure we start writing in the
+        * next idle-delta.
+        */
+       if (!time_before(jiffies, calc_load_update))
+               idx++;
+
+       return idx & 1;
+}
+
+static inline int calc_load_read_idx(void)
+{
+       return calc_load_idx & 1;
+}
+
+void calc_load_enter_idle(void)
+{
+       struct rq *this_rq = this_rq();
+       long delta;
+
+       /*
+        * We're going into NOHZ mode, if there's any pending delta, fold it
+        * into the pending idle delta.
+        */
+       delta = calc_load_fold_active(this_rq);
+       if (delta) {
+               int idx = calc_load_write_idx();
+               atomic_long_add(delta, &calc_load_idle[idx]);
+       }
+}
+
+void calc_load_exit_idle(void)
+{
+       struct rq *this_rq = this_rq();
+
+       /*
+        * If we're still before the sample window, we're done.
+        */
+       if (time_before(jiffies, this_rq->calc_load_update))
+               return;
+
+       /*
+        * We woke inside or after the sample window, this means we're already
+        * accounted through the nohz accounting, so skip the entire deal and
+        * sync up for the next window.
+        */
+       this_rq->calc_load_update = calc_load_update;
+       if (time_before(jiffies, this_rq->calc_load_update + 10))
+               this_rq->calc_load_update += LOAD_FREQ;
+}
+
+static long calc_load_fold_idle(void)
+{
+       int idx = calc_load_read_idx();
+       long delta = 0;
+
+       if (atomic_long_read(&calc_load_idle[idx]))
+               delta = atomic_long_xchg(&calc_load_idle[idx], 0);
+
+       return delta;
+}
+
+/**
+ * fixed_power_int - compute: x^n, in O(log n) time
+ *
+ * @x:         base of the power
+ * @frac_bits: fractional bits of @x
+ * @n:         power to raise @x to.
+ *
+ * By exploiting the relation between the definition of the natural power
+ * function: x^n := x*x*...*x (x multiplied by itself for n times), and
+ * the binary encoding of numbers used by computers: n := \Sum n_i * 2^i,
+ * (where: n_i \elem {0, 1}, the binary vector representing n),
+ * we find: x^n := x^(\Sum n_i * 2^i) := \Prod x^(n_i * 2^i), which is
+ * of course trivially computable in O(log_2 n), the length of our binary
+ * vector.
+ */
+static unsigned long
+fixed_power_int(unsigned long x, unsigned int frac_bits, unsigned int n)
+{
+       unsigned long result = 1UL << frac_bits;
+
+       if (n) for (;;) {
+               if (n & 1) {
+                       result *= x;
+                       result += 1UL << (frac_bits - 1);
+                       result >>= frac_bits;
+               }
+               n >>= 1;
+               if (!n)
+                       break;
+               x *= x;
+               x += 1UL << (frac_bits - 1);
+               x >>= frac_bits;
+       }
+
+       return result;
+}
+
+/*
+ * a1 = a0 * e + a * (1 - e)
+ *
+ * a2 = a1 * e + a * (1 - e)
+ *    = (a0 * e + a * (1 - e)) * e + a * (1 - e)
+ *    = a0 * e^2 + a * (1 - e) * (1 + e)
+ *
+ * a3 = a2 * e + a * (1 - e)
+ *    = (a0 * e^2 + a * (1 - e) * (1 + e)) * e + a * (1 - e)
+ *    = a0 * e^3 + a * (1 - e) * (1 + e + e^2)
+ *
+ *  ...
+ *
+ * an = a0 * e^n + a * (1 - e) * (1 + e + ... + e^n-1) [1]
+ *    = a0 * e^n + a * (1 - e) * (1 - e^n)/(1 - e)
+ *    = a0 * e^n + a * (1 - e^n)
+ *
+ * [1] application of the geometric series:
+ *
+ *              n         1 - x^(n+1)
+ *     S_n := \Sum x^i = -------------
+ *             i=0          1 - x
+ */
+static unsigned long
+calc_load_n(unsigned long load, unsigned long exp,
+           unsigned long active, unsigned int n)
+{
+
+       return calc_load(load, fixed_power_int(exp, FSHIFT, n), active);
+}
+
+/*
+ * NO_HZ can leave us missing all per-cpu ticks calling
+ * calc_load_account_active(), but since an idle CPU folds its delta into
+ * calc_load_tasks_idle per calc_load_account_idle(), all we need to do is fold
+ * in the pending idle delta if our idle period crossed a load cycle boundary.
+ *
+ * Once we've updated the global active value, we need to apply the exponential
+ * weights adjusted to the number of cycles missed.
+ */
+static void calc_global_nohz(void)
+{
+       long delta, active, n;
+
+       if (!time_before(jiffies, calc_load_update + 10)) {
+               /*
+                * Catch-up, fold however many we are behind still
+                */
+               delta = jiffies - calc_load_update - 10;
+               n = 1 + (delta / LOAD_FREQ);
+
+               active = atomic_long_read(&calc_load_tasks);
+               active = active > 0 ? active * FIXED_1 : 0;
+
+               avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
+               avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
+               avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
+
+               calc_load_update += n * LOAD_FREQ;
+       }
+
+       /*
+        * Flip the idle index...
+        *
+        * Make sure we first write the new time then flip the index, so that
+        * calc_load_write_idx() will see the new time when it reads the new
+        * index, this avoids a double flip messing things up.
+        */
+       smp_wmb();
+       calc_load_idx++;
+}
+#else /* !CONFIG_NO_HZ_COMMON */
+
+static inline long calc_load_fold_idle(void) { return 0; }
+static inline void calc_global_nohz(void) { }
+
+#endif /* CONFIG_NO_HZ_COMMON */
+
+/*
+ * calc_load - update the avenrun load estimates 10 ticks after the
+ * CPUs have updated calc_load_tasks.
+ */
+void calc_global_load(unsigned long ticks)
+{
+       long active, delta;
+
+       if (time_before(jiffies, calc_load_update + 10))
+               return;
+
+       /*
+        * Fold the 'old' idle-delta to include all NO_HZ cpus.
+        */
+       delta = calc_load_fold_idle();
+       if (delta)
+               atomic_long_add(delta, &calc_load_tasks);
+
+       active = atomic_long_read(&calc_load_tasks);
+       active = active > 0 ? active * FIXED_1 : 0;
+
+       avenrun[0] = calc_load(avenrun[0], EXP_1, active);
+       avenrun[1] = calc_load(avenrun[1], EXP_5, active);
+       avenrun[2] = calc_load(avenrun[2], EXP_15, active);
+
+       calc_load_update += LOAD_FREQ;
+
+       /*
+        * In case we idled for multiple LOAD_FREQ intervals, catch up in bulk.
+        */
+       calc_global_nohz();
+}
+
+/*
+ * Called from update_cpu_load() to periodically update this CPU's
+ * active count.
+ */
+static void calc_load_account_active(struct rq *this_rq)
+{
+       long delta;
+
+       if (time_before(jiffies, this_rq->calc_load_update))
+               return;
+
+       delta  = calc_load_fold_active(this_rq);
+       if (delta)
+               atomic_long_add(delta, &calc_load_tasks);
+
+       this_rq->calc_load_update += LOAD_FREQ;
+}
+
+/*
+ * End of global load-average stuff
+ */
+
+/*
+ * 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
+ *
+ * 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
+ *
+ * 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
+ *
+ * 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} };
+
+/*
+ * Update cpu_load for any missed ticks, due to tickless idle. The backlog
+ * would be when CPU is idle and so we just decay the old load without
+ * adding any new load.
+ */
+static unsigned long
+decay_load_missed(unsigned long load, unsigned long missed_updates, int idx)
+{
+       int j = 0;
+
+       if (!missed_updates)
+               return load;
+
+       if (missed_updates >= degrade_zero_ticks[idx])
+               return 0;
+
+       if (idx == 1)
+               return load >> missed_updates;
+
+       while (missed_updates) {
+               if (missed_updates % 2)
+                       load = (load * degrade_factor[idx][j]) >> DEGRADE_SHIFT;
+
+               missed_updates >>= 1;
+               j++;
+       }
+       return load;
+}
+
+/*
+ * 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.
+ */
+static void __update_cpu_load(struct rq *this_rq, unsigned long this_load,
+                             unsigned long pending_updates)
+{
+       int i, scale;
+
+       this_rq->nr_load_updates++;
+
+       /* Update our load: */
+       this_rq->cpu_load[0] = this_load; /* Fasttrack for idx 0 */
+       for (i = 1, scale = 2; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
+               unsigned long old_load, new_load;
+
+               /* scale is effectively 1 << i now, and >> i divides by scale */
+
+               old_load = this_rq->cpu_load[i];
+               old_load = decay_load_missed(old_load, pending_updates - 1, i);
+               new_load = this_load;
+               /*
+                * Round up the averaging division if load is increasing. This
+                * prevents us from getting stuck on 9 if the load is 10, for
+                * example.
+                */
+               if (new_load > old_load)
+                       new_load += scale - 1;
+
+               this_rq->cpu_load[i] = (old_load * (scale - 1) + new_load) >> i;
+       }
+
+       sched_avg_update(this_rq);
+}
+
+#ifdef CONFIG_SMP
+static inline unsigned long get_rq_runnable_load(struct rq *rq)
+{
+       return rq->cfs.runnable_load_avg;
+}
+#else
+static inline unsigned long get_rq_runnable_load(struct rq *rq)
+{
+       return rq->load.weight;
+}
+#endif
+
+#ifdef CONFIG_NO_HZ_COMMON
+/*
+ * There is no sane way to deal with nohz on smp when using jiffies because the
+ * cpu doing the jiffies update might drift wrt the cpu doing the jiffy reading
+ * causing off-by-one errors in observed deltas; {0,2} instead of {1,1}.
+ *
+ * Therefore we cannot use the delta approach from the regular tick since that
+ * would seriously skew the load calculation. However we'll make do for those
+ * updates happening while idle (nohz_idle_balance) or coming out of idle
+ * (tick_nohz_idle_exit).
+ *
+ * This means we might still be one tick off for nohz periods.
+ */
+
+/*
+ * Called from nohz_idle_balance() to update the load ratings before doing the
+ * idle balance.
+ */
+void update_idle_cpu_load(struct rq *this_rq)
+{
+       unsigned long curr_jiffies = ACCESS_ONCE(jiffies);
+       unsigned long load = get_rq_runnable_load(this_rq);
+       unsigned long pending_updates;
+
+       /*
+        * bail if there's load or we're actually up-to-date.
+        */
+       if (load || curr_jiffies == this_rq->last_load_update_tick)
+               return;
+
+       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);
+}
+
+/*
+ * Called from tick_nohz_idle_exit() -- try and fix up the ticks we missed.
+ */
+void update_cpu_load_nohz(void)
+{
+       struct rq *this_rq = this_rq();
+       unsigned long curr_jiffies = ACCESS_ONCE(jiffies);
+       unsigned long pending_updates;
+
+       if (curr_jiffies == this_rq->last_load_update_tick)
+               return;
+
+       raw_spin_lock(&this_rq->lock);
+       pending_updates = curr_jiffies - this_rq->last_load_update_tick;
+       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.
+                */
+               __update_cpu_load(this_rq, 0, pending_updates);
+       }
+       raw_spin_unlock(&this_rq->lock);
+}
+#endif /* CONFIG_NO_HZ */
+
+/*
+ * Called from scheduler_tick()
+ */
+void update_cpu_load_active(struct rq *this_rq)
+{
+       unsigned long load = get_rq_runnable_load(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);
+
+       calc_load_account_active(this_rq);
+}
index 127a2c4cf4ab4f176bbf554be2ad34f4d597c258..01970c8e64df64def4585bf3bd517c3bdb8a9354 100644 (file)
@@ -399,20 +399,6 @@ static inline struct task_group *next_task_group(struct task_group *tg)
                (iter = next_task_group(iter)) &&                       \
                (rt_rq = iter->rt_rq[cpu_of(rq)]);)
 
-static inline void list_add_leaf_rt_rq(struct rt_rq *rt_rq)
-{
-       list_add_rcu(&rt_rq->leaf_rt_rq_list,
-                       &rq_of_rt_rq(rt_rq)->leaf_rt_rq_list);
-}
-
-static inline void list_del_leaf_rt_rq(struct rt_rq *rt_rq)
-{
-       list_del_rcu(&rt_rq->leaf_rt_rq_list);
-}
-
-#define for_each_leaf_rt_rq(rt_rq, rq) \
-       list_for_each_entry_rcu(rt_rq, &rq->leaf_rt_rq_list, leaf_rt_rq_list)
-
 #define for_each_sched_rt_entity(rt_se) \
        for (; rt_se; rt_se = rt_se->parent)
 
@@ -472,7 +458,7 @@ static int rt_se_boosted(struct sched_rt_entity *rt_se)
 #ifdef CONFIG_SMP
 static inline const struct cpumask *sched_rt_period_mask(void)
 {
-       return cpu_rq(smp_processor_id())->rd->span;
+       return this_rq()->rd->span;
 }
 #else
 static inline const struct cpumask *sched_rt_period_mask(void)
@@ -509,17 +495,6 @@ typedef struct rt_rq *rt_rq_iter_t;
 #define for_each_rt_rq(rt_rq, iter, rq) \
        for ((void) iter, rt_rq = &rq->rt; rt_rq; rt_rq = NULL)
 
-static inline void list_add_leaf_rt_rq(struct rt_rq *rt_rq)
-{
-}
-
-static inline void list_del_leaf_rt_rq(struct rt_rq *rt_rq)
-{
-}
-
-#define for_each_leaf_rt_rq(rt_rq, rq) \
-       for (rt_rq = &rq->rt; rt_rq; rt_rq = NULL)
-
 #define for_each_sched_rt_entity(rt_se) \
        for (; rt_se; rt_se = NULL)
 
@@ -699,15 +674,6 @@ balanced:
        }
 }
 
-static void disable_runtime(struct rq *rq)
-{
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&rq->lock, flags);
-       __disable_runtime(rq);
-       raw_spin_unlock_irqrestore(&rq->lock, flags);
-}
-
 static void __enable_runtime(struct rq *rq)
 {
        rt_rq_iter_t iter;
@@ -732,37 +698,6 @@ static void __enable_runtime(struct rq *rq)
        }
 }
 
-static void enable_runtime(struct rq *rq)
-{
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&rq->lock, flags);
-       __enable_runtime(rq);
-       raw_spin_unlock_irqrestore(&rq->lock, flags);
-}
-
-int update_runtime(struct notifier_block *nfb, unsigned long action, void *hcpu)
-{
-       int cpu = (int)(long)hcpu;
-
-       switch (action) {
-       case CPU_DOWN_PREPARE:
-       case CPU_DOWN_PREPARE_FROZEN:
-               disable_runtime(cpu_rq(cpu));
-               return NOTIFY_OK;
-
-       case CPU_DOWN_FAILED:
-       case CPU_DOWN_FAILED_FROZEN:
-       case CPU_ONLINE:
-       case CPU_ONLINE_FROZEN:
-               enable_runtime(cpu_rq(cpu));
-               return NOTIFY_OK;
-
-       default:
-               return NOTIFY_DONE;
-       }
-}
-
 static int balance_runtime(struct rt_rq *rt_rq)
 {
        int more = 0;
@@ -926,7 +861,7 @@ static void update_curr_rt(struct rq *rq)
        if (curr->sched_class != &rt_sched_class)
                return;
 
-       delta_exec = rq->clock_task - curr->se.exec_start;
+       delta_exec = rq_clock_task(rq) - curr->se.exec_start;
        if (unlikely((s64)delta_exec <= 0))
                return;
 
@@ -936,7 +871,7 @@ static void update_curr_rt(struct rq *rq)
        curr->se.sum_exec_runtime += delta_exec;
        account_group_exec_runtime(curr, delta_exec);
 
-       curr->se.exec_start = rq->clock_task;
+       curr->se.exec_start = rq_clock_task(rq);
        cpuacct_charge(curr, delta_exec);
 
        sched_rt_avg_update(rq, delta_exec);
@@ -1106,9 +1041,6 @@ static void __enqueue_rt_entity(struct sched_rt_entity *rt_se, bool head)
        if (group_rq && (rt_rq_throttled(group_rq) || !group_rq->rt_nr_running))
                return;
 
-       if (!rt_rq->rt_nr_running)
-               list_add_leaf_rt_rq(rt_rq);
-
        if (head)
                list_add(&rt_se->run_list, queue);
        else
@@ -1128,8 +1060,6 @@ static void __dequeue_rt_entity(struct sched_rt_entity *rt_se)
                __clear_bit(rt_se_prio(rt_se), array->bitmap);
 
        dec_rt_tasks(rt_se, rt_rq);
-       if (!rt_rq->rt_nr_running)
-               list_del_leaf_rt_rq(rt_rq);
 }
 
 /*
@@ -1385,7 +1315,7 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq)
        } while (rt_rq);
 
        p = rt_task_of(rt_se);
-       p->se.exec_start = rq->clock_task;
+       p->se.exec_start = rq_clock_task(rq);
 
        return p;
 }
@@ -1434,42 +1364,24 @@ static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu)
        return 0;
 }
 
-/* Return the second highest RT task, NULL otherwise */
-static struct task_struct *pick_next_highest_task_rt(struct rq *rq, int cpu)
+/*
+ * Return the highest pushable rq's task, which is suitable to be executed
+ * on the cpu, NULL otherwise
+ */
+static struct task_struct *pick_highest_pushable_task(struct rq *rq, int cpu)
 {
-       struct task_struct *next = NULL;
-       struct sched_rt_entity *rt_se;
-       struct rt_prio_array *array;
-       struct rt_rq *rt_rq;
-       int idx;
-
-       for_each_leaf_rt_rq(rt_rq, rq) {
-               array = &rt_rq->active;
-               idx = sched_find_first_bit(array->bitmap);
-next_idx:
-               if (idx >= MAX_RT_PRIO)
-                       continue;
-               if (next && next->prio <= idx)
-                       continue;
-               list_for_each_entry(rt_se, array->queue + idx, run_list) {
-                       struct task_struct *p;
+       struct plist_head *head = &rq->rt.pushable_tasks;
+       struct task_struct *p;
 
-                       if (!rt_entity_is_task(rt_se))
-                               continue;
+       if (!has_pushable_tasks(rq))
+               return NULL;
 
-                       p = rt_task_of(rt_se);
-                       if (pick_rt_task(rq, p, cpu)) {
-                               next = p;
-                               break;
-                       }
-               }
-               if (!next) {
-                       idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx+1);
-                       goto next_idx;
-               }
+       plist_for_each_entry(p, head, pushable_tasks) {
+               if (pick_rt_task(rq, p, cpu))
+                       return p;
        }
 
-       return next;
+       return NULL;
 }
 
 static DEFINE_PER_CPU(cpumask_var_t, local_cpu_mask);
@@ -1743,12 +1655,10 @@ static int pull_rt_task(struct rq *this_rq)
                double_lock_balance(this_rq, src_rq);
 
                /*
-                * Are there still pullable RT tasks?
+                * We can pull only a task, which is pushable
+                * on its rq, and no others.
                 */
-               if (src_rq->rt.rt_nr_running <= 1)
-                       goto skip;
-
-               p = pick_next_highest_task_rt(src_rq, this_cpu);
+               p = pick_highest_pushable_task(src_rq, this_cpu);
 
                /*
                 * Do we have an RT task that preempts
@@ -2037,7 +1947,7 @@ static void set_curr_task_rt(struct rq *rq)
 {
        struct task_struct *p = rq->curr;
 
-       p->se.exec_start = rq->clock_task;
+       p->se.exec_start = rq_clock_task(rq);
 
        /* The running task is never eligible for pushing */
        dequeue_pushable_task(rq, p);
index ce39224d615599c40a1d6e7f8f4a78d728e2acad..ef0a7b2439dde25bdd3d4ee54c4801364e09607d 100644 (file)
 #include "cpupri.h"
 #include "cpuacct.h"
 
+struct rq;
+
 extern __read_mostly int scheduler_running;
 
+extern unsigned long calc_load_update;
+extern atomic_long_t calc_load_tasks;
+
+extern long calc_load_fold_active(struct rq *this_rq);
+extern void update_cpu_load_active(struct rq *this_rq);
+
 /*
  * Convert user-nice values [ -20 ... 0 ... 19 ]
  * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
@@ -140,10 +148,11 @@ struct task_group {
        struct cfs_rq **cfs_rq;
        unsigned long shares;
 
-       atomic_t load_weight;
-       atomic64_t load_avg;
+#ifdef CONFIG_SMP
+       atomic_long_t load_avg;
        atomic_t runnable_avg;
 #endif
+#endif
 
 #ifdef CONFIG_RT_GROUP_SCHED
        struct sched_rt_entity **rt_se;
@@ -261,26 +270,21 @@ struct cfs_rq {
 #endif
 
 #ifdef CONFIG_SMP
-/*
- * Load-tracking only depends on SMP, FAIR_GROUP_SCHED dependency below may be
- * removed when useful for applications beyond shares distribution (e.g.
- * load-balance).
- */
-#ifdef CONFIG_FAIR_GROUP_SCHED
        /*
         * CFS Load tracking
         * Under CFS, load is tracked on a per-entity basis and aggregated up.
         * This allows for the description of both thread and group usage (in
         * the FAIR_GROUP_SCHED case).
         */
-       u64 runnable_load_avg, blocked_load_avg;
-       atomic64_t decay_counter, removed_load;
+       unsigned long runnable_load_avg, blocked_load_avg;
+       atomic64_t decay_counter;
        u64 last_decay;
-#endif /* CONFIG_FAIR_GROUP_SCHED */
-/* These always depend on CONFIG_FAIR_GROUP_SCHED */
+       atomic_long_t removed_load;
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
+       /* Required to track per-cpu representation of a task_group */
        u32 tg_runnable_contrib;
-       u64 tg_load_contrib;
+       unsigned long tg_load_contrib;
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
        /*
@@ -353,7 +357,6 @@ struct rt_rq {
        unsigned long rt_nr_boosted;
 
        struct rq *rq;
-       struct list_head leaf_rt_rq_list;
        struct task_group *tg;
 #endif
 };
@@ -540,6 +543,16 @@ DECLARE_PER_CPU(struct rq, runqueues);
 #define cpu_curr(cpu)          (cpu_rq(cpu)->curr)
 #define raw_rq()               (&__raw_get_cpu_var(runqueues))
 
+static inline u64 rq_clock(struct rq *rq)
+{
+       return rq->clock;
+}
+
+static inline u64 rq_clock_task(struct rq *rq)
+{
+       return rq->clock_task;
+}
+
 #ifdef CONFIG_SMP
 
 #define rcu_dereference_check_sched_domain(p) \
@@ -884,24 +897,6 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
 #define WF_FORK                0x02            /* child wakeup after fork */
 #define WF_MIGRATED    0x4             /* internal use, task got migrated */
 
-static inline void update_load_add(struct load_weight *lw, unsigned long inc)
-{
-       lw->weight += inc;
-       lw->inv_weight = 0;
-}
-
-static inline void update_load_sub(struct load_weight *lw, unsigned long dec)
-{
-       lw->weight -= dec;
-       lw->inv_weight = 0;
-}
-
-static inline void update_load_set(struct load_weight *lw, unsigned long w)
-{
-       lw->weight = w;
-       lw->inv_weight = 0;
-}
-
 /*
  * To aid in avoiding the subversion of "niceness" due to uneven distribution
  * of tasks with abnormal "nice" values across CPUs the contribution that
@@ -1028,17 +1023,8 @@ extern void update_group_power(struct sched_domain *sd, int cpu);
 extern void trigger_load_balance(struct rq *rq, int cpu);
 extern void idle_balance(int this_cpu, struct rq *this_rq);
 
-/*
- * Only depends on SMP, FAIR_GROUP_SCHED may be removed when runnable_avg
- * becomes useful in lb
- */
-#if defined(CONFIG_FAIR_GROUP_SCHED)
 extern void idle_enter_fair(struct rq *this_rq);
 extern void idle_exit_fair(struct rq *this_rq);
-#else
-static inline void idle_enter_fair(struct rq *this_rq) {}
-static inline void idle_exit_fair(struct rq *this_rq) {}
-#endif
 
 #else  /* CONFIG_SMP */
 
@@ -1051,7 +1037,6 @@ static inline void idle_balance(int cpu, struct rq *rq)
 extern void sysrq_sched_debug_show(void);
 extern void sched_init_granularity(void);
 extern void update_max_interval(void);
-extern int update_runtime(struct notifier_block *nfb, unsigned long action, void *hcpu);
 extern void init_sched_rt_class(void);
 extern void init_sched_fair_class(void);
 
@@ -1063,6 +1048,8 @@ extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime
 
 extern void update_idle_cpu_load(struct rq *this_rq);
 
+extern void init_task_runnable_average(struct task_struct *p);
+
 #ifdef CONFIG_PARAVIRT
 static inline u64 steal_ticks(u64 steal)
 {
index 2ef90a51ec5e3ad6ccff9e8f44fde752d204dcda..17d7065c38721a3431e011642e8d6e634d10a40d 100644 (file)
@@ -61,7 +61,7 @@ static inline void sched_info_reset_dequeued(struct task_struct *t)
  */
 static inline void sched_info_dequeued(struct task_struct *t)
 {
-       unsigned long long now = task_rq(t)->clock, delta = 0;
+       unsigned long long now = rq_clock(task_rq(t)), delta = 0;
 
        if (unlikely(sched_info_on()))
                if (t->sched_info.last_queued)
@@ -79,7 +79,7 @@ static inline void sched_info_dequeued(struct task_struct *t)
  */
 static void sched_info_arrive(struct task_struct *t)
 {
-       unsigned long long now = task_rq(t)->clock, delta = 0;
+       unsigned long long now = rq_clock(task_rq(t)), delta = 0;
 
        if (t->sched_info.last_queued)
                delta = now - t->sched_info.last_queued;
@@ -100,7 +100,7 @@ static inline void sched_info_queued(struct task_struct *t)
 {
        if (unlikely(sched_info_on()))
                if (!t->sched_info.last_queued)
-                       t->sched_info.last_queued = task_rq(t)->clock;
+                       t->sched_info.last_queued = rq_clock(task_rq(t));
 }
 
 /*
@@ -112,7 +112,7 @@ static inline void sched_info_queued(struct task_struct *t)
  */
 static inline void sched_info_depart(struct task_struct *t)
 {
-       unsigned long long delta = task_rq(t)->clock -
+       unsigned long long delta = rq_clock(task_rq(t)) -
                                        t->sched_info.last_arrival;
 
        rq_sched_info_depart(task_rq(t), delta);
index da5eb5bed84a2ca8db2443ccb71817d48f06c1f5..e08fbeeb54b9ffecf77bc8cdfc5b5ad7b63455f7 100644 (file)
@@ -28,7 +28,7 @@ static struct task_struct *pick_next_task_stop(struct rq *rq)
        struct task_struct *stop = rq->stop;
 
        if (stop && stop->on_rq) {
-               stop->se.exec_start = rq->clock_task;
+               stop->se.exec_start = rq_clock_task(rq);
                return stop;
        }
 
@@ -57,7 +57,7 @@ static void put_prev_task_stop(struct rq *rq, struct task_struct *prev)
        struct task_struct *curr = rq->curr;
        u64 delta_exec;
 
-       delta_exec = rq->clock_task - curr->se.exec_start;
+       delta_exec = rq_clock_task(rq) - curr->se.exec_start;
        if (unlikely((s64)delta_exec < 0))
                delta_exec = 0;
 
@@ -67,7 +67,7 @@ static void put_prev_task_stop(struct rq *rq, struct task_struct *prev)
        curr->se.sum_exec_runtime += delta_exec;
        account_group_exec_runtime(curr, delta_exec);
 
-       curr->se.exec_start = rq->clock_task;
+       curr->se.exec_start = rq_clock_task(rq);
        cpuacct_charge(curr, delta_exec);
 }
 
@@ -79,7 +79,7 @@ static void set_curr_task_stop(struct rq *rq)
 {
        struct task_struct *stop = rq->stop;
 
-       stop->se.exec_start = rq->clock_task;
+       stop->se.exec_start = rq_clock_task(rq);
 }
 
 static void switched_to_stop(struct rq *rq, struct task_struct *p)
index 113411bfe8b1205ad0f26556776f2a317e06eb0c..50e41075ac77105fd26d190b2068929af6c4becc 100644 (file)
@@ -2848,7 +2848,7 @@ int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
                recalc_sigpending();
                spin_unlock_irq(&tsk->sighand->siglock);
 
-               timeout = schedule_timeout_interruptible(timeout);
+               timeout = freezable_schedule_timeout_interruptible(timeout);
 
                spin_lock_irq(&tsk->sighand->siglock);
                __set_task_blocked(tsk, &tsk->real_blocked);
index 3d6833f125d307214bae0210bd68cbaaa925755d..ca25e6e704a2f8ba1277fd3bd5975ed3518b09f7 100644 (file)
@@ -127,8 +127,7 @@ static inline void __local_bh_disable(unsigned long ip, unsigned int cnt)
 
 void local_bh_disable(void)
 {
-       __local_bh_disable((unsigned long)__builtin_return_address(0),
-                               SOFTIRQ_DISABLE_OFFSET);
+       __local_bh_disable(_RET_IP_, SOFTIRQ_DISABLE_OFFSET);
 }
 
 EXPORT_SYMBOL(local_bh_disable);
@@ -139,7 +138,7 @@ static void __local_bh_enable(unsigned int cnt)
        WARN_ON_ONCE(!irqs_disabled());
 
        if (softirq_count() == cnt)
-               trace_softirqs_on((unsigned long)__builtin_return_address(0));
+               trace_softirqs_on(_RET_IP_);
        sub_preempt_count(cnt);
 }
 
@@ -184,7 +183,7 @@ static inline void _local_bh_enable_ip(unsigned long ip)
 
 void local_bh_enable(void)
 {
-       _local_bh_enable_ip((unsigned long)__builtin_return_address(0));
+       _local_bh_enable_ip(_RET_IP_);
 }
 EXPORT_SYMBOL(local_bh_enable);
 
@@ -229,8 +228,7 @@ asmlinkage void __do_softirq(void)
        pending = local_softirq_pending();
        account_irq_enter_time(current);
 
-       __local_bh_disable((unsigned long)__builtin_return_address(0),
-                               SOFTIRQ_OFFSET);
+       __local_bh_disable(_RET_IP_, SOFTIRQ_OFFSET);
        lockdep_softirq_enter();
 
        cpu = smp_processor_id();
index 2bbd9a73b54c27b0e75eb651d931f0987ff870ed..071de900c824540abd7e42ee942e2ed89767643b 100644 (file)
@@ -511,7 +511,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
        case LINUX_REBOOT_CMD_HALT:
                kernel_halt();
                do_exit(0);
-               panic("cannot halt");
+               panic("cannot halt.\n");
 
        case LINUX_REBOOT_CMD_POWER_OFF:
                kernel_power_off();
@@ -1309,6 +1309,17 @@ out:
        return retval;
 }
 
+static void set_special_pids(struct pid *pid)
+{
+       struct task_struct *curr = current->group_leader;
+
+       if (task_session(curr) != pid)
+               change_pid(curr, PIDTYPE_SID, pid);
+
+       if (task_pgrp(curr) != pid)
+               change_pid(curr, PIDTYPE_PGID, pid);
+}
+
 SYSCALL_DEFINE0(setsid)
 {
        struct task_struct *group_leader = current->group_leader;
@@ -1328,7 +1339,7 @@ SYSCALL_DEFINE0(setsid)
                goto out;
 
        group_leader->signal->leader = 1;
-       __set_special_pids(sid);
+       set_special_pids(sid);
 
        proc_clear_tty(group_leader);
 
@@ -2355,8 +2366,7 @@ static int do_sysinfo(struct sysinfo *info)
 
        memset(info, 0, sizeof(struct sysinfo));
 
-       ktime_get_ts(&tp);
-       monotonic_to_bootbased(&tp);
+       get_monotonic_boottime(&tp);
        info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0);
 
        get_avenrun(info->loads, 0, SI_LOAD_SHIFT - FSHIFT);
index 9edcf456e0fcaa16e929b8a87c6229e33d24efa8..4ce13c3cedb97a8bb4eb402d02bc10f79c35245e 100644 (file)
@@ -120,7 +120,6 @@ extern int blk_iopoll_enabled;
 /* Constants used for minimum and  maximum */
 #ifdef CONFIG_LOCKUP_DETECTOR
 static int sixty = 60;
-static int neg_one = -1;
 #endif
 
 static int zero;
@@ -814,7 +813,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dowatchdog,
-               .extra1         = &neg_one,
+               .extra1         = &zero,
                .extra2         = &sixty,
        },
        {
@@ -1044,6 +1043,15 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = perf_proc_update_handler,
        },
+       {
+               .procname       = "perf_cpu_time_max_percent",
+               .data           = &sysctl_perf_cpu_time_max_percent,
+               .maxlen         = sizeof(sysctl_perf_cpu_time_max_percent),
+               .mode           = 0644,
+               .proc_handler   = perf_cpu_time_max_percent_handler,
+               .extra1         = &zero,
+               .extra2         = &one_hundred,
+       },
 #endif
 #ifdef CONFIG_KMEMCHECK
        {
index d3617dbd3dca6b3844e0814e889026f01af0ddd4..7c7964c33ae764b7f3ee29ed8045222986f6a53e 100644 (file)
@@ -11,7 +11,7 @@
  * Modification history kernel/time.c
  *
  * 1993-09-02    Philip Gladstone
- *      Created file with time related functions from sched.c and adjtimex()
+ *      Created file with time related functions from sched/core.c and adjtimex()
  * 1993-10-08    Torsten Duwe
  *      adjtime interface update and CMOS clock write code
  * 1995-08-13    Torsten Duwe
index ee8e29a2320c7c76d67df8f4816af52cd9da5f68..f02c4a4a0c3c8925f61c29982d87b6edcef7dd95 100644 (file)
@@ -272,6 +272,15 @@ static cpumask_var_t *wq_numa_possible_cpumask;
 static bool wq_disable_numa;
 module_param_named(disable_numa, wq_disable_numa, bool, 0444);
 
+/* see the comment above the definition of WQ_POWER_EFFICIENT */
+#ifdef CONFIG_WQ_POWER_EFFICIENT_DEFAULT
+static bool wq_power_efficient = true;
+#else
+static bool wq_power_efficient;
+#endif
+
+module_param_named(power_efficient, wq_power_efficient, bool, 0444);
+
 static bool wq_numa_enabled;           /* unbound NUMA affinity enabled */
 
 /* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */
@@ -305,6 +314,10 @@ struct workqueue_struct *system_unbound_wq __read_mostly;
 EXPORT_SYMBOL_GPL(system_unbound_wq);
 struct workqueue_struct *system_freezable_wq __read_mostly;
 EXPORT_SYMBOL_GPL(system_freezable_wq);
+struct workqueue_struct *system_power_efficient_wq __read_mostly;
+EXPORT_SYMBOL_GPL(system_power_efficient_wq);
+struct workqueue_struct *system_freezable_power_efficient_wq __read_mostly;
+EXPORT_SYMBOL_GPL(system_freezable_power_efficient_wq);
 
 static int worker_thread(void *__worker);
 static void copy_workqueue_attrs(struct workqueue_attrs *to,
@@ -4086,6 +4099,10 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
        struct workqueue_struct *wq;
        struct pool_workqueue *pwq;
 
+       /* see the comment above the definition of WQ_POWER_EFFICIENT */
+       if ((flags & WQ_POWER_EFFICIENT) && wq_power_efficient)
+               flags |= WQ_UNBOUND;
+
        /* allocate wq and format name */
        if (flags & WQ_UNBOUND)
                tbl_size = wq_numa_tbl_len * sizeof(wq->numa_pwq_tbl[0]);
@@ -4985,8 +5002,15 @@ static int __init init_workqueues(void)
                                            WQ_UNBOUND_MAX_ACTIVE);
        system_freezable_wq = alloc_workqueue("events_freezable",
                                              WQ_FREEZABLE, 0);
+       system_power_efficient_wq = alloc_workqueue("events_power_efficient",
+                                             WQ_POWER_EFFICIENT, 0);
+       system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_power_efficient",
+                                             WQ_FREEZABLE | WQ_POWER_EFFICIENT,
+                                             0);
        BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq ||
-              !system_unbound_wq || !system_freezable_wq);
+              !system_unbound_wq || !system_freezable_wq ||
+              !system_power_efficient_wq ||
+              !system_freezable_power_efficient_wq);
        return 0;
 }
 early_initcall(init_workqueues);
index ad83c96b2ece2d563b6d3125695534458fd6050e..7e2204db0b1a7a03c97e0147a1b416daf01aab00 100644 (file)
@@ -64,7 +64,7 @@ static inline struct worker *current_wq_worker(void)
 
 /*
  * Scheduler hooks for concurrency managed workqueue.  Only to be used from
- * sched.c and workqueue.c.
+ * sched/core.c and workqueue.c.
  */
 void wq_worker_waking_up(struct task_struct *task, int cpu);
 struct task_struct *wq_worker_sleeping(struct task_struct *task, int cpu);
index d246a3bbd6eff291d4f0ea3f43566c5b0da9685b..5a5203ded0dd5c570fb4ac94185b1a956ada6891 100644 (file)
@@ -410,4 +410,6 @@ config OID_REGISTRY
 config UCS2_STRING
         tristate
 
+source "lib/fonts/Kconfig"
+
 endmenu
index 566cf2bc08eaac44813dd9a1d1ac0d816a072237..7154f799541a41c5a4b7f3a351696d24b6e7db49 100644 (file)
@@ -547,6 +547,19 @@ config DEBUG_MUTEXES
         This feature allows mutex semantics violations to be detected and
         reported.
 
+config DEBUG_WW_MUTEX_SLOWPATH
+       bool "Wait/wound mutex debugging: Slowpath testing"
+       depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
+       select DEBUG_LOCK_ALLOC
+       select DEBUG_SPINLOCK
+       select DEBUG_MUTEXES
+       help
+        This feature enables slowpath testing for w/w mutex users by
+        injecting additional -EDEADLK wound/backoff cases. Together with
+        the full mutex checks enabled with (CONFIG_PROVE_LOCKING) this
+        will test all possible w/w mutex interface abuse with the
+        exception of simply not acquiring all the required locks.
+
 config DEBUG_LOCK_ALLOC
        bool "Lock debugging: detect incorrect freeing of live locks"
        depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
index 22f0f4e8a9e1bd9a1dcf4b8eb56012d53cacbbef..c09e38eca87ac5df2c6bf45ef33e6487cba1cd23 100644 (file)
@@ -13,7 +13,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
         sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
         proportions.o flex_proportions.o prio_heap.o ratelimit.o show_mem.o \
         is_single_threaded.o plist.o decompress.o kobject_uevent.o \
-        earlycpio.o
+        earlycpio.o percpu-refcount.o
 
 obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o
 lib-$(CONFIG_MMU) += ioremap.o
@@ -153,6 +153,8 @@ interval_tree_test-objs := interval_tree_test_main.o interval_tree.o
 
 obj-$(CONFIG_ASN1) += asn1_decoder.o
 
+obj-$(CONFIG_FONT_SUPPORT) += fonts/
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
index f2fa60c59343c2a26fd725c261331b6e8353f488..96c4c633d95e687d1c658dfa433273bbb3f81a66 100644 (file)
@@ -30,6 +30,7 @@ EXPORT_SYMBOL_GPL(debug_locks);
  * a locking bug is detected.
  */
 int debug_locks_silent;
+EXPORT_SYMBOL_GPL(debug_locks_silent);
 
 /*
  * Generic 'turn off all lock debugging' function:
@@ -44,3 +45,4 @@ int debug_locks_off(void)
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(debug_locks_off);
index 53bad099ebd6310cf5dfac7dc7ae44fc85df82c8..c03154173cc70cd2a240c137e55bb17f7d612434 100644 (file)
@@ -6,15 +6,58 @@
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/atomic.h>
+
+static void __dump_stack(void)
+{
+       dump_stack_print_info(KERN_DEFAULT);
+       show_stack(NULL, NULL);
+}
 
 /**
  * dump_stack - dump the current task information and its stack trace
  *
  * Architectures can override this implementation by implementing its own.
  */
+#ifdef CONFIG_SMP
+static atomic_t dump_lock = ATOMIC_INIT(-1);
+
 void dump_stack(void)
 {
-       dump_stack_print_info(KERN_DEFAULT);
-       show_stack(NULL, NULL);
+       int was_locked;
+       int old;
+       int cpu;
+
+       /*
+        * Permit this cpu to perform nested stack dumps while serialising
+        * against other CPUs
+        */
+       preempt_disable();
+
+retry:
+       cpu = smp_processor_id();
+       old = atomic_cmpxchg(&dump_lock, -1, cpu);
+       if (old == -1) {
+               was_locked = 0;
+       } else if (old == cpu) {
+               was_locked = 1;
+       } else {
+               cpu_relax();
+               goto retry;
+       }
+
+       __dump_stack();
+
+       if (!was_locked)
+               atomic_set(&dump_lock, -1);
+
+       preempt_enable();
+}
+#else
+void dump_stack(void)
+{
+       __dump_stack();
 }
+#endif
 EXPORT_SYMBOL(dump_stack);
diff --git a/lib/fonts/Kconfig b/lib/fonts/Kconfig
new file mode 100644 (file)
index 0000000..34fd931
--- /dev/null
@@ -0,0 +1,117 @@
+#
+# Font configuration
+#
+
+config FONT_SUPPORT
+       tristate
+
+if FONT_SUPPORT
+
+config FONTS
+       bool "Select compiled-in fonts"
+       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
+       help
+         Say Y here if you would like to use fonts other than the default
+         your frame buffer console usually use.
+
+         Note that the answer to this question won't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about foreign fonts.
+
+         If unsure, say N (the default choices are safe).
+
+config FONT_8x8
+       bool "VGA 8x8 font" if FONTS
+       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
+       default y if !SPARC && !FONTS
+       help
+         This is the "high resolution" font for the VGA frame buffer (the one
+         provided by the text console 80x50 (and higher) modes).
+
+         Note that this is a poor quality font. The VGA 8x16 font is quite a
+         lot more readable.
+
+         Given the resolution provided by the frame buffer device, answer N
+         here is safe.
+
+config FONT_8x16
+       bool "VGA 8x16 font" if FONTS
+       default y if !SPARC && !FONTS
+       help
+         This is the "high resolution" font for the VGA frame buffer (the one
+         provided by the VGA text console 80x25 mode.
+
+         If unsure, say Y.
+
+config FONT_6x11
+       bool "Mac console 6x11 font (not supported by all drivers)" if FONTS
+       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
+       default y if !SPARC && !FONTS && MAC
+       help
+         Small console font with Macintosh-style high-half glyphs.  Some Mac
+         framebuffer drivers don't support this one at all.
+
+config FONT_7x14
+       bool "console 7x14 font (not supported by all drivers)" if FONTS
+       depends on FRAMEBUFFER_CONSOLE
+       help
+         Console font with characters just a bit smaller than the default.
+         If the standard 8x16 font is a little too big for you, say Y.
+         Otherwise, say N.
+
+config FONT_PEARL_8x8
+       bool "Pearl (old m68k) console 8x8 font" if FONTS
+       depends on FRAMEBUFFER_CONSOLE
+       default y if !SPARC && !FONTS && AMIGA
+       help
+         Small console font with PC-style control-character and high-half
+         glyphs.
+
+config FONT_ACORN_8x8
+       bool "Acorn console 8x8 font" if FONTS
+       depends on FRAMEBUFFER_CONSOLE
+       default y if !SPARC && !FONTS && ARM && ARCH_ACORN
+       help
+         Small console font with PC-style control characters and high-half
+         glyphs.
+
+config FONT_MINI_4x6
+       bool "Mini 4x6 font"
+       depends on !SPARC && FONTS
+
+config FONT_SUN8x16
+       bool "Sparc console 8x16 font"
+       depends on FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC)
+       help
+         This is the high resolution console font for Sun machines. Say Y.
+
+config FONT_SUN12x22
+       bool "Sparc console 12x22 font (not supported by all drivers)"
+       depends on FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC)
+       help
+         This is the high resolution console font for Sun machines with very
+         big letters (like the letters used in the SPARC PROM). If the
+         standard font is unreadable for you, say Y, otherwise say N.
+
+config FONT_10x18
+       bool "console 10x18 font (not supported by all drivers)" if FONTS
+       depends on FRAMEBUFFER_CONSOLE
+       help
+         This is a high resolution console font for machines with very
+         big letters. It fits between the sun 12x22 and the normal 8x16 font.
+         If other fonts are too big or too small for you, say Y, otherwise say N.
+
+config FONT_AUTOSELECT
+       def_bool y
+       depends on !FONT_8x8
+       depends on !FONT_6x11
+       depends on !FONT_7x14
+       depends on !FONT_PEARL_8x8
+       depends on !FONT_ACORN_8x8
+       depends on !FONT_MINI_4x6
+       depends on !FONT_SUN8x16
+       depends on !FONT_SUN12x22
+       depends on !FONT_10x18
+       select FONT_8x16
+
+endif # FONT_SUPPORT
diff --git a/lib/fonts/Makefile b/lib/fonts/Makefile
new file mode 100644 (file)
index 0000000..2761560
--- /dev/null
@@ -0,0 +1,18 @@
+# Font handling
+
+font-objs := fonts.o
+
+font-objs-$(CONFIG_FONT_SUN8x16)   += font_sun8x16.o
+font-objs-$(CONFIG_FONT_SUN12x22)  += font_sun12x22.o
+font-objs-$(CONFIG_FONT_8x8)       += font_8x8.o
+font-objs-$(CONFIG_FONT_8x16)      += font_8x16.o
+font-objs-$(CONFIG_FONT_6x11)      += font_6x11.o
+font-objs-$(CONFIG_FONT_7x14)      += font_7x14.o
+font-objs-$(CONFIG_FONT_10x18)     += font_10x18.o
+font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o
+font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o
+font-objs-$(CONFIG_FONT_MINI_4x6)  += font_mini_4x6.o
+
+font-objs += $(font-objs-y)
+
+obj-$(CONFIG_FONT_SUPPORT)         += font.o
similarity index 98%
rename from drivers/video/console/fonts.c
rename to lib/fonts/fonts.c
index d0c03fd7087141359d3d733791bbca2020de0de0..f947189efe6d4b961c940b7f0fa2876a6b6938e6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/video/fonts.c -- `Soft' font definitions
+ * `Soft' font definitions
  *
  *    Created 1995 by Geert Uytterhoeven
  *    Rewritten 1998 by Martin Mares <mj@ucw.cz>
index cca4b9302a710c5ef0e1a66355302040ada9d3d7..bfe4db4e165f2941654e5ba551fbc8c3fe0a467c 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -524,9 +524,7 @@ EXPORT_SYMBOL(idr_alloc_cyclic);
 
 static void idr_remove_warning(int id)
 {
-       printk(KERN_WARNING
-               "idr_remove called for id=%d which is not allocated.\n", id);
-       dump_stack();
+       WARN(1, "idr_remove called for id=%d which is not allocated.\n", id);
 }
 
 static void sub_remove(struct idr *idp, int shift, int id)
@@ -1064,8 +1062,7 @@ void ida_remove(struct ida *ida, int id)
        return;
 
  err:
-       printk(KERN_WARNING
-              "ida_remove called for id=%d which is not allocated.\n", id);
+       WARN(1, "ida_remove called for id=%d which is not allocated.\n", id);
 }
 EXPORT_SYMBOL(ida_remove);
 
index c3eb261a7df369a5bfbb0834566001fabb583e12..aad024dde3c476c9865c1153fd8d57de266d4dd9 100644 (file)
@@ -26,6 +26,8 @@
  */
 static unsigned int debug_locks_verbose;
 
+static DEFINE_WW_CLASS(ww_lockdep);
+
 static int __init setup_debug_locks_verbose(char *str)
 {
        get_option(&str, &debug_locks_verbose);
@@ -42,6 +44,10 @@ __setup("debug_locks_verbose=", setup_debug_locks_verbose);
 #define LOCKTYPE_RWLOCK        0x2
 #define LOCKTYPE_MUTEX 0x4
 #define LOCKTYPE_RWSEM 0x8
+#define LOCKTYPE_WW    0x10
+
+static struct ww_acquire_ctx t, t2;
+static struct ww_mutex o, o2, o3;
 
 /*
  * Normal standalone locks, for the circular and irq-context
@@ -193,6 +199,20 @@ static void init_shared_classes(void)
 #define RSU(x)                 up_read(&rwsem_##x)
 #define RWSI(x)                        init_rwsem(&rwsem_##x)
 
+#ifndef CONFIG_DEBUG_WW_MUTEX_SLOWPATH
+#define WWAI(x)                        ww_acquire_init(x, &ww_lockdep)
+#else
+#define WWAI(x)                        do { ww_acquire_init(x, &ww_lockdep); (x)->deadlock_inject_countdown = ~0U; } while (0)
+#endif
+#define WWAD(x)                        ww_acquire_done(x)
+#define WWAF(x)                        ww_acquire_fini(x)
+
+#define WWL(x, c)              ww_mutex_lock(x, c)
+#define WWT(x)                 ww_mutex_trylock(x)
+#define WWL1(x)                        ww_mutex_lock(x, NULL)
+#define WWU(x)                 ww_mutex_unlock(x)
+
+
 #define LOCK_UNLOCK_2(x,y)     LOCK(x); LOCK(y); UNLOCK(y); UNLOCK(x)
 
 /*
@@ -894,11 +914,13 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft)
 # define I_RWLOCK(x)   lockdep_reset_lock(&rwlock_##x.dep_map)
 # define I_MUTEX(x)    lockdep_reset_lock(&mutex_##x.dep_map)
 # define I_RWSEM(x)    lockdep_reset_lock(&rwsem_##x.dep_map)
+# define I_WW(x)       lockdep_reset_lock(&x.dep_map)
 #else
 # define I_SPINLOCK(x)
 # define I_RWLOCK(x)
 # define I_MUTEX(x)
 # define I_RWSEM(x)
+# define I_WW(x)
 #endif
 
 #define I1(x)                                  \
@@ -920,11 +942,20 @@ GENERATE_PERMUTATIONS_3_EVENTS(irq_read_recursion_soft)
 static void reset_locks(void)
 {
        local_irq_disable();
+       lockdep_free_key_range(&ww_lockdep.acquire_key, 1);
+       lockdep_free_key_range(&ww_lockdep.mutex_key, 1);
+
        I1(A); I1(B); I1(C); I1(D);
        I1(X1); I1(X2); I1(Y1); I1(Y2); I1(Z1); I1(Z2);
+       I_WW(t); I_WW(t2); I_WW(o.base); I_WW(o2.base); I_WW(o3.base);
        lockdep_reset();
        I2(A); I2(B); I2(C); I2(D);
        init_shared_classes();
+
+       ww_mutex_init(&o, &ww_lockdep); ww_mutex_init(&o2, &ww_lockdep); ww_mutex_init(&o3, &ww_lockdep);
+       memset(&t, 0, sizeof(t)); memset(&t2, 0, sizeof(t2));
+       memset(&ww_lockdep.acquire_key, 0, sizeof(ww_lockdep.acquire_key));
+       memset(&ww_lockdep.mutex_key, 0, sizeof(ww_lockdep.mutex_key));
        local_irq_enable();
 }
 
@@ -938,7 +969,6 @@ static int unexpected_testcase_failures;
 static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask)
 {
        unsigned long saved_preempt_count = preempt_count();
-       int expected_failure = 0;
 
        WARN_ON(irqs_disabled());
 
@@ -947,25 +977,17 @@ static void dotest(void (*testcase_fn)(void), int expected, int lockclass_mask)
         * Filter out expected failures:
         */
 #ifndef CONFIG_PROVE_LOCKING
-       if ((lockclass_mask & LOCKTYPE_SPIN) && debug_locks != expected)
-               expected_failure = 1;
-       if ((lockclass_mask & LOCKTYPE_RWLOCK) && debug_locks != expected)
-               expected_failure = 1;
-       if ((lockclass_mask & LOCKTYPE_MUTEX) && debug_locks != expected)
-               expected_failure = 1;
-       if ((lockclass_mask & LOCKTYPE_RWSEM) && debug_locks != expected)
-               expected_failure = 1;
+       if (expected == FAILURE && debug_locks) {
+               expected_testcase_failures++;
+               printk("failed|");
+       }
+       else
 #endif
        if (debug_locks != expected) {
-               if (expected_failure) {
-                       expected_testcase_failures++;
-                       printk("failed|");
-               } else {
-                       unexpected_testcase_failures++;
-
-                       printk("FAILED|");
-                       dump_stack();
-               }
+               unexpected_testcase_failures++;
+               printk("FAILED|");
+
+               dump_stack();
        } else {
                testcase_successes++;
                printk("  ok  |");
@@ -1108,6 +1130,666 @@ static inline void print_testname(const char *testname)
        DO_TESTCASE_6IRW(desc, name, 312);                      \
        DO_TESTCASE_6IRW(desc, name, 321);
 
+static void ww_test_fail_acquire(void)
+{
+       int ret;
+
+       WWAI(&t);
+       t.stamp++;
+
+       ret = WWL(&o, &t);
+
+       if (WARN_ON(!o.ctx) ||
+           WARN_ON(ret))
+               return;
+
+       /* No lockdep test, pure API */
+       ret = WWL(&o, &t);
+       WARN_ON(ret != -EALREADY);
+
+       ret = WWT(&o);
+       WARN_ON(ret);
+
+       t2 = t;
+       t2.stamp++;
+       ret = WWL(&o, &t2);
+       WARN_ON(ret != -EDEADLK);
+       WWU(&o);
+
+       if (WWT(&o))
+               WWU(&o);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       else
+               DEBUG_LOCKS_WARN_ON(1);
+#endif
+}
+
+static void ww_test_normal(void)
+{
+       int ret;
+
+       WWAI(&t);
+
+       /*
+        * None of the ww_mutex codepaths should be taken in the 'normal'
+        * mutex calls. The easiest way to verify this is by using the
+        * normal mutex calls, and making sure o.ctx is unmodified.
+        */
+
+       /* mutex_lock (and indirectly, mutex_lock_nested) */
+       o.ctx = (void *)~0UL;
+       mutex_lock(&o.base);
+       mutex_unlock(&o.base);
+       WARN_ON(o.ctx != (void *)~0UL);
+
+       /* mutex_lock_interruptible (and *_nested) */
+       o.ctx = (void *)~0UL;
+       ret = mutex_lock_interruptible(&o.base);
+       if (!ret)
+               mutex_unlock(&o.base);
+       else
+               WARN_ON(1);
+       WARN_ON(o.ctx != (void *)~0UL);
+
+       /* mutex_lock_killable (and *_nested) */
+       o.ctx = (void *)~0UL;
+       ret = mutex_lock_killable(&o.base);
+       if (!ret)
+               mutex_unlock(&o.base);
+       else
+               WARN_ON(1);
+       WARN_ON(o.ctx != (void *)~0UL);
+
+       /* trylock, succeeding */
+       o.ctx = (void *)~0UL;
+       ret = mutex_trylock(&o.base);
+       WARN_ON(!ret);
+       if (ret)
+               mutex_unlock(&o.base);
+       else
+               WARN_ON(1);
+       WARN_ON(o.ctx != (void *)~0UL);
+
+       /* trylock, failing */
+       o.ctx = (void *)~0UL;
+       mutex_lock(&o.base);
+       ret = mutex_trylock(&o.base);
+       WARN_ON(ret);
+       mutex_unlock(&o.base);
+       WARN_ON(o.ctx != (void *)~0UL);
+
+       /* nest_lock */
+       o.ctx = (void *)~0UL;
+       mutex_lock_nest_lock(&o.base, &t);
+       mutex_unlock(&o.base);
+       WARN_ON(o.ctx != (void *)~0UL);
+}
+
+static void ww_test_two_contexts(void)
+{
+       WWAI(&t);
+       WWAI(&t2);
+}
+
+static void ww_test_diff_class(void)
+{
+       WWAI(&t);
+#ifdef CONFIG_DEBUG_MUTEXES
+       t.ww_class = NULL;
+#endif
+       WWL(&o, &t);
+}
+
+static void ww_test_context_done_twice(void)
+{
+       WWAI(&t);
+       WWAD(&t);
+       WWAD(&t);
+       WWAF(&t);
+}
+
+static void ww_test_context_unlock_twice(void)
+{
+       WWAI(&t);
+       WWAD(&t);
+       WWAF(&t);
+       WWAF(&t);
+}
+
+static void ww_test_context_fini_early(void)
+{
+       WWAI(&t);
+       WWL(&o, &t);
+       WWAD(&t);
+       WWAF(&t);
+}
+
+static void ww_test_context_lock_after_done(void)
+{
+       WWAI(&t);
+       WWAD(&t);
+       WWL(&o, &t);
+}
+
+static void ww_test_object_unlock_twice(void)
+{
+       WWL1(&o);
+       WWU(&o);
+       WWU(&o);
+}
+
+static void ww_test_object_lock_unbalanced(void)
+{
+       WWAI(&t);
+       WWL(&o, &t);
+       t.acquired = 0;
+       WWU(&o);
+       WWAF(&t);
+}
+
+static void ww_test_object_lock_stale_context(void)
+{
+       WWAI(&t);
+       o.ctx = &t2;
+       WWL(&o, &t);
+}
+
+static void ww_test_edeadlk_normal(void)
+{
+       int ret;
+
+       mutex_lock(&o2.base);
+       o2.ctx = &t2;
+       mutex_release(&o2.base.dep_map, 1, _THIS_IP_);
+
+       WWAI(&t);
+       t2 = t;
+       t2.stamp--;
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret != -EDEADLK);
+
+       o2.ctx = NULL;
+       mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_);
+       mutex_unlock(&o2.base);
+       WWU(&o);
+
+       WWL(&o2, &t);
+}
+
+static void ww_test_edeadlk_normal_slow(void)
+{
+       int ret;
+
+       mutex_lock(&o2.base);
+       mutex_release(&o2.base.dep_map, 1, _THIS_IP_);
+       o2.ctx = &t2;
+
+       WWAI(&t);
+       t2 = t;
+       t2.stamp--;
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret != -EDEADLK);
+
+       o2.ctx = NULL;
+       mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_);
+       mutex_unlock(&o2.base);
+       WWU(&o);
+
+       ww_mutex_lock_slow(&o2, &t);
+}
+
+static void ww_test_edeadlk_no_unlock(void)
+{
+       int ret;
+
+       mutex_lock(&o2.base);
+       o2.ctx = &t2;
+       mutex_release(&o2.base.dep_map, 1, _THIS_IP_);
+
+       WWAI(&t);
+       t2 = t;
+       t2.stamp--;
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret != -EDEADLK);
+
+       o2.ctx = NULL;
+       mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_);
+       mutex_unlock(&o2.base);
+
+       WWL(&o2, &t);
+}
+
+static void ww_test_edeadlk_no_unlock_slow(void)
+{
+       int ret;
+
+       mutex_lock(&o2.base);
+       mutex_release(&o2.base.dep_map, 1, _THIS_IP_);
+       o2.ctx = &t2;
+
+       WWAI(&t);
+       t2 = t;
+       t2.stamp--;
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret != -EDEADLK);
+
+       o2.ctx = NULL;
+       mutex_acquire(&o2.base.dep_map, 0, 1, _THIS_IP_);
+       mutex_unlock(&o2.base);
+
+       ww_mutex_lock_slow(&o2, &t);
+}
+
+static void ww_test_edeadlk_acquire_more(void)
+{
+       int ret;
+
+       mutex_lock(&o2.base);
+       mutex_release(&o2.base.dep_map, 1, _THIS_IP_);
+       o2.ctx = &t2;
+
+       WWAI(&t);
+       t2 = t;
+       t2.stamp--;
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret != -EDEADLK);
+
+       ret = WWL(&o3, &t);
+}
+
+static void ww_test_edeadlk_acquire_more_slow(void)
+{
+       int ret;
+
+       mutex_lock(&o2.base);
+       mutex_release(&o2.base.dep_map, 1, _THIS_IP_);
+       o2.ctx = &t2;
+
+       WWAI(&t);
+       t2 = t;
+       t2.stamp--;
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret != -EDEADLK);
+
+       ww_mutex_lock_slow(&o3, &t);
+}
+
+static void ww_test_edeadlk_acquire_more_edeadlk(void)
+{
+       int ret;
+
+       mutex_lock(&o2.base);
+       mutex_release(&o2.base.dep_map, 1, _THIS_IP_);
+       o2.ctx = &t2;
+
+       mutex_lock(&o3.base);
+       mutex_release(&o3.base.dep_map, 1, _THIS_IP_);
+       o3.ctx = &t2;
+
+       WWAI(&t);
+       t2 = t;
+       t2.stamp--;
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret != -EDEADLK);
+
+       ret = WWL(&o3, &t);
+       WARN_ON(ret != -EDEADLK);
+}
+
+static void ww_test_edeadlk_acquire_more_edeadlk_slow(void)
+{
+       int ret;
+
+       mutex_lock(&o2.base);
+       mutex_release(&o2.base.dep_map, 1, _THIS_IP_);
+       o2.ctx = &t2;
+
+       mutex_lock(&o3.base);
+       mutex_release(&o3.base.dep_map, 1, _THIS_IP_);
+       o3.ctx = &t2;
+
+       WWAI(&t);
+       t2 = t;
+       t2.stamp--;
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret != -EDEADLK);
+
+       ww_mutex_lock_slow(&o3, &t);
+}
+
+static void ww_test_edeadlk_acquire_wrong(void)
+{
+       int ret;
+
+       mutex_lock(&o2.base);
+       mutex_release(&o2.base.dep_map, 1, _THIS_IP_);
+       o2.ctx = &t2;
+
+       WWAI(&t);
+       t2 = t;
+       t2.stamp--;
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret != -EDEADLK);
+       if (!ret)
+               WWU(&o2);
+
+       WWU(&o);
+
+       ret = WWL(&o3, &t);
+}
+
+static void ww_test_edeadlk_acquire_wrong_slow(void)
+{
+       int ret;
+
+       mutex_lock(&o2.base);
+       mutex_release(&o2.base.dep_map, 1, _THIS_IP_);
+       o2.ctx = &t2;
+
+       WWAI(&t);
+       t2 = t;
+       t2.stamp--;
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret != -EDEADLK);
+       if (!ret)
+               WWU(&o2);
+
+       WWU(&o);
+
+       ww_mutex_lock_slow(&o3, &t);
+}
+
+static void ww_test_spin_nest_unlocked(void)
+{
+       raw_spin_lock_nest_lock(&lock_A, &o.base);
+       U(A);
+}
+
+static void ww_test_unneeded_slow(void)
+{
+       WWAI(&t);
+
+       ww_mutex_lock_slow(&o, &t);
+}
+
+static void ww_test_context_block(void)
+{
+       int ret;
+
+       WWAI(&t);
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+       WWL1(&o2);
+}
+
+static void ww_test_context_try(void)
+{
+       int ret;
+
+       WWAI(&t);
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWT(&o2);
+       WARN_ON(!ret);
+       WWU(&o2);
+       WWU(&o);
+}
+
+static void ww_test_context_context(void)
+{
+       int ret;
+
+       WWAI(&t);
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret);
+
+       WWU(&o2);
+       WWU(&o);
+}
+
+static void ww_test_try_block(void)
+{
+       bool ret;
+
+       ret = WWT(&o);
+       WARN_ON(!ret);
+
+       WWL1(&o2);
+       WWU(&o2);
+       WWU(&o);
+}
+
+static void ww_test_try_try(void)
+{
+       bool ret;
+
+       ret = WWT(&o);
+       WARN_ON(!ret);
+       ret = WWT(&o2);
+       WARN_ON(!ret);
+       WWU(&o2);
+       WWU(&o);
+}
+
+static void ww_test_try_context(void)
+{
+       int ret;
+
+       ret = WWT(&o);
+       WARN_ON(!ret);
+
+       WWAI(&t);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret);
+}
+
+static void ww_test_block_block(void)
+{
+       WWL1(&o);
+       WWL1(&o2);
+}
+
+static void ww_test_block_try(void)
+{
+       bool ret;
+
+       WWL1(&o);
+       ret = WWT(&o2);
+       WARN_ON(!ret);
+}
+
+static void ww_test_block_context(void)
+{
+       int ret;
+
+       WWL1(&o);
+       WWAI(&t);
+
+       ret = WWL(&o2, &t);
+       WARN_ON(ret);
+}
+
+static void ww_test_spin_block(void)
+{
+       L(A);
+       U(A);
+
+       WWL1(&o);
+       L(A);
+       U(A);
+       WWU(&o);
+
+       L(A);
+       WWL1(&o);
+       WWU(&o);
+       U(A);
+}
+
+static void ww_test_spin_try(void)
+{
+       bool ret;
+
+       L(A);
+       U(A);
+
+       ret = WWT(&o);
+       WARN_ON(!ret);
+       L(A);
+       U(A);
+       WWU(&o);
+
+       L(A);
+       ret = WWT(&o);
+       WARN_ON(!ret);
+       WWU(&o);
+       U(A);
+}
+
+static void ww_test_spin_context(void)
+{
+       int ret;
+
+       L(A);
+       U(A);
+
+       WWAI(&t);
+
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+       L(A);
+       U(A);
+       WWU(&o);
+
+       L(A);
+       ret = WWL(&o, &t);
+       WARN_ON(ret);
+       WWU(&o);
+       U(A);
+}
+
+static void ww_tests(void)
+{
+       printk("  --------------------------------------------------------------------------\n");
+       printk("  | Wound/wait tests |\n");
+       printk("  ---------------------\n");
+
+       print_testname("ww api failures");
+       dotest(ww_test_fail_acquire, SUCCESS, LOCKTYPE_WW);
+       dotest(ww_test_normal, SUCCESS, LOCKTYPE_WW);
+       dotest(ww_test_unneeded_slow, FAILURE, LOCKTYPE_WW);
+       printk("\n");
+
+       print_testname("ww contexts mixing");
+       dotest(ww_test_two_contexts, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_diff_class, FAILURE, LOCKTYPE_WW);
+       printk("\n");
+
+       print_testname("finishing ww context");
+       dotest(ww_test_context_done_twice, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_context_unlock_twice, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_context_fini_early, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_context_lock_after_done, FAILURE, LOCKTYPE_WW);
+       printk("\n");
+
+       print_testname("locking mismatches");
+       dotest(ww_test_object_unlock_twice, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_object_lock_unbalanced, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_object_lock_stale_context, FAILURE, LOCKTYPE_WW);
+       printk("\n");
+
+       print_testname("EDEADLK handling");
+       dotest(ww_test_edeadlk_normal, SUCCESS, LOCKTYPE_WW);
+       dotest(ww_test_edeadlk_normal_slow, SUCCESS, LOCKTYPE_WW);
+       dotest(ww_test_edeadlk_no_unlock, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_edeadlk_no_unlock_slow, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_edeadlk_acquire_more, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_edeadlk_acquire_more_slow, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_edeadlk_acquire_more_edeadlk, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_edeadlk_acquire_more_edeadlk_slow, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_edeadlk_acquire_wrong, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_edeadlk_acquire_wrong_slow, FAILURE, LOCKTYPE_WW);
+       printk("\n");
+
+       print_testname("spinlock nest unlocked");
+       dotest(ww_test_spin_nest_unlocked, FAILURE, LOCKTYPE_WW);
+       printk("\n");
+
+       printk("  -----------------------------------------------------\n");
+       printk("                                 |block | try  |context|\n");
+       printk("  -----------------------------------------------------\n");
+
+       print_testname("context");
+       dotest(ww_test_context_block, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_context_try, SUCCESS, LOCKTYPE_WW);
+       dotest(ww_test_context_context, SUCCESS, LOCKTYPE_WW);
+       printk("\n");
+
+       print_testname("try");
+       dotest(ww_test_try_block, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_try_try, SUCCESS, LOCKTYPE_WW);
+       dotest(ww_test_try_context, FAILURE, LOCKTYPE_WW);
+       printk("\n");
+
+       print_testname("block");
+       dotest(ww_test_block_block, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_block_try, SUCCESS, LOCKTYPE_WW);
+       dotest(ww_test_block_context, FAILURE, LOCKTYPE_WW);
+       printk("\n");
+
+       print_testname("spinlock");
+       dotest(ww_test_spin_block, FAILURE, LOCKTYPE_WW);
+       dotest(ww_test_spin_try, SUCCESS, LOCKTYPE_WW);
+       dotest(ww_test_spin_context, FAILURE, LOCKTYPE_WW);
+       printk("\n");
+}
 
 void locking_selftest(void)
 {
@@ -1188,6 +1870,8 @@ void locking_selftest(void)
        DO_TESTCASE_6x2("irq read-recursion", irq_read_recursion);
 //     DO_TESTCASE_6x2B("irq read-recursion #2", irq_read_recursion2);
 
+       ww_tests();
+
        if (unexpected_testcase_failures) {
                printk("-----------------------------------------------------------------\n");
                debug_locks = 0;
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c
new file mode 100644 (file)
index 0000000..7deeb62
--- /dev/null
@@ -0,0 +1,158 @@
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#include <linux/kernel.h>
+#include <linux/percpu-refcount.h>
+
+/*
+ * Initially, a percpu refcount is just a set of percpu counters. Initially, we
+ * don't try to detect the ref hitting 0 - which means that get/put can just
+ * increment or decrement the local counter. Note that the counter on a
+ * particular cpu can (and will) wrap - this is fine, when we go to shutdown the
+ * percpu counters will all sum to the correct value
+ *
+ * (More precisely: because moduler arithmatic is commutative the sum of all the
+ * pcpu_count vars will be equal to what it would have been if all the gets and
+ * puts were done to a single integer, even if some of the percpu integers
+ * overflow or underflow).
+ *
+ * The real trick to implementing percpu refcounts is shutdown. We can't detect
+ * the ref hitting 0 on every put - this would require global synchronization
+ * and defeat the whole purpose of using percpu refs.
+ *
+ * What we do is require the user to keep track of the initial refcount; we know
+ * the ref can't hit 0 before the user drops the initial ref, so as long as we
+ * convert to non percpu mode before the initial ref is dropped everything
+ * works.
+ *
+ * Converting to non percpu mode is done with some RCUish stuff in
+ * percpu_ref_kill. Additionally, we need a bias value so that the atomic_t
+ * can't hit 0 before we've added up all the percpu refs.
+ */
+
+#define PCPU_COUNT_BIAS                (1U << 31)
+
+/**
+ * percpu_ref_init - initialize a percpu refcount
+ * @ref: percpu_ref to initialize
+ * @release: function which will be called when refcount hits 0
+ *
+ * Initializes the refcount in single atomic counter mode with a refcount of 1;
+ * analagous to atomic_set(ref, 1).
+ *
+ * Note that @release must not sleep - it may potentially be called from RCU
+ * callback context by percpu_ref_kill().
+ */
+int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release)
+{
+       atomic_set(&ref->count, 1 + PCPU_COUNT_BIAS);
+
+       ref->pcpu_count = alloc_percpu(unsigned);
+       if (!ref->pcpu_count)
+               return -ENOMEM;
+
+       ref->release = release;
+       return 0;
+}
+
+/**
+ * percpu_ref_cancel_init - cancel percpu_ref_init()
+ * @ref: percpu_ref to cancel init for
+ *
+ * Once a percpu_ref is initialized, its destruction is initiated by
+ * percpu_ref_kill() and completes asynchronously, which can be painful to
+ * do when destroying a half-constructed object in init failure path.
+ *
+ * This function destroys @ref without invoking @ref->release and the
+ * memory area containing it can be freed immediately on return.  To
+ * prevent accidental misuse, it's required that @ref has finished
+ * percpu_ref_init(), whether successful or not, but never used.
+ *
+ * The weird name and usage restriction are to prevent people from using
+ * this function by mistake for normal shutdown instead of
+ * percpu_ref_kill().
+ */
+void percpu_ref_cancel_init(struct percpu_ref *ref)
+{
+       unsigned __percpu *pcpu_count = ref->pcpu_count;
+       int cpu;
+
+       WARN_ON_ONCE(atomic_read(&ref->count) != 1 + PCPU_COUNT_BIAS);
+
+       if (pcpu_count) {
+               for_each_possible_cpu(cpu)
+                       WARN_ON_ONCE(*per_cpu_ptr(pcpu_count, cpu));
+               free_percpu(ref->pcpu_count);
+       }
+}
+
+static void percpu_ref_kill_rcu(struct rcu_head *rcu)
+{
+       struct percpu_ref *ref = container_of(rcu, struct percpu_ref, rcu);
+       unsigned __percpu *pcpu_count = ref->pcpu_count;
+       unsigned count = 0;
+       int cpu;
+
+       /* Mask out PCPU_REF_DEAD */
+       pcpu_count = (unsigned __percpu *)
+               (((unsigned long) pcpu_count) & ~PCPU_STATUS_MASK);
+
+       for_each_possible_cpu(cpu)
+               count += *per_cpu_ptr(pcpu_count, cpu);
+
+       free_percpu(pcpu_count);
+
+       pr_debug("global %i pcpu %i", atomic_read(&ref->count), (int) count);
+
+       /*
+        * It's crucial that we sum the percpu counters _before_ adding the sum
+        * to &ref->count; since gets could be happening on one cpu while puts
+        * happen on another, adding a single cpu's count could cause
+        * @ref->count to hit 0 before we've got a consistent value - but the
+        * sum of all the counts will be consistent and correct.
+        *
+        * Subtracting the bias value then has to happen _after_ adding count to
+        * &ref->count; we need the bias value to prevent &ref->count from
+        * reaching 0 before we add the percpu counts. But doing it at the same
+        * time is equivalent and saves us atomic operations:
+        */
+
+       atomic_add((int) count - PCPU_COUNT_BIAS, &ref->count);
+
+       /* @ref is viewed as dead on all CPUs, send out kill confirmation */
+       if (ref->confirm_kill)
+               ref->confirm_kill(ref);
+
+       /*
+        * Now we're in single atomic_t mode with a consistent refcount, so it's
+        * safe to drop our initial ref:
+        */
+       percpu_ref_put(ref);
+}
+
+/**
+ * percpu_ref_kill_and_confirm - drop the initial ref and schedule confirmation
+ * @ref: percpu_ref to kill
+ * @confirm_kill: optional confirmation callback
+ *
+ * Equivalent to percpu_ref_kill() but also schedules kill confirmation if
+ * @confirm_kill is not NULL.  @confirm_kill, which may not block, will be
+ * called after @ref is seen as dead from all CPUs - all further
+ * invocations of percpu_ref_tryget() will fail.  See percpu_ref_tryget()
+ * for more details.
+ *
+ * Due to the way percpu_ref is implemented, @confirm_kill will be called
+ * after at least one full RCU grace period has passed but this is an
+ * implementation detail and callers must not depend on it.
+ */
+void percpu_ref_kill_and_confirm(struct percpu_ref *ref,
+                                percpu_ref_func_t *confirm_kill)
+{
+       WARN_ONCE(REF_STATUS(ref->pcpu_count) == PCPU_REF_DEAD,
+                 "percpu_ref_kill() called more than once!\n");
+
+       ref->pcpu_count = (unsigned __percpu *)
+               (((unsigned long) ref->pcpu_count)|PCPU_REF_DEAD);
+       ref->confirm_kill = confirm_kill;
+
+       call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu);
+}
index ba6085d9c7411f33bbb6aa0077423e822ad1c3dc..1fc23a3277e13794eca7d230ae2ff79aa9c1e4b5 100644 (file)
@@ -80,8 +80,8 @@ void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
        if (count >= batch || count <= -batch) {
                raw_spin_lock(&fbc->lock);
                fbc->count += count;
-               __this_cpu_write(*fbc->counters, 0);
                raw_spin_unlock(&fbc->lock);
+               __this_cpu_write(*fbc->counters, 0);
        } else {
                __this_cpu_write(*fbc->counters, count);
        }
index f5e698e30d4a230f6fe0b45e92892483507f3ade..7e28ecfa8aa42663ba3153a984ee1dbe69f7e96b 100644 (file)
@@ -477,3 +477,15 @@ config FRONTSWAP
          and swap data is stored as normal on the matching swap device.
 
          If unsure, say Y to enable frontswap.
+
+config MEM_SOFT_DIRTY
+       bool "Track memory changes"
+       depends on CHECKPOINT_RESTORE && HAVE_ARCH_SOFT_DIRTY
+       select PROC_PAGE_MONITOR
+       help
+         This option enables memory changes tracking by introducing a
+         soft-dirty bit on pte-s. This bit it set when someone writes
+         into a page just as regular dirty bit, but unlike the latter
+         it can be cleared by hands.
+
+         See Documentation/vm/soft-dirty.txt for more details.
index 50251749225885d958a1b531519326bd177ecf2e..d014ee5fcbbd2fa8004ae642f83571ddd949a5e6 100644 (file)
@@ -515,7 +515,6 @@ EXPORT_SYMBOL(bdi_destroy);
 int bdi_setup_and_register(struct backing_dev_info *bdi, char *name,
                           unsigned int cap)
 {
-       char tmp[32];
        int err;
 
        bdi->name = name;
@@ -524,8 +523,8 @@ int bdi_setup_and_register(struct backing_dev_info *bdi, char *name,
        if (err)
                return err;
 
-       sprintf(tmp, "%.28s%s", name, "-%d");
-       err = bdi_register(bdi, NULL, tmp, atomic_long_inc_return(&bdi_seq));
+       err = bdi_register(bdi, NULL, "%.28s-%ld", name,
+                          atomic_long_inc_return(&bdi_seq));
        if (err) {
                bdi_destroy(bdi);
                return err;
index 2b0bcb019ec222b8d56be811866e421a6287f13b..6ab7744e692ed86cd4417041686dc3a0821cab9f 100644 (file)
@@ -241,33 +241,26 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
        return count;
 }
 
-static void reset_node_lowmem_managed_pages(pg_data_t *pgdat)
+static int reset_managed_pages_done __initdata;
+
+static inline void __init reset_node_managed_pages(pg_data_t *pgdat)
 {
        struct zone *z;
 
-       /*
-        * In free_area_init_core(), highmem zone's managed_pages is set to
-        * present_pages, and bootmem allocator doesn't allocate from highmem
-        * zones. So there's no need to recalculate managed_pages because all
-        * highmem pages will be managed by the buddy system. Here highmem
-        * zone also includes highmem movable zone.
-        */
+       if (reset_managed_pages_done)
+               return;
+
        for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
-               if (!is_highmem(z))
-                       z->managed_pages = 0;
+               z->managed_pages = 0;
 }
 
-/**
- * free_all_bootmem_node - release a node's free pages to the buddy allocator
- * @pgdat: node to be released
- *
- * Returns the number of pages actually released.
- */
-unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
+void __init reset_all_zones_managed_pages(void)
 {
-       register_page_bootmem_info_node(pgdat);
-       reset_node_lowmem_managed_pages(pgdat);
-       return free_all_bootmem_core(pgdat->bdata);
+       struct pglist_data *pgdat;
+
+       for_each_online_pgdat(pgdat)
+               reset_node_managed_pages(pgdat);
+       reset_managed_pages_done = 1;
 }
 
 /**
@@ -279,14 +272,14 @@ unsigned long __init free_all_bootmem(void)
 {
        unsigned long total_pages = 0;
        bootmem_data_t *bdata;
-       struct pglist_data *pgdat;
 
-       for_each_online_pgdat(pgdat)
-               reset_node_lowmem_managed_pages(pgdat);
+       reset_all_zones_managed_pages();
 
        list_for_each_entry(bdata, &bdata_list, list)
                total_pages += free_all_bootmem_core(bdata);
 
+       totalram_pages += total_pages;
+
        return total_pages;
 }
 
index 362c329b83fe7441b4d2119c1e164a54c58fc860..d8b3b850150cbac9c78fa8b55a6961a8da85c77c 100644 (file)
@@ -1429,7 +1429,7 @@ int move_huge_pmd(struct vm_area_struct *vma, struct vm_area_struct *new_vma,
        if (ret == 1) {
                pmd = pmdp_get_and_clear(mm, old_addr, old_pmd);
                VM_BUG_ON(!pmd_none(*new_pmd));
-               set_pmd_at(mm, new_addr, new_pmd, pmd);
+               set_pmd_at(mm, new_addr, new_pmd, pmd_mksoft_dirty(pmd));
                spin_unlock(&mm->page_table_lock);
        }
 out:
index e2bfbf73a551d0747fbea1b69200dd773e36754e..83aff0a4d0938e308619a703dfca17265419e628 100644 (file)
@@ -319,7 +319,7 @@ unsigned long vma_kernel_pagesize(struct vm_area_struct *vma)
 
        hstate = hstate_vma(vma);
 
-       return 1UL << (hstate->order + PAGE_SHIFT);
+       return 1UL << huge_page_shift(hstate);
 }
 EXPORT_SYMBOL_GPL(vma_kernel_pagesize);
 
@@ -690,6 +690,23 @@ int PageHuge(struct page *page)
 }
 EXPORT_SYMBOL_GPL(PageHuge);
 
+pgoff_t __basepage_index(struct page *page)
+{
+       struct page *page_head = compound_head(page);
+       pgoff_t index = page_index(page_head);
+       unsigned long compound_idx;
+
+       if (!PageHuge(page_head))
+               return page_index(page);
+
+       if (compound_order(page_head) >= MAX_ORDER)
+               compound_idx = page_to_pfn(page) - page_to_pfn(page_head);
+       else
+               compound_idx = page - page_head;
+
+       return (index << compound_order(page_head)) + compound_idx;
+}
+
 static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid)
 {
        struct page *page;
@@ -1246,7 +1263,7 @@ static void __init gather_bootmem_prealloc(void)
                 * side-effects, like CommitLimit going negative.
                 */
                if (h->order > (MAX_ORDER - 1))
-                       totalram_pages += 1 << h->order;
+                       adjust_managed_page_count(page, 1 << h->order);
        }
 }
 
@@ -2931,15 +2948,6 @@ out_mutex:
        return ret;
 }
 
-/* Can be overriden by architectures */
-__attribute__((weak)) struct page *
-follow_huge_pud(struct mm_struct *mm, unsigned long address,
-              pud_t *pud, int write)
-{
-       BUG();
-       return NULL;
-}
-
 long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
                         struct page **pages, struct vm_area_struct **vmas,
                         unsigned long *position, unsigned long *nr_pages,
@@ -3169,6 +3177,216 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
        hugetlb_acct_memory(h, -(chg - freed));
 }
 
+#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
+static unsigned long page_table_shareable(struct vm_area_struct *svma,
+                               struct vm_area_struct *vma,
+                               unsigned long addr, pgoff_t idx)
+{
+       unsigned long saddr = ((idx - svma->vm_pgoff) << PAGE_SHIFT) +
+                               svma->vm_start;
+       unsigned long sbase = saddr & PUD_MASK;
+       unsigned long s_end = sbase + PUD_SIZE;
+
+       /* Allow segments to share if only one is marked locked */
+       unsigned long vm_flags = vma->vm_flags & ~VM_LOCKED;
+       unsigned long svm_flags = svma->vm_flags & ~VM_LOCKED;
+
+       /*
+        * match the virtual addresses, permission and the alignment of the
+        * page table page.
+        */
+       if (pmd_index(addr) != pmd_index(saddr) ||
+           vm_flags != svm_flags ||
+           sbase < svma->vm_start || svma->vm_end < s_end)
+               return 0;
+
+       return saddr;
+}
+
+static int vma_shareable(struct vm_area_struct *vma, unsigned long addr)
+{
+       unsigned long base = addr & PUD_MASK;
+       unsigned long end = base + PUD_SIZE;
+
+       /*
+        * check on proper vm_flags and page table alignment
+        */
+       if (vma->vm_flags & VM_MAYSHARE &&
+           vma->vm_start <= base && end <= vma->vm_end)
+               return 1;
+       return 0;
+}
+
+/*
+ * Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc()
+ * and returns the corresponding pte. While this is not necessary for the
+ * !shared pmd case because we can allocate the pmd later as well, it makes the
+ * code much cleaner. pmd allocation is essential for the shared case because
+ * pud has to be populated inside the same i_mmap_mutex section - otherwise
+ * racing tasks could either miss the sharing (see huge_pte_offset) or select a
+ * bad pmd for sharing.
+ */
+pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
+{
+       struct vm_area_struct *vma = find_vma(mm, addr);
+       struct address_space *mapping = vma->vm_file->f_mapping;
+       pgoff_t idx = ((addr - vma->vm_start) >> PAGE_SHIFT) +
+                       vma->vm_pgoff;
+       struct vm_area_struct *svma;
+       unsigned long saddr;
+       pte_t *spte = NULL;
+       pte_t *pte;
+
+       if (!vma_shareable(vma, addr))
+               return (pte_t *)pmd_alloc(mm, pud, addr);
+
+       mutex_lock(&mapping->i_mmap_mutex);
+       vma_interval_tree_foreach(svma, &mapping->i_mmap, idx, idx) {
+               if (svma == vma)
+                       continue;
+
+               saddr = page_table_shareable(svma, vma, addr, idx);
+               if (saddr) {
+                       spte = huge_pte_offset(svma->vm_mm, saddr);
+                       if (spte) {
+                               get_page(virt_to_page(spte));
+                               break;
+                       }
+               }
+       }
+
+       if (!spte)
+               goto out;
+
+       spin_lock(&mm->page_table_lock);
+       if (pud_none(*pud))
+               pud_populate(mm, pud,
+                               (pmd_t *)((unsigned long)spte & PAGE_MASK));
+       else
+               put_page(virt_to_page(spte));
+       spin_unlock(&mm->page_table_lock);
+out:
+       pte = (pte_t *)pmd_alloc(mm, pud, addr);
+       mutex_unlock(&mapping->i_mmap_mutex);
+       return pte;
+}
+
+/*
+ * unmap huge page backed by shared pte.
+ *
+ * Hugetlb pte page is ref counted at the time of mapping.  If pte is shared
+ * indicated by page_count > 1, unmap is achieved by clearing pud and
+ * decrementing the ref count. If count == 1, the pte page is not shared.
+ *
+ * called with vma->vm_mm->page_table_lock held.
+ *
+ * returns: 1 successfully unmapped a shared pte page
+ *         0 the underlying pte page is not shared, or it is the last user
+ */
+int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
+{
+       pgd_t *pgd = pgd_offset(mm, *addr);
+       pud_t *pud = pud_offset(pgd, *addr);
+
+       BUG_ON(page_count(virt_to_page(ptep)) == 0);
+       if (page_count(virt_to_page(ptep)) == 1)
+               return 0;
+
+       pud_clear(pud);
+       put_page(virt_to_page(ptep));
+       *addr = ALIGN(*addr, HPAGE_SIZE * PTRS_PER_PTE) - HPAGE_SIZE;
+       return 1;
+}
+#define want_pmd_share()       (1)
+#else /* !CONFIG_ARCH_WANT_HUGE_PMD_SHARE */
+pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
+{
+       return NULL;
+}
+#define want_pmd_share()       (0)
+#endif /* CONFIG_ARCH_WANT_HUGE_PMD_SHARE */
+
+#ifdef CONFIG_ARCH_WANT_GENERAL_HUGETLB
+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;
+
+       pgd = pgd_offset(mm, addr);
+       pud = pud_alloc(mm, pgd, addr);
+       if (pud) {
+               if (sz == PUD_SIZE) {
+                       pte = (pte_t *)pud;
+               } else {
+                       BUG_ON(sz != PMD_SIZE);
+                       if (want_pmd_share() && pud_none(*pud))
+                               pte = huge_pmd_share(mm, addr, pud);
+                       else
+                               pte = (pte_t *)pmd_alloc(mm, pud, addr);
+               }
+       }
+       BUG_ON(pte && !pte_none(*pte) && !pte_huge(*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;
+
+       pgd = pgd_offset(mm, addr);
+       if (pgd_present(*pgd)) {
+               pud = pud_offset(pgd, addr);
+               if (pud_present(*pud)) {
+                       if (pud_huge(*pud))
+                               return (pte_t *)pud;
+                       pmd = pmd_offset(pud, addr);
+               }
+       }
+       return (pte_t *) pmd;
+}
+
+struct page *
+follow_huge_pmd(struct mm_struct *mm, unsigned long address,
+               pmd_t *pmd, int write)
+{
+       struct page *page;
+
+       page = pte_page(*(pte_t *)pmd);
+       if (page)
+               page += ((address & ~PMD_MASK) >> PAGE_SHIFT);
+       return page;
+}
+
+struct page *
+follow_huge_pud(struct mm_struct *mm, unsigned long address,
+               pud_t *pud, int write)
+{
+       struct page *page;
+
+       page = pte_page(*(pte_t *)pud);
+       if (page)
+               page += ((address & ~PUD_MASK) >> PAGE_SHIFT);
+       return page;
+}
+
+#else /* !CONFIG_ARCH_WANT_GENERAL_HUGETLB */
+
+/* Can be overriden by architectures */
+__attribute__((weak)) struct page *
+follow_huge_pud(struct mm_struct *mm, unsigned long address,
+              pud_t *pud, int write)
+{
+       BUG();
+       return NULL;
+}
+
+#endif /* CONFIG_ARCH_WANT_GENERAL_HUGETLB */
+
 #ifdef CONFIG_MEMORY_FAILURE
 
 /* Should be called in hugetlb_lock */
index 194721839cf5d303a0de2b4df611b700db895043..2e851f453814529d0a3e032e9e5e1dd009a4b34a 100644 (file)
@@ -1148,6 +1148,58 @@ skip_node:
        return NULL;
 }
 
+static void mem_cgroup_iter_invalidate(struct mem_cgroup *root)
+{
+       /*
+        * When a group in the hierarchy below root is destroyed, the
+        * hierarchy iterator can no longer be trusted since it might
+        * have pointed to the destroyed group.  Invalidate it.
+        */
+       atomic_inc(&root->dead_count);
+}
+
+static struct mem_cgroup *
+mem_cgroup_iter_load(struct mem_cgroup_reclaim_iter *iter,
+                    struct mem_cgroup *root,
+                    int *sequence)
+{
+       struct mem_cgroup *position = NULL;
+       /*
+        * A cgroup destruction happens in two stages: offlining and
+        * release.  They are separated by a RCU grace period.
+        *
+        * If the iterator is valid, we may still race with an
+        * offlining.  The RCU lock ensures the object won't be
+        * released, tryget will fail if we lost the race.
+        */
+       *sequence = atomic_read(&root->dead_count);
+       if (iter->last_dead_count == *sequence) {
+               smp_rmb();
+               position = iter->last_visited;
+               if (position && !css_tryget(&position->css))
+                       position = NULL;
+       }
+       return position;
+}
+
+static void mem_cgroup_iter_update(struct mem_cgroup_reclaim_iter *iter,
+                                  struct mem_cgroup *last_visited,
+                                  struct mem_cgroup *new_position,
+                                  int sequence)
+{
+       if (last_visited)
+               css_put(&last_visited->css);
+       /*
+        * We store the sequence count from the time @last_visited was
+        * loaded successfully instead of rereading it here so that we
+        * don't lose destruction events in between.  We could have
+        * raced with the destruction of @new_position after all.
+        */
+       iter->last_visited = new_position;
+       smp_wmb();
+       iter->last_dead_count = sequence;
+}
+
 /**
  * mem_cgroup_iter - iterate over memory cgroup hierarchy
  * @root: hierarchy root
@@ -1171,7 +1223,6 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
 {
        struct mem_cgroup *memcg = NULL;
        struct mem_cgroup *last_visited = NULL;
-       unsigned long uninitialized_var(dead_count);
 
        if (mem_cgroup_disabled())
                return NULL;
@@ -1191,6 +1242,7 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
        rcu_read_lock();
        while (!memcg) {
                struct mem_cgroup_reclaim_iter *uninitialized_var(iter);
+               int uninitialized_var(seq);
 
                if (reclaim) {
                        int nid = zone_to_nid(reclaim->zone);
@@ -1204,37 +1256,13 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
                                goto out_unlock;
                        }
 
-                       /*
-                        * If the dead_count mismatches, a destruction
-                        * has happened or is happening concurrently.
-                        * If the dead_count matches, a destruction
-                        * might still happen concurrently, but since
-                        * we checked under RCU, that destruction
-                        * won't free the object until we release the
-                        * RCU reader lock.  Thus, the dead_count
-                        * check verifies the pointer is still valid,
-                        * css_tryget() verifies the cgroup pointed to
-                        * is alive.
-                        */
-                       dead_count = atomic_read(&root->dead_count);
-                       if (dead_count == iter->last_dead_count) {
-                               smp_rmb();
-                               last_visited = iter->last_visited;
-                               if (last_visited &&
-                                   !css_tryget(&last_visited->css))
-                                       last_visited = NULL;
-                       }
+                       last_visited = mem_cgroup_iter_load(iter, root, &seq);
                }
 
                memcg = __mem_cgroup_iter_next(root, last_visited);
 
                if (reclaim) {
-                       if (last_visited)
-                               css_put(&last_visited->css);
-
-                       iter->last_visited = memcg;
-                       smp_wmb();
-                       iter->last_dead_count = dead_count;
+                       mem_cgroup_iter_update(iter, last_visited, memcg, seq);
 
                        if (!memcg)
                                iter->generation++;
@@ -1448,11 +1476,12 @@ static bool mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
        return ret;
 }
 
-int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg)
+bool task_in_mem_cgroup(struct task_struct *task,
+                       const struct mem_cgroup *memcg)
 {
-       int ret;
        struct mem_cgroup *curr = NULL;
        struct task_struct *p;
+       bool ret;
 
        p = find_lock_task_mm(task);
        if (p) {
@@ -1464,14 +1493,14 @@ int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg)
                 * killer still needs to detect if they have already been oom
                 * killed to prevent needlessly killing additional tasks.
                 */
-               task_lock(task);
+               rcu_read_lock();
                curr = mem_cgroup_from_task(task);
                if (curr)
                        css_get(&curr->css);
-               task_unlock(task);
+               rcu_read_unlock();
        }
        if (!curr)
-               return 0;
+               return false;
        /*
         * We should check use_hierarchy of "memcg" not "curr". Because checking
         * use_hierarchy of "curr" here make this function true if hierarchy is
@@ -6317,14 +6346,14 @@ static void mem_cgroup_invalidate_reclaim_iterators(struct mem_cgroup *memcg)
        struct mem_cgroup *parent = memcg;
 
        while ((parent = parent_mem_cgroup(parent)))
-               atomic_inc(&parent->dead_count);
+               mem_cgroup_iter_invalidate(parent);
 
        /*
         * if the root memcg is not hierarchical we have to check it
         * explicitely.
         */
        if (!root_mem_cgroup->use_hierarchy)
-               atomic_inc(&root_mem_cgroup->dead_count);
+               mem_cgroup_iter_invalidate(root_mem_cgroup);
 }
 
 static void mem_cgroup_css_offline(struct cgroup *cont)
index ceb0c7f1932f2e97c18cb1971f5b0593d57172ab..2c13aa7a0164101a360e4f776090f6b183aab5ab 100644 (file)
@@ -1410,7 +1410,8 @@ static int __get_any_page(struct page *p, unsigned long pfn, int flags)
 
        /*
         * Isolate the page, so that it doesn't get reallocated if it
-        * was free.
+        * was free. This flag should be kept set until the source page
+        * is freed and PG_hwpoison on it is set.
         */
        set_migratetype_isolate(p, true);
        /*
@@ -1433,7 +1434,6 @@ static int __get_any_page(struct page *p, unsigned long pfn, int flags)
                /* Not a free page */
                ret = 1;
        }
-       unset_migratetype_isolate(p, MIGRATE_MOVABLE);
        unlock_memory_hotplug();
        return ret;
 }
@@ -1494,7 +1494,6 @@ static int soft_offline_huge_page(struct page *page, int flags)
                atomic_long_add(1 << compound_trans_order(hpage),
                                &num_poisoned_pages);
        }
-       /* keep elevated page count for bad page */
        return ret;
 }
 
@@ -1559,7 +1558,7 @@ int soft_offline_page(struct page *page, int flags)
                        atomic_long_inc(&num_poisoned_pages);
                }
        }
-       /* keep elevated page count for bad page */
+       unset_migratetype_isolate(page, MIGRATE_MOVABLE);
        return ret;
 }
 
@@ -1625,7 +1624,22 @@ static int __soft_offline_page(struct page *page, int flags)
                        if (ret > 0)
                                ret = -EIO;
                } else {
+                       /*
+                        * After page migration succeeds, the source page can
+                        * be trapped in pagevec and actual freeing is delayed.
+                        * Freeing code works differently based on PG_hwpoison,
+                        * so there's a race. We need to make sure that the
+                        * source page should be freed back to buddy before
+                        * setting PG_hwpoison.
+                        */
+                       if (!is_free_buddy_page(page))
+                               lru_add_drain_all();
+                       if (!is_free_buddy_page(page))
+                               drain_all_pages();
                        SetPageHWPoison(page);
+                       if (!is_free_buddy_page(page))
+                               pr_info("soft offline: %#lx: page leaked\n",
+                                       pfn);
                        atomic_long_inc(&num_poisoned_pages);
                }
        } else {
index 61a262b08e53efa2f69c1387e488bea6f87bb0f9..b68812d682b66c24e306d955ddbcb125e658e708 100644 (file)
@@ -82,7 +82,6 @@ EXPORT_SYMBOL(max_mapnr);
 EXPORT_SYMBOL(mem_map);
 #endif
 
-unsigned long num_physpages;
 /*
  * A number of key systems in x86 including ioremap() rely on the assumption
  * that high_memory defines the upper bound on direct map memory, then end
@@ -92,7 +91,6 @@ unsigned long num_physpages;
  */
 void * high_memory;
 
-EXPORT_SYMBOL(num_physpages);
 EXPORT_SYMBOL(high_memory);
 
 /*
@@ -1101,6 +1099,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
        spinlock_t *ptl;
        pte_t *start_pte;
        pte_t *pte;
+       unsigned long range_start = addr;
 
 again:
        init_rss_vec(rss);
@@ -1206,12 +1205,14 @@ again:
                force_flush = 0;
 
 #ifdef HAVE_GENERIC_MMU_GATHER
-               tlb->start = addr;
-               tlb->end = end;
+               tlb->start = range_start;
+               tlb->end = addr;
 #endif
                tlb_flush_mmu(tlb);
-               if (addr != end)
+               if (addr != end) {
+                       range_start = addr;
                        goto again;
+               }
        }
 
        return addr;
@@ -2904,7 +2905,7 @@ static inline void unmap_mapping_range_tree(struct rb_root *root,
                        details->first_index, details->last_index) {
 
                vba = vma->vm_pgoff;
-               vea = vba + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) - 1;
+               vea = vba + vma_pages(vma) - 1;
                /* Assume for now that PAGE_CACHE_SHIFT == PAGE_SHIFT */
                zba = details->first_index;
                if (zba < vba)
@@ -4201,7 +4202,7 @@ void print_vma_addr(char *prefix, unsigned long ip)
        up_read(&mm->mmap_sem);
 }
 
-#ifdef CONFIG_PROVE_LOCKING
+#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP)
 void might_fault(void)
 {
        /*
@@ -4213,13 +4214,17 @@ void might_fault(void)
        if (segment_eq(get_fs(), KERNEL_DS))
                return;
 
-       might_sleep();
        /*
         * it would be nicer only to annotate paths which are not under
         * pagefault_disable, however that requires a larger audit and
         * providing helpers like get_user_atomic.
         */
-       if (!in_atomic() && current->mm)
+       if (in_atomic())
+               return;
+
+       __might_sleep(__FILE__, __LINE__, 0);
+
+       if (current->mm)
                might_lock_read(&current->mm->mmap_sem);
 }
 EXPORT_SYMBOL(might_fault);
index 1ad92b46753edfe8d9f54fae81c5f3aa15b34110..f5ba127b2051b51d77a35883edec74a4f57cb6a1 100644 (file)
@@ -75,7 +75,7 @@ static struct resource *register_memory_resource(u64 start, u64 size)
        res->end = start + size - 1;
        res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
        if (request_resource(&iomem_resource, res) < 0) {
-               printk("System RAM resource %pR cannot be added\n", res);
+               pr_debug("System RAM resource %pR cannot be added\n", res);
                kfree(res);
                res = NULL;
        }
@@ -101,12 +101,9 @@ void get_page_bootmem(unsigned long info,  struct page *page,
        atomic_inc(&page->_count);
 }
 
-/* reference to __meminit __free_pages_bootmem is valid
- * so use __ref to tell modpost not to generate a warning */
-void __ref put_page_bootmem(struct page *page)
+void put_page_bootmem(struct page *page)
 {
        unsigned long type;
-       static DEFINE_MUTEX(ppb_lock);
 
        type = (unsigned long) page->lru.next;
        BUG_ON(type < MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE ||
@@ -116,17 +113,8 @@ void __ref put_page_bootmem(struct page *page)
                ClearPagePrivate(page);
                set_page_private(page, 0);
                INIT_LIST_HEAD(&page->lru);
-
-               /*
-                * Please refer to comment for __free_pages_bootmem()
-                * for why we serialize here.
-                */
-               mutex_lock(&ppb_lock);
-               __free_pages_bootmem(page, 0);
-               mutex_unlock(&ppb_lock);
-               totalram_pages++;
+               free_reserved_page(page);
        }
-
 }
 
 #ifdef CONFIG_HAVE_BOOTMEM_INFO_NODE
@@ -309,7 +297,7 @@ static int __meminit move_pfn_range_left(struct zone *z1, struct zone *z2,
        /* can't move pfns which are higher than @z2 */
        if (end_pfn > zone_end_pfn(z2))
                goto out_fail;
-       /* the move out part mast at the left most of @z2 */
+       /* the move out part must be at the left most of @z2 */
        if (start_pfn > z2->zone_start_pfn)
                goto out_fail;
        /* must included/overlap */
@@ -775,29 +763,18 @@ EXPORT_SYMBOL_GPL(restore_online_page_callback);
 
 void __online_page_set_limits(struct page *page)
 {
-       unsigned long pfn = page_to_pfn(page);
-
-       if (pfn >= num_physpages)
-               num_physpages = pfn + 1;
 }
 EXPORT_SYMBOL_GPL(__online_page_set_limits);
 
 void __online_page_increment_counters(struct page *page)
 {
-       totalram_pages++;
-
-#ifdef CONFIG_HIGHMEM
-       if (PageHighMem(page))
-               totalhigh_pages++;
-#endif
+       adjust_managed_page_count(page, 1);
 }
 EXPORT_SYMBOL_GPL(__online_page_increment_counters);
 
 void __online_page_free(struct page *page)
 {
-       ClearPageReserved(page);
-       init_page_count(page);
-       __free_page(page);
+       __free_reserved_page(page);
 }
 EXPORT_SYMBOL_GPL(__online_page_free);
 
@@ -918,6 +895,7 @@ static void node_states_set_node(int node, struct memory_notify *arg)
 
 int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_type)
 {
+       unsigned long flags;
        unsigned long onlined_pages = 0;
        struct zone *zone;
        int need_zonelists_rebuild = 0;
@@ -994,9 +972,12 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ
                return ret;
        }
 
-       zone->managed_pages += onlined_pages;
        zone->present_pages += onlined_pages;
+
+       pgdat_resize_lock(zone->zone_pgdat, &flags);
        zone->zone_pgdat->node_present_pages += onlined_pages;
+       pgdat_resize_unlock(zone->zone_pgdat, &flags);
+
        if (onlined_pages) {
                node_states_set_node(zone_to_nid(zone), &arg);
                if (need_zonelists_rebuild)
@@ -1487,6 +1468,7 @@ static int __ref __offline_pages(unsigned long start_pfn,
        unsigned long pfn, nr_pages, expire;
        long offlined_pages;
        int ret, drain, retry_max, node;
+       unsigned long flags;
        struct zone *zone;
        struct memory_notify arg;
 
@@ -1578,10 +1560,12 @@ repeat:
        /* reset pagetype flags and makes migrate type to be MOVABLE */
        undo_isolate_page_range(start_pfn, end_pfn, MIGRATE_MOVABLE);
        /* removal success */
-       zone->managed_pages -= offlined_pages;
+       adjust_managed_page_count(pfn_to_page(start_pfn), -offlined_pages);
        zone->present_pages -= offlined_pages;
+
+       pgdat_resize_lock(zone->zone_pgdat, &flags);
        zone->zone_pgdat->node_present_pages -= offlined_pages;
-       totalram_pages -= offlined_pages;
+       pgdat_resize_unlock(zone->zone_pgdat, &flags);
 
        init_per_zone_wmark_min();
 
@@ -1621,6 +1605,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
 {
        return __offline_pages(start_pfn, start_pfn + nr_pages, 120 * HZ);
 }
+#endif /* CONFIG_MEMORY_HOTREMOVE */
 
 /**
  * walk_memory_range - walks through all mem sections in [start_pfn, end_pfn)
@@ -1634,7 +1619,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
  *
  * Returns the return value of func.
  */
-static int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
+int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
                void *arg, int (*func)(struct memory_block *, void *))
 {
        struct memory_block *mem = NULL;
@@ -1671,24 +1656,7 @@ static int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
        return 0;
 }
 
-/**
- * offline_memory_block_cb - callback function for offlining memory block
- * @mem: the memory block to be offlined
- * @arg: buffer to hold error msg
- *
- * Always return 0, and put the error msg in arg if any.
- */
-static int offline_memory_block_cb(struct memory_block *mem, void *arg)
-{
-       int *ret = arg;
-       int error = offline_memory_block(mem);
-
-       if (error != 0 && *ret == 0)
-               *ret = error;
-
-       return 0;
-}
-
+#ifdef CONFIG_MEMORY_HOTREMOVE
 static int is_memblock_offlined_cb(struct memory_block *mem, void *arg)
 {
        int ret = !is_memblock_offlined(mem);
@@ -1814,54 +1782,22 @@ void try_offline_node(int nid)
 }
 EXPORT_SYMBOL(try_offline_node);
 
-int __ref remove_memory(int nid, u64 start, u64 size)
+void __ref remove_memory(int nid, u64 start, u64 size)
 {
-       unsigned long start_pfn, end_pfn;
-       int ret = 0;
-       int retry = 1;
-
-       start_pfn = PFN_DOWN(start);
-       end_pfn = PFN_UP(start + size - 1);
-
-       /*
-        * When CONFIG_MEMCG is on, one memory block may be used by other
-        * blocks to store page cgroup when onlining pages. But we don't know
-        * in what order pages are onlined. So we iterate twice to offline
-        * memory:
-        * 1st iterate: offline every non primary memory block.
-        * 2nd iterate: offline primary (i.e. first added) memory block.
-        */
-repeat:
-       walk_memory_range(start_pfn, end_pfn, &ret,
-                         offline_memory_block_cb);
-       if (ret) {
-               if (!retry)
-                       return ret;
-
-               retry = 0;
-               ret = 0;
-               goto repeat;
-       }
+       int ret;
 
        lock_memory_hotplug();
 
        /*
-        * we have offlined all memory blocks like this:
-        *   1. lock memory hotplug
-        *   2. offline a memory block
-        *   3. unlock memory hotplug
-        *
-        * repeat step1-3 to offline the memory block. All memory blocks
-        * must be offlined before removing memory. But we don't hold the
-        * lock in the whole operation. So we should check whether all
-        * memory blocks are offlined.
+        * All memory blocks must be offlined before removing memory.  Check
+        * whether all memory blocks in question are offline and trigger a BUG()
+        * if this is not the case.
         */
-
-       ret = walk_memory_range(start_pfn, end_pfn, NULL,
+       ret = walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), NULL,
                                is_memblock_offlined_cb);
        if (ret) {
                unlock_memory_hotplug();
-               return ret;
+               BUG();
        }
 
        /* remove memmap entry */
@@ -1872,17 +1808,6 @@ repeat:
        try_offline_node(nid);
 
        unlock_memory_hotplug();
-
-       return 0;
 }
-#else
-int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
-{
-       return -EINVAL;
-}
-int remove_memory(int nid, u64 start, u64 size)
-{
-       return -EINVAL;
-}
-#endif /* CONFIG_MEMORY_HOTREMOVE */
 EXPORT_SYMBOL_GPL(remove_memory);
+#endif /* CONFIG_MEMORY_HOTREMOVE */
index c280a02ea11ea2ce79113c5487ce09044652ac80..633c08863fd8923ca393f6126bc61f24f38fa427 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/init.h>
 #include <linux/kobject.h>
 #include <linux/export.h>
+#include <linux/memory.h>
+#include <linux/notifier.h>
 #include "internal.h"
 
 #ifdef CONFIG_DEBUG_MEMORY_INIT
@@ -147,6 +149,51 @@ early_param("mminit_loglevel", set_mminit_loglevel);
 struct kobject *mm_kobj;
 EXPORT_SYMBOL_GPL(mm_kobj);
 
+#ifdef CONFIG_SMP
+s32 vm_committed_as_batch = 32;
+
+static void __meminit mm_compute_batch(void)
+{
+       u64 memsized_batch;
+       s32 nr = num_present_cpus();
+       s32 batch = max_t(s32, nr*2, 32);
+
+       /* batch size set to 0.4% of (total memory/#cpus), or max int32 */
+       memsized_batch = min_t(u64, (totalram_pages/nr)/256, 0x7fffffff);
+
+       vm_committed_as_batch = max_t(s32, memsized_batch, batch);
+}
+
+static int __meminit mm_compute_batch_notifier(struct notifier_block *self,
+                                       unsigned long action, void *arg)
+{
+       switch (action) {
+       case MEM_ONLINE:
+       case MEM_OFFLINE:
+               mm_compute_batch();
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block compute_batch_nb __meminitdata = {
+       .notifier_call = mm_compute_batch_notifier,
+       .priority = IPC_CALLBACK_PRI, /* use lowest priority */
+};
+
+static int __init mm_compute_batch_init(void)
+{
+       mm_compute_batch();
+       register_hotmemory_notifier(&compute_batch_nb);
+
+       return 0;
+}
+
+__initcall(mm_compute_batch_init);
+
+#endif
+
 static int __init mm_sysfs_init(void)
 {
        mm_kobj = kobject_create_and_add("mm", kernel_kobj);
index f681e1842fadc1ccd8d7188a7ca1688c73548111..8468ffd05baec80b81c13f5fa1a2a27e9b90f625 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -955,7 +955,7 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
        if (is_mergeable_vma(vma, file, vm_flags) &&
            is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
                pgoff_t vm_pglen;
-               vm_pglen = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+               vm_pglen = vma_pages(vma);
                if (vma->vm_pgoff + vm_pglen == vm_pgoff)
                        return 1;
        }
index 463a25705ac6d4ca38fb202b30b2ccae9161ce5b..3708655378e9298b52ca34a204df48507aa954d2 100644 (file)
@@ -126,7 +126,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
                        continue;
                pte = ptep_get_and_clear(mm, old_addr, old_pte);
                pte = move_pte(pte, new_vma->vm_page_prot, old_addr, new_addr);
-               set_pte_at(mm, new_addr, new_pte, pte);
+               set_pte_at(mm, new_addr, new_pte, pte_mksoft_dirty(pte));
        }
 
        arch_leave_lazy_mmu_mode();
index bdd3fa2fc73b8395fa78979874eb46c2e3ab20c5..61107cf55bb3e2c491bffdfb63f489b9587b6f06 100644 (file)
@@ -137,20 +137,25 @@ static unsigned long __init free_low_memory_core_early(void)
        return count;
 }
 
-static void reset_node_lowmem_managed_pages(pg_data_t *pgdat)
+static int reset_managed_pages_done __initdata;
+
+static inline void __init reset_node_managed_pages(pg_data_t *pgdat)
 {
        struct zone *z;
 
-       /*
-        * In free_area_init_core(), highmem zone's managed_pages is set to
-        * present_pages, and bootmem allocator doesn't allocate from highmem
-        * zones. So there's no need to recalculate managed_pages because all
-        * highmem pages will be managed by the buddy system. Here highmem
-        * zone also includes highmem movable zone.
-        */
+       if (reset_managed_pages_done)
+               return;
        for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++)
-               if (!is_highmem(z))
-                       z->managed_pages = 0;
+               z->managed_pages = 0;
+}
+
+void __init reset_all_zones_managed_pages(void)
+{
+       struct pglist_data *pgdat;
+
+       for_each_online_pgdat(pgdat)
+               reset_node_managed_pages(pgdat);
+       reset_managed_pages_done = 1;
 }
 
 /**
@@ -160,17 +165,19 @@ static void reset_node_lowmem_managed_pages(pg_data_t *pgdat)
  */
 unsigned long __init free_all_bootmem(void)
 {
-       struct pglist_data *pgdat;
+       unsigned long pages;
 
-       for_each_online_pgdat(pgdat)
-               reset_node_lowmem_managed_pages(pgdat);
+       reset_all_zones_managed_pages();
 
        /*
         * We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id
         *  because in some case like Node0 doesn't have RAM installed
         *  low ram will be on Node1
         */
-       return free_low_memory_core_early();
+       pages = free_low_memory_core_early();
+       totalram_pages += pages;
+
+       return pages;
 }
 
 /**
index 298884dcd6e71e4723a203a82f1613cbfcec19ec..e44e6e0a125cb7148913f42fb8ff3e1587a49be9 100644 (file)
@@ -56,7 +56,6 @@
 void *high_memory;
 struct page *mem_map;
 unsigned long max_mapnr;
-unsigned long num_physpages;
 unsigned long highest_memmap_pfn;
 struct percpu_counter vm_committed_as;
 int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */
@@ -85,7 +84,6 @@ unsigned long vm_memory_committed(void)
 EXPORT_SYMBOL_GPL(vm_memory_committed);
 
 EXPORT_SYMBOL(mem_map);
-EXPORT_SYMBOL(num_physpages);
 
 /* list of mapped, potentially shareable regions */
 static struct kmem_cache *vm_region_jar;
@@ -282,6 +280,10 @@ EXPORT_SYMBOL(vmalloc_to_pfn);
 
 long vread(char *buf, char *addr, unsigned long count)
 {
+       /* Don't allow overflow */
+       if ((unsigned long) buf + count < count)
+               count = -(unsigned long) buf;
+
        memcpy(buf, addr, count);
        return count;
 }
index c3edb624fccf30c303ccff94cf139e090b416d7e..327516b7aee96de1caf2afebb048955734a71ebd 100644 (file)
 #include <linux/hugetlb.h>
 #include <linux/sched/rt.h>
 
+#include <asm/sections.h>
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
 #include "internal.h"
 
+/* prevent >1 _updater_ of zone percpu pageset ->high and ->batch fields */
+static DEFINE_MUTEX(pcp_batch_high_lock);
+
 #ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID
 DEFINE_PER_CPU(int, numa_node);
 EXPORT_PER_CPU_SYMBOL(numa_node);
@@ -100,6 +104,9 @@ nodemask_t node_states[NR_NODE_STATES] __read_mostly = {
 };
 EXPORT_SYMBOL(node_states);
 
+/* Protect totalram_pages and zone->managed_pages */
+static DEFINE_SPINLOCK(managed_page_count_lock);
+
 unsigned long totalram_pages __read_mostly;
 unsigned long totalreserve_pages __read_mostly;
 /*
@@ -739,14 +746,7 @@ static void __free_pages_ok(struct page *page, unsigned int order)
        local_irq_restore(flags);
 }
 
-/*
- * Read access to zone->managed_pages is safe because it's unsigned long,
- * but we still need to serialize writers. Currently all callers of
- * __free_pages_bootmem() except put_page_bootmem() should only be used
- * at boot time. So for shorter boot time, we shift the burden to
- * put_page_bootmem() to serialize writers.
- */
-void __meminit __free_pages_bootmem(struct page *page, unsigned int order)
+void __init __free_pages_bootmem(struct page *page, unsigned int order)
 {
        unsigned int nr_pages = 1 << order;
        unsigned int loop;
@@ -781,11 +781,7 @@ void __init init_cma_reserved_pageblock(struct page *page)
        set_page_refcounted(page);
        set_pageblock_migratetype(page, MIGRATE_CMA);
        __free_pages(page, pageblock_order);
-       totalram_pages += pageblock_nr_pages;
-#ifdef CONFIG_HIGHMEM
-       if (PageHighMem(page))
-               totalhigh_pages += pageblock_nr_pages;
-#endif
+       adjust_managed_page_count(page, pageblock_nr_pages);
 }
 #endif
 
@@ -1179,10 +1175,12 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
 {
        unsigned long flags;
        int to_drain;
+       unsigned long batch;
 
        local_irq_save(flags);
-       if (pcp->count >= pcp->batch)
-               to_drain = pcp->batch;
+       batch = ACCESS_ONCE(pcp->batch);
+       if (pcp->count >= batch)
+               to_drain = batch;
        else
                to_drain = pcp->count;
        if (to_drain > 0) {
@@ -1350,8 +1348,9 @@ void free_hot_cold_page(struct page *page, int cold)
                list_add(&page->lru, &pcp->lists[migratetype]);
        pcp->count++;
        if (pcp->count >= pcp->high) {
-               free_pcppages_bulk(zone, pcp->batch, pcp);
-               pcp->count -= pcp->batch;
+               unsigned long batch = ACCESS_ONCE(pcp->batch);
+               free_pcppages_bulk(zone, batch, pcp);
+               pcp->count -= batch;
        }
 
 out:
@@ -2839,7 +2838,7 @@ EXPORT_SYMBOL(free_pages_exact);
  * nr_free_zone_pages() counts the number of counts pages which are beyond the
  * high watermark within all zones at or below a given zone index.  For each
  * zone, the number of pages is calculated as:
- *     present_pages - high_pages
+ *     managed_pages - high_pages
  */
 static unsigned long nr_free_zone_pages(int offset)
 {
@@ -2906,9 +2905,13 @@ EXPORT_SYMBOL(si_meminfo);
 #ifdef CONFIG_NUMA
 void si_meminfo_node(struct sysinfo *val, int nid)
 {
+       int zone_type;          /* needs to be signed */
+       unsigned long managed_pages = 0;
        pg_data_t *pgdat = NODE_DATA(nid);
 
-       val->totalram = pgdat->node_present_pages;
+       for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++)
+               managed_pages += pgdat->node_zones[zone_type].managed_pages;
+       val->totalram = managed_pages;
        val->freeram = node_page_state(nid, NR_FREE_PAGES);
 #ifdef CONFIG_HIGHMEM
        val->totalhigh = pgdat->node_zones[ZONE_HIGHMEM].managed_pages;
@@ -3250,18 +3253,25 @@ int numa_zonelist_order_handler(ctl_table *table, int write,
        static DEFINE_MUTEX(zl_order_mutex);
 
        mutex_lock(&zl_order_mutex);
-       if (write)
-               strcpy(saved_string, (char*)table->data);
+       if (write) {
+               if (strlen((char *)table->data) >= NUMA_ZONELIST_ORDER_LEN) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               strcpy(saved_string, (char *)table->data);
+       }
        ret = proc_dostring(table, write, buffer, length, ppos);
        if (ret)
                goto out;
        if (write) {
                int oldval = user_zonelist_order;
-               if (__parse_numa_zonelist_order((char*)table->data)) {
+
+               ret = __parse_numa_zonelist_order((char *)table->data);
+               if (ret) {
                        /*
                         * bogus value.  restore saved string
                         */
-                       strncpy((char*)table->data, saved_string,
+                       strncpy((char *)table->data, saved_string,
                                NUMA_ZONELIST_ORDER_LEN);
                        user_zonelist_order = oldval;
                } else if (oldval != user_zonelist_order) {
@@ -3425,8 +3435,8 @@ static int default_zonelist_order(void)
                        z = &NODE_DATA(nid)->node_zones[zone_type];
                        if (populated_zone(z)) {
                                if (zone_type < ZONE_NORMAL)
-                                       low_kmem_size += z->present_pages;
-                               total_size += z->present_pages;
+                                       low_kmem_size += z->managed_pages;
+                               total_size += z->managed_pages;
                        } else if (zone_type == ZONE_NORMAL) {
                                /*
                                 * If any node has only lowmem, then node order
@@ -3705,12 +3715,12 @@ void __ref build_all_zonelists(pg_data_t *pgdat, struct zone *zone)
                mminit_verify_zonelist();
                cpuset_init_current_mems_allowed();
        } else {
-               /* we have to stop all cpus to guarantee there is no user
-                  of zonelist */
 #ifdef CONFIG_MEMORY_HOTPLUG
                if (zone)
                        setup_zone_pageset(zone);
 #endif
+               /* we have to stop all cpus to guarantee there is no user
+                  of zonelist */
                stop_machine(__build_all_zonelists, pgdat, NULL);
                /* cpuset refresh routine should be here */
        }
@@ -4032,7 +4042,40 @@ static int __meminit zone_batchsize(struct zone *zone)
 #endif
 }
 
-static void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)
+/*
+ * pcp->high and pcp->batch values are related and dependent on one another:
+ * ->batch must never be higher then ->high.
+ * The following function updates them in a safe manner without read side
+ * locking.
+ *
+ * Any new users of pcp->batch and pcp->high should ensure they can cope with
+ * those fields changing asynchronously (acording the the above rule).
+ *
+ * mutex_is_locked(&pcp_batch_high_lock) required when calling this function
+ * outside of boot time (or some other assurance that no concurrent updaters
+ * exist).
+ */
+static void pageset_update(struct per_cpu_pages *pcp, unsigned long high,
+               unsigned long batch)
+{
+       /* start with a fail safe value for batch */
+       pcp->batch = 1;
+       smp_wmb();
+
+       /* Update high, then batch, in order */
+       pcp->high = high;
+       smp_wmb();
+
+       pcp->batch = batch;
+}
+
+/* a companion to pageset_set_high() */
+static void pageset_set_batch(struct per_cpu_pageset *p, unsigned long batch)
+{
+       pageset_update(&p->pcp, 6 * batch, max(1UL, 1 * batch));
+}
+
+static void pageset_init(struct per_cpu_pageset *p)
 {
        struct per_cpu_pages *pcp;
        int migratetype;
@@ -4041,45 +4084,55 @@ static void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)
 
        pcp = &p->pcp;
        pcp->count = 0;
-       pcp->high = 6 * batch;
-       pcp->batch = max(1UL, 1 * batch);
        for (migratetype = 0; migratetype < MIGRATE_PCPTYPES; migratetype++)
                INIT_LIST_HEAD(&pcp->lists[migratetype]);
 }
 
+static void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)
+{
+       pageset_init(p);
+       pageset_set_batch(p, batch);
+}
+
 /*
- * setup_pagelist_highmark() sets the high water mark for hot per_cpu_pagelist
+ * pageset_set_high() sets the high water mark for hot per_cpu_pagelist
  * to the value high for the pageset p.
  */
-
-static void setup_pagelist_highmark(struct per_cpu_pageset *p,
+static void pageset_set_high(struct per_cpu_pageset *p,
                                unsigned long high)
 {
-       struct per_cpu_pages *pcp;
+       unsigned long batch = max(1UL, high / 4);
+       if ((high / 4) > (PAGE_SHIFT * 8))
+               batch = PAGE_SHIFT * 8;
 
-       pcp = &p->pcp;
-       pcp->high = high;
-       pcp->batch = max(1UL, high/4);
-       if ((high/4) > (PAGE_SHIFT * 8))
-               pcp->batch = PAGE_SHIFT * 8;
+       pageset_update(&p->pcp, high, batch);
 }
 
-static void __meminit setup_zone_pageset(struct zone *zone)
+static void __meminit pageset_set_high_and_batch(struct zone *zone,
+               struct per_cpu_pageset *pcp)
 {
-       int cpu;
-
-       zone->pageset = alloc_percpu(struct per_cpu_pageset);
+       if (percpu_pagelist_fraction)
+               pageset_set_high(pcp,
+                       (zone->managed_pages /
+                               percpu_pagelist_fraction));
+       else
+               pageset_set_batch(pcp, zone_batchsize(zone));
+}
 
-       for_each_possible_cpu(cpu) {
-               struct per_cpu_pageset *pcp = per_cpu_ptr(zone->pageset, cpu);
+static void __meminit zone_pageset_init(struct zone *zone, int cpu)
+{
+       struct per_cpu_pageset *pcp = per_cpu_ptr(zone->pageset, cpu);
 
-               setup_pageset(pcp, zone_batchsize(zone));
+       pageset_init(pcp);
+       pageset_set_high_and_batch(zone, pcp);
+}
 
-               if (percpu_pagelist_fraction)
-                       setup_pagelist_highmark(pcp,
-                               (zone->managed_pages /
-                                       percpu_pagelist_fraction));
-       }
+static void __meminit setup_zone_pageset(struct zone *zone)
+{
+       int cpu;
+       zone->pageset = alloc_percpu(struct per_cpu_pageset);
+       for_each_possible_cpu(cpu)
+               zone_pageset_init(zone, cpu);
 }
 
 /*
@@ -5150,35 +5203,101 @@ early_param("movablecore", cmdline_parse_movablecore);
 
 #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
 
-unsigned long free_reserved_area(unsigned long start, unsigned long end,
-                                int poison, char *s)
+void adjust_managed_page_count(struct page *page, long count)
+{
+       spin_lock(&managed_page_count_lock);
+       page_zone(page)->managed_pages += count;
+       totalram_pages += count;
+#ifdef CONFIG_HIGHMEM
+       if (PageHighMem(page))
+               totalhigh_pages += count;
+#endif
+       spin_unlock(&managed_page_count_lock);
+}
+EXPORT_SYMBOL(adjust_managed_page_count);
+
+unsigned long free_reserved_area(void *start, void *end, int poison, char *s)
 {
-       unsigned long pages, pos;
+       void *pos;
+       unsigned long pages = 0;
 
-       pos = start = PAGE_ALIGN(start);
-       end &= PAGE_MASK;
-       for (pages = 0; pos < end; pos += PAGE_SIZE, pages++) {
-               if (poison)
-                       memset((void *)pos, poison, PAGE_SIZE);
-               free_reserved_page(virt_to_page((void *)pos));
+       start = (void *)PAGE_ALIGN((unsigned long)start);
+       end = (void *)((unsigned long)end & PAGE_MASK);
+       for (pos = start; pos < end; pos += PAGE_SIZE, pages++) {
+               if ((unsigned int)poison <= 0xFF)
+                       memset(pos, poison, PAGE_SIZE);
+               free_reserved_page(virt_to_page(pos));
        }
 
        if (pages && s)
-               pr_info("Freeing %s memory: %ldK (%lx - %lx)\n",
+               pr_info("Freeing %s memory: %ldK (%p - %p)\n",
                        s, pages << (PAGE_SHIFT - 10), start, end);
 
        return pages;
 }
+EXPORT_SYMBOL(free_reserved_area);
 
 #ifdef CONFIG_HIGHMEM
 void free_highmem_page(struct page *page)
 {
        __free_reserved_page(page);
        totalram_pages++;
+       page_zone(page)->managed_pages++;
        totalhigh_pages++;
 }
 #endif
 
+
+void __init mem_init_print_info(const char *str)
+{
+       unsigned long physpages, codesize, datasize, rosize, bss_size;
+       unsigned long init_code_size, init_data_size;
+
+       physpages = get_num_physpages();
+       codesize = _etext - _stext;
+       datasize = _edata - _sdata;
+       rosize = __end_rodata - __start_rodata;
+       bss_size = __bss_stop - __bss_start;
+       init_data_size = __init_end - __init_begin;
+       init_code_size = _einittext - _sinittext;
+
+       /*
+        * Detect special cases and adjust section sizes accordingly:
+        * 1) .init.* may be embedded into .data sections
+        * 2) .init.text.* may be out of [__init_begin, __init_end],
+        *    please refer to arch/tile/kernel/vmlinux.lds.S.
+        * 3) .rodata.* may be embedded into .text or .data sections.
+        */
+#define adj_init_size(start, end, size, pos, adj) \
+       if (start <= pos && pos < end && size > adj) \
+               size -= adj;
+
+       adj_init_size(__init_begin, __init_end, init_data_size,
+                    _sinittext, init_code_size);
+       adj_init_size(_stext, _etext, codesize, _sinittext, init_code_size);
+       adj_init_size(_sdata, _edata, datasize, __init_begin, init_data_size);
+       adj_init_size(_stext, _etext, codesize, __start_rodata, rosize);
+       adj_init_size(_sdata, _edata, datasize, __start_rodata, rosize);
+
+#undef adj_init_size
+
+       printk("Memory: %luK/%luK available "
+              "(%luK kernel code, %luK rwdata, %luK rodata, "
+              "%luK init, %luK bss, %luK reserved"
+#ifdef CONFIG_HIGHMEM
+              ", %luK highmem"
+#endif
+              "%s%s)\n",
+              nr_free_pages() << (PAGE_SHIFT-10), physpages << (PAGE_SHIFT-10),
+              codesize >> 10, datasize >> 10, rosize >> 10,
+              (init_data_size + init_code_size) >> 10, bss_size >> 10,
+              (physpages - totalram_pages) << (PAGE_SHIFT-10),
+#ifdef CONFIG_HIGHMEM
+              totalhigh_pages << (PAGE_SHIFT-10),
+#endif
+              str ? ", " : "", str ? str : "");
+}
+
 /**
  * set_dma_reserve - set the specified number of pages reserved in the first zone
  * @new_dma_reserve: The number of pages to mark reserved
@@ -5540,7 +5659,6 @@ int lowmem_reserve_ratio_sysctl_handler(ctl_table *table, int write,
  * cpu.  It is the fraction of total pages in each zone that a hot per cpu pagelist
  * can have before it gets flushed back to buddy allocator.
  */
-
 int percpu_pagelist_fraction_sysctl_handler(ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
@@ -5551,14 +5669,16 @@ int percpu_pagelist_fraction_sysctl_handler(ctl_table *table, int write,
        ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
        if (!write || (ret < 0))
                return ret;
+
+       mutex_lock(&pcp_batch_high_lock);
        for_each_populated_zone(zone) {
-               for_each_possible_cpu(cpu) {
-                       unsigned long  high;
-                       high = zone->managed_pages / percpu_pagelist_fraction;
-                       setup_pagelist_highmark(
-                               per_cpu_ptr(zone->pageset, cpu), high);
-               }
+               unsigned long  high;
+               high = zone->managed_pages / percpu_pagelist_fraction;
+               for_each_possible_cpu(cpu)
+                       pageset_set_high(per_cpu_ptr(zone->pageset, cpu),
+                                        high);
        }
+       mutex_unlock(&pcp_batch_high_lock);
        return 0;
 }
 
@@ -6047,32 +6167,18 @@ void free_contig_range(unsigned long pfn, unsigned nr_pages)
 #endif
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-static int __meminit __zone_pcp_update(void *data)
-{
-       struct zone *zone = data;
-       int cpu;
-       unsigned long batch = zone_batchsize(zone), flags;
-
-       for_each_possible_cpu(cpu) {
-               struct per_cpu_pageset *pset;
-               struct per_cpu_pages *pcp;
-
-               pset = per_cpu_ptr(zone->pageset, cpu);
-               pcp = &pset->pcp;
-
-               local_irq_save(flags);
-               if (pcp->count > 0)
-                       free_pcppages_bulk(zone, pcp->count, pcp);
-               drain_zonestat(zone, pset);
-               setup_pageset(pset, batch);
-               local_irq_restore(flags);
-       }
-       return 0;
-}
-
+/*
+ * The zone indicated has a new number of managed_pages; batch sizes and percpu
+ * page high values need to be recalulated.
+ */
 void __meminit zone_pcp_update(struct zone *zone)
 {
-       stop_machine(__zone_pcp_update, zone, NULL);
+       unsigned cpu;
+       mutex_lock(&pcp_batch_high_lock);
+       for_each_possible_cpu(cpu)
+               pageset_set_high_and_batch(zone,
+                               per_cpu_ptr(zone->pageset, cpu));
+       mutex_unlock(&pcp_batch_high_lock);
 }
 #endif
 
@@ -6142,6 +6248,10 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
                list_del(&page->lru);
                rmv_page_order(page);
                zone->free_area[order].nr_free--;
+#ifdef CONFIG_HIGHMEM
+               if (PageHighMem(page))
+                       totalhigh_pages -= 1 << order;
+#endif
                for (i = 0; i < (1 << order); i++)
                        SetPageReserved((page+i));
                pfn += (1 << order);
index a8a3ef45fed753b68ac1cc4a94c9260979a37879..ba05b64e5d8ddfc19f31c046f7c0b735d099364b 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/writeback.h>
 #include <linux/frontswap.h>
 #include <linux/aio.h>
+#include <linux/blkdev.h>
 #include <asm/pgtable.h>
 
 static struct bio *get_swap_bio(gfp_t gfp_flags,
@@ -80,9 +81,54 @@ void end_swap_bio_read(struct bio *bio, int err)
                                imajor(bio->bi_bdev->bd_inode),
                                iminor(bio->bi_bdev->bd_inode),
                                (unsigned long long)bio->bi_sector);
-       } else {
-               SetPageUptodate(page);
+               goto out;
        }
+
+       SetPageUptodate(page);
+
+       /*
+        * There is no guarantee that the page is in swap cache - the software
+        * suspend code (at least) uses end_swap_bio_read() against a non-
+        * swapcache page.  So we must check PG_swapcache before proceeding with
+        * this optimization.
+        */
+       if (likely(PageSwapCache(page))) {
+               struct swap_info_struct *sis;
+
+               sis = page_swap_info(page);
+               if (sis->flags & SWP_BLKDEV) {
+                       /*
+                        * The swap subsystem performs lazy swap slot freeing,
+                        * expecting that the page will be swapped out again.
+                        * So we can avoid an unnecessary write if the page
+                        * isn't redirtied.
+                        * This is good for real swap storage because we can
+                        * reduce unnecessary I/O and enhance wear-leveling
+                        * if an SSD is used as the as swap device.
+                        * But if in-memory swap device (eg zram) is used,
+                        * this causes a duplicated copy between uncompressed
+                        * data in VM-owned memory and compressed data in
+                        * zram-owned memory.  So let's free zram-owned memory
+                        * and make the VM-owned decompressed page *dirty*,
+                        * so the page should be swapped out somewhere again if
+                        * we again wish to reclaim it.
+                        */
+                       struct gendisk *disk = sis->bdev->bd_disk;
+                       if (disk->fops->swap_slot_free_notify) {
+                               swp_entry_t entry;
+                               unsigned long offset;
+
+                               entry.val = page_private(page);
+                               offset = swp_offset(entry);
+
+                               SetPageDirty(page);
+                               disk->fops->swap_slot_free_notify(sis->bdev,
+                                               offset);
+                       }
+               }
+       }
+
+out:
        unlock_page(page);
        bio_put(bio);
 }
index 6280da86b5d6761ed8a245c3fadb6e42015216c5..e22ceeb6e5ec8a07dafec758a55e26f8a590fe26 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1093,9 +1093,10 @@ void page_add_new_anon_rmap(struct page *page,
        else
                __inc_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
        __page_set_anon_rmap(page, vma, address, 1);
-       if (!mlocked_vma_newpage(vma, page))
-               lru_cache_add_lru(page, LRU_ACTIVE_ANON);
-       else
+       if (!mlocked_vma_newpage(vma, page)) {
+               SetPageActive(page);
+               lru_cache_add(page);
+       } else
                add_page_to_unevictable_list(page);
 }
 
index 5e6a8422658b832921196ca4908e7cc6148eb84a..a87990cf9f94019c70d7263d247c1c94945aee5b 100644 (file)
@@ -1798,10 +1798,7 @@ static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
                }
        }
 
-       if (offset >= 0 && offset != file->f_pos) {
-               file->f_pos = offset;
-               file->f_version = 0;
-       }
+       offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE);
        mutex_unlock(&inode->i_mutex);
        return offset;
 }
@@ -1939,6 +1936,13 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
 
        inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);
        if (inode) {
+#ifdef CONFIG_TMPFS_POSIX_ACL
+               error = generic_acl_init(inode, dir);
+               if (error) {
+                       iput(inode);
+                       return error;
+               }
+#endif
                error = security_inode_init_security(inode, dir,
                                                     &dentry->d_name,
                                                     shmem_initxattrs, NULL);
@@ -1948,6 +1952,33 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
                                return error;
                        }
                }
+
+               error = 0;
+               dir->i_size += BOGO_DIRENT_SIZE;
+               dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+               d_instantiate(dentry, inode);
+               dget(dentry); /* Extra count - pin the dentry in core */
+       }
+       return error;
+}
+
+static int
+shmem_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       struct inode *inode;
+       int error = -ENOSPC;
+
+       inode = shmem_get_inode(dir->i_sb, dir, mode, 0, VM_NORESERVE);
+       if (inode) {
+               error = security_inode_init_security(inode, dir,
+                                                    NULL,
+                                                    shmem_initxattrs, NULL);
+               if (error) {
+                       if (error != -EOPNOTSUPP) {
+                               iput(inode);
+                               return error;
+                       }
+               }
 #ifdef CONFIG_TMPFS_POSIX_ACL
                error = generic_acl_init(inode, dir);
                if (error) {
@@ -1957,10 +1988,7 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
 #else
                error = 0;
 #endif
-               dir->i_size += BOGO_DIRENT_SIZE;
-               dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-               d_instantiate(dentry, inode);
-               dget(dentry); /* Extra count - pin the dentry in core */
+               d_tmpfile(dentry, inode);
        }
        return error;
 }
@@ -2723,6 +2751,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
        .rmdir          = shmem_rmdir,
        .mknod          = shmem_mknod,
        .rename         = shmem_rename,
+       .tmpfile        = shmem_tmpfile,
 #endif
 #ifdef CONFIG_TMPFS_XATTR
        .setxattr       = shmem_setxattr,
index 1c91f0d3f6ab4a16476a0953d02b8e61331521ac..3194ec414728ffab13034cf0082ce2a6dff77a0b 100644 (file)
@@ -481,6 +481,9 @@ void __init sparse_init(void)
        struct page **map_map;
 #endif
 
+       /* see include/linux/mmzone.h 'struct mem_section' definition */
+       BUILD_BUG_ON(!is_power_of_2(sizeof(struct mem_section)));
+
        /* Setup pageblock_order for HUGETLB_PAGE_SIZE_VARIABLE */
        set_pageblock_order();
 
index dfd7d71d68418023b592c09a7d18c7a3ac4c5843..4a1d0d2c52fa4ab4ca66ff4a2025e093521556c9 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
 
 #include "internal.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/pagemap.h>
+
 /* How many pages do we try to swap or page in/out together? */
 int page_cluster;
 
-static DEFINE_PER_CPU(struct pagevec[NR_LRU_LISTS], lru_add_pvecs);
+static DEFINE_PER_CPU(struct pagevec, lru_add_pvec);
 static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs);
 static DEFINE_PER_CPU(struct pagevec, lru_deactivate_pvecs);
 
@@ -384,6 +387,7 @@ static void __activate_page(struct page *page, struct lruvec *lruvec,
                SetPageActive(page);
                lru += LRU_ACTIVE;
                add_page_to_lru_list(page, lruvec, lru);
+               trace_mm_lru_activate(page, page_to_pfn(page));
 
                __count_vm_event(PGACTIVATE);
                update_page_reclaim_stat(lruvec, file, 1);
@@ -428,6 +432,33 @@ void activate_page(struct page *page)
 }
 #endif
 
+static void __lru_cache_activate_page(struct page *page)
+{
+       struct pagevec *pvec = &get_cpu_var(lru_add_pvec);
+       int i;
+
+       /*
+        * Search backwards on the optimistic assumption that the page being
+        * activated has just been added to this pagevec. Note that only
+        * the local pagevec is examined as a !PageLRU page could be in the
+        * process of being released, reclaimed, migrated or on a remote
+        * pagevec that is currently being drained. Furthermore, marking
+        * a remote pagevec's page PageActive potentially hits a race where
+        * a page is marked PageActive just after it is added to the inactive
+        * list causing accounting errors and BUG_ON checks to trigger.
+        */
+       for (i = pagevec_count(pvec) - 1; i >= 0; i--) {
+               struct page *pagevec_page = pvec->pages[i];
+
+               if (pagevec_page == page) {
+                       SetPageActive(page);
+                       break;
+               }
+       }
+
+       put_cpu_var(lru_add_pvec);
+}
+
 /*
  * Mark a page as having seen activity.
  *
@@ -438,8 +469,18 @@ void activate_page(struct page *page)
 void mark_page_accessed(struct page *page)
 {
        if (!PageActive(page) && !PageUnevictable(page) &&
-                       PageReferenced(page) && PageLRU(page)) {
-               activate_page(page);
+                       PageReferenced(page)) {
+
+               /*
+                * If the page is on the LRU, queue it for activation via
+                * activate_page_pvecs. Otherwise, assume the page is on a
+                * pagevec, mark it active and it'll be moved to the active
+                * LRU on the next drain.
+                */
+               if (PageLRU(page))
+                       activate_page(page);
+               else
+                       __lru_cache_activate_page(page);
                ClearPageReferenced(page);
        } else if (!PageReferenced(page)) {
                SetPageReferenced(page);
@@ -448,42 +489,37 @@ void mark_page_accessed(struct page *page)
 EXPORT_SYMBOL(mark_page_accessed);
 
 /*
- * Order of operations is important: flush the pagevec when it's already
- * full, not when adding the last page, to make sure that last page is
- * not added to the LRU directly when passed to this function. Because
- * mark_page_accessed() (called after this when writing) only activates
- * pages that are on the LRU, linear writes in subpage chunks would see
- * every PAGEVEC_SIZE page activated, which is unexpected.
+ * Queue the page for addition to the LRU via pagevec. The decision on whether
+ * to add the page to the [in]active [file|anon] list is deferred until the
+ * pagevec is drained. This gives a chance for the caller of __lru_cache_add()
+ * have the page added to the active list using mark_page_accessed().
  */
-void __lru_cache_add(struct page *page, enum lru_list lru)
+void __lru_cache_add(struct page *page)
 {
-       struct pagevec *pvec = &get_cpu_var(lru_add_pvecs)[lru];
+       struct pagevec *pvec = &get_cpu_var(lru_add_pvec);
 
        page_cache_get(page);
        if (!pagevec_space(pvec))
-               __pagevec_lru_add(pvec, lru);
+               __pagevec_lru_add(pvec);
        pagevec_add(pvec, page);
-       put_cpu_var(lru_add_pvecs);
+       put_cpu_var(lru_add_pvec);
 }
 EXPORT_SYMBOL(__lru_cache_add);
 
 /**
- * lru_cache_add_lru - add a page to a page list
+ * lru_cache_add - add a page to a page list
  * @page: the page to be added to the LRU.
- * @lru: the LRU list to which the page is added.
  */
-void lru_cache_add_lru(struct page *page, enum lru_list lru)
+void lru_cache_add(struct page *page)
 {
        if (PageActive(page)) {
                VM_BUG_ON(PageUnevictable(page));
-               ClearPageActive(page);
        } else if (PageUnevictable(page)) {
                VM_BUG_ON(PageActive(page));
-               ClearPageUnevictable(page);
        }
 
-       VM_BUG_ON(PageLRU(page) || PageActive(page) || PageUnevictable(page));
-       __lru_cache_add(page, lru);
+       VM_BUG_ON(PageLRU(page));
+       __lru_cache_add(page);
 }
 
 /**
@@ -583,15 +619,10 @@ static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec,
  */
 void lru_add_drain_cpu(int cpu)
 {
-       struct pagevec *pvecs = per_cpu(lru_add_pvecs, cpu);
-       struct pagevec *pvec;
-       int lru;
+       struct pagevec *pvec = &per_cpu(lru_add_pvec, cpu);
 
-       for_each_lru(lru) {
-               pvec = &pvecs[lru - LRU_BASE];
-               if (pagevec_count(pvec))
-                       __pagevec_lru_add(pvec, lru);
-       }
+       if (pagevec_count(pvec))
+               __pagevec_lru_add(pvec);
 
        pvec = &per_cpu(lru_rotate_pvecs, cpu);
        if (pagevec_count(pvec)) {
@@ -708,6 +739,9 @@ void release_pages(struct page **pages, int nr, int cold)
                        del_page_from_lru_list(page, lruvec, page_off_lru(page));
                }
 
+               /* Clear Active bit in case of parallel mark_page_accessed */
+               ClearPageActive(page);
+
                list_add(&page->lru, &pages_to_free);
        }
        if (zone)
@@ -795,30 +829,26 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
 static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec,
                                 void *arg)
 {
-       enum lru_list lru = (enum lru_list)arg;
-       int file = is_file_lru(lru);
-       int active = is_active_lru(lru);
+       int file = page_is_file_cache(page);
+       int active = PageActive(page);
+       enum lru_list lru = page_lru(page);
 
-       VM_BUG_ON(PageActive(page));
        VM_BUG_ON(PageUnevictable(page));
        VM_BUG_ON(PageLRU(page));
 
        SetPageLRU(page);
-       if (active)
-               SetPageActive(page);
        add_page_to_lru_list(page, lruvec, lru);
        update_page_reclaim_stat(lruvec, file, active);
+       trace_mm_lru_insertion(page, page_to_pfn(page), lru, trace_pagemap_flags(page));
 }
 
 /*
  * Add the passed pages to the LRU, then drop the caller's refcount
  * on them.  Reinitialises the caller's pagevec.
  */
-void __pagevec_lru_add(struct pagevec *pvec, enum lru_list lru)
+void __pagevec_lru_add(struct pagevec *pvec)
 {
-       VM_BUG_ON(is_unevictable_lru(lru));
-
-       pagevec_lru_move_fn(pvec, __pagevec_lru_add_fn, (void *)lru);
+       pagevec_lru_move_fn(pvec, __pagevec_lru_add_fn, NULL);
 }
 EXPORT_SYMBOL(__pagevec_lru_add);
 
index 746af55b8455ce0e9280b81c78e0ee5f2316f5d4..36af6eeaa67eaa0532442706e668e9a268596c90 100644 (file)
@@ -212,7 +212,7 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
                        si->cluster_nr = SWAPFILE_CLUSTER - 1;
                        goto checks;
                }
-               if (si->flags & SWP_DISCARDABLE) {
+               if (si->flags & SWP_PAGE_DISCARD) {
                        /*
                         * Start range check on racing allocations, in case
                         * they overlap the cluster we eventually decide on
@@ -322,7 +322,7 @@ checks:
 
        if (si->lowest_alloc) {
                /*
-                * Only set when SWP_DISCARDABLE, and there's a scan
+                * Only set when SWP_PAGE_DISCARD, and there's a scan
                 * for a free cluster in progress or just completed.
                 */
                if (found_free_cluster) {
@@ -2016,6 +2016,20 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p,
        return nr_extents;
 }
 
+/*
+ * Helper to sys_swapon determining if a given swap
+ * backing device queue supports DISCARD operations.
+ */
+static bool swap_discardable(struct swap_info_struct *si)
+{
+       struct request_queue *q = bdev_get_queue(si->bdev);
+
+       if (!q || !blk_queue_discard(q))
+               return false;
+
+       return true;
+}
+
 SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
 {
        struct swap_info_struct *p;
@@ -2123,8 +2137,37 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
                        p->flags |= SWP_SOLIDSTATE;
                        p->cluster_next = 1 + (prandom_u32() % p->highest_bit);
                }
-               if ((swap_flags & SWAP_FLAG_DISCARD) && discard_swap(p) == 0)
-                       p->flags |= SWP_DISCARDABLE;
+
+               if ((swap_flags & SWAP_FLAG_DISCARD) && swap_discardable(p)) {
+                       /*
+                        * When discard is enabled for swap with no particular
+                        * policy flagged, we set all swap discard flags here in
+                        * order to sustain backward compatibility with older
+                        * swapon(8) releases.
+                        */
+                       p->flags |= (SWP_DISCARDABLE | SWP_AREA_DISCARD |
+                                    SWP_PAGE_DISCARD);
+
+                       /*
+                        * By flagging sys_swapon, a sysadmin can tell us to
+                        * either do single-time area discards only, or to just
+                        * perform discards for released swap page-clusters.
+                        * Now it's time to adjust the p->flags accordingly.
+                        */
+                       if (swap_flags & SWAP_FLAG_DISCARD_ONCE)
+                               p->flags &= ~SWP_PAGE_DISCARD;
+                       else if (swap_flags & SWAP_FLAG_DISCARD_PAGES)
+                               p->flags &= ~SWP_AREA_DISCARD;
+
+                       /* issue a swapon-time discard if it's still required */
+                       if (p->flags & SWP_AREA_DISCARD) {
+                               int err = discard_swap(p);
+                               if (unlikely(err))
+                                       printk(KERN_ERR
+                                              "swapon: discard_swap(%p): %d\n",
+                                               p, err);
+                       }
+               }
        }
 
        mutex_lock(&swapon_mutex);
@@ -2135,11 +2178,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        enable_swap_info(p, prio, swap_map, frontswap_map);
 
        printk(KERN_INFO "Adding %uk swap on %s.  "
-                       "Priority:%d extents:%d across:%lluk %s%s%s\n",
+                       "Priority:%d extents:%d across:%lluk %s%s%s%s%s\n",
                p->pages<<(PAGE_SHIFT-10), name->name, p->prio,
                nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10),
                (p->flags & SWP_SOLIDSTATE) ? "SS" : "",
                (p->flags & SWP_DISCARDABLE) ? "D" : "",
+               (p->flags & SWP_AREA_DISCARD) ? "s" : "",
+               (p->flags & SWP_PAGE_DISCARD) ? "c" : "",
                (frontswap_map) ? "FS" : "");
 
        mutex_unlock(&swapon_mutex);
index d365724feb05206fc0b37c852f5859499f1cb6b3..91a10472a39a833b29ae0be1faeb6c30c72c0160 100644 (file)
@@ -292,7 +292,7 @@ static struct vmap_area *__find_vmap_area(unsigned long addr)
                va = rb_entry(n, struct vmap_area, rb_node);
                if (addr < va->va_start)
                        n = n->rb_left;
-               else if (addr > va->va_start)
+               else if (addr >= va->va_end)
                        n = n->rb_right;
                else
                        return va;
@@ -1322,13 +1322,6 @@ static void clear_vm_unlist(struct vm_struct *vm)
        vm->flags &= ~VM_UNLIST;
 }
 
-static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
-                             unsigned long flags, const void *caller)
-{
-       setup_vmalloc_vm(vm, va, flags, caller);
-       clear_vm_unlist(vm);
-}
-
 static struct vm_struct *__get_vm_area_node(unsigned long size,
                unsigned long align, unsigned long flags, unsigned long start,
                unsigned long end, int node, gfp_t gfp_mask, const void *caller)
@@ -1337,16 +1330,8 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
        struct vm_struct *area;
 
        BUG_ON(in_interrupt());
-       if (flags & VM_IOREMAP) {
-               int bit = fls(size);
-
-               if (bit > IOREMAP_MAX_ORDER)
-                       bit = IOREMAP_MAX_ORDER;
-               else if (bit < PAGE_SHIFT)
-                       bit = PAGE_SHIFT;
-
-               align = 1ul << bit;
-       }
+       if (flags & VM_IOREMAP)
+               align = 1ul << clamp(fls(size), PAGE_SHIFT, IOREMAP_MAX_ORDER);
 
        size = PAGE_ALIGN(size);
        if (unlikely(!size))
@@ -1367,16 +1352,7 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
                return NULL;
        }
 
-       /*
-        * When this function is called from __vmalloc_node_range,
-        * we add VM_UNLIST flag to avoid accessing uninitialized
-        * members of vm_struct such as pages and nr_pages fields.
-        * They will be set later.
-        */
-       if (flags & VM_UNLIST)
-               setup_vmalloc_vm(area, va, flags, caller);
-       else
-               insert_vmalloc_vm(area, va, flags, caller);
+       setup_vmalloc_vm(area, va, flags, caller);
 
        return area;
 }
@@ -1476,10 +1452,9 @@ static void __vunmap(const void *addr, int deallocate_pages)
        if (!addr)
                return;
 
-       if ((PAGE_SIZE-1) & (unsigned long)addr) {
-               WARN(1, KERN_ERR "Trying to vfree() bad address (%p)\n", addr);
+       if (WARN(!PAGE_ALIGNED(addr), "Trying to vfree() bad address (%p)\n",
+                       addr));
                return;
-       }
 
        area = remove_vm_area(addr);
        if (unlikely(!area)) {
@@ -2148,42 +2123,43 @@ finished:
 }
 
 /**
- *     remap_vmalloc_range  -  map vmalloc pages to userspace
- *     @vma:           vma to cover (map full range of vma)
- *     @addr:          vmalloc memory
- *     @pgoff:         number of pages into addr before first page to map
+ *     remap_vmalloc_range_partial  -  map vmalloc pages to userspace
+ *     @vma:           vma to cover
+ *     @uaddr:         target user address to start at
+ *     @kaddr:         virtual address of vmalloc kernel memory
+ *     @size:          size of map area
  *
  *     Returns:        0 for success, -Exxx on failure
  *
- *     This function checks that addr is a valid vmalloc'ed area, and
- *     that it is big enough to cover the vma. Will return failure if
- *     that criteria isn't met.
+ *     This function checks that @kaddr is a valid vmalloc'ed area,
+ *     and that it is big enough to cover the range starting at
+ *     @uaddr in @vma. Will return failure if that criteria isn't
+ *     met.
  *
  *     Similar to remap_pfn_range() (see mm/memory.c)
  */
-int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
-                                               unsigned long pgoff)
+int remap_vmalloc_range_partial(struct vm_area_struct *vma, unsigned long uaddr,
+                               void *kaddr, unsigned long size)
 {
        struct vm_struct *area;
-       unsigned long uaddr = vma->vm_start;
-       unsigned long usize = vma->vm_end - vma->vm_start;
 
-       if ((PAGE_SIZE-1) & (unsigned long)addr)
+       size = PAGE_ALIGN(size);
+
+       if (!PAGE_ALIGNED(uaddr) || !PAGE_ALIGNED(kaddr))
                return -EINVAL;
 
-       area = find_vm_area(addr);
+       area = find_vm_area(kaddr);
        if (!area)
                return -EINVAL;
 
        if (!(area->flags & VM_USERMAP))
                return -EINVAL;
 
-       if (usize + (pgoff << PAGE_SHIFT) > area->size - PAGE_SIZE)
+       if (kaddr + size > area->addr + area->size)
                return -EINVAL;
 
-       addr += pgoff << PAGE_SHIFT;
        do {
-               struct page *page = vmalloc_to_page(addr);
+               struct page *page = vmalloc_to_page(kaddr);
                int ret;
 
                ret = vm_insert_page(vma, uaddr, page);
@@ -2191,14 +2167,37 @@ int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
                        return ret;
 
                uaddr += PAGE_SIZE;
-               addr += PAGE_SIZE;
-               usize -= PAGE_SIZE;
-       } while (usize > 0);
+               kaddr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       } while (size > 0);
 
        vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 
        return 0;
 }
+EXPORT_SYMBOL(remap_vmalloc_range_partial);
+
+/**
+ *     remap_vmalloc_range  -  map vmalloc pages to userspace
+ *     @vma:           vma to cover (map full range of vma)
+ *     @addr:          vmalloc memory
+ *     @pgoff:         number of pages into addr before first page to map
+ *
+ *     Returns:        0 for success, -Exxx on failure
+ *
+ *     This function checks that addr is a valid vmalloc'ed area, and
+ *     that it is big enough to cover the vma. Will return failure if
+ *     that criteria isn't met.
+ *
+ *     Similar to remap_pfn_range() (see mm/memory.c)
+ */
+int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
+                                               unsigned long pgoff)
+{
+       return remap_vmalloc_range_partial(vma, vma->vm_start,
+                                          addr + (pgoff << PAGE_SHIFT),
+                                          vma->vm_end - vma->vm_start);
+}
 EXPORT_SYMBOL(remap_vmalloc_range);
 
 /*
@@ -2512,8 +2511,8 @@ found:
 
        /* insert all vm's */
        for (area = 0; area < nr_vms; area++)
-               insert_vmalloc_vm(vms[area], vas[area], VM_ALLOC,
-                                 pcpu_get_vm_areas);
+               setup_vmalloc_vm(vms[area], vas[area], VM_ALLOC,
+                                pcpu_get_vm_areas);
 
        kfree(vas);
        return vms;
index fa6a85378ee41400985aca748cd76b59c0f87594..99b3ac7771ada907f36e1fbee15bddd524a1db23 100644 (file)
@@ -546,7 +546,6 @@ int remove_mapping(struct address_space *mapping, struct page *page)
 void putback_lru_page(struct page *page)
 {
        int lru;
-       int active = !!TestClearPageActive(page);
        int was_unevictable = PageUnevictable(page);
 
        VM_BUG_ON(PageLRU(page));
@@ -561,8 +560,8 @@ redo:
                 * unevictable page on [in]active list.
                 * We know how to handle that.
                 */
-               lru = active + page_lru_base_type(page);
-               lru_cache_add_lru(page, lru);
+               lru = page_lru_base_type(page);
+               lru_cache_add(page);
        } else {
                /*
                 * Put unevictable pages directly on zone's unevictable
@@ -669,6 +668,35 @@ static enum page_references page_check_references(struct page *page,
        return PAGEREF_RECLAIM;
 }
 
+/* Check if a page is dirty or under writeback */
+static void page_check_dirty_writeback(struct page *page,
+                                      bool *dirty, bool *writeback)
+{
+       struct address_space *mapping;
+
+       /*
+        * Anonymous pages are not handled by flushers and must be written
+        * from reclaim context. Do not stall reclaim based on them
+        */
+       if (!page_is_file_cache(page)) {
+               *dirty = false;
+               *writeback = false;
+               return;
+       }
+
+       /* By default assume that the page flags are accurate */
+       *dirty = PageDirty(page);
+       *writeback = PageWriteback(page);
+
+       /* Verify dirty/writeback state if the filesystem supports it */
+       if (!page_has_private(page))
+               return;
+
+       mapping = page_mapping(page);
+       if (mapping && mapping->a_ops->is_dirty_writeback)
+               mapping->a_ops->is_dirty_writeback(page, dirty, writeback);
+}
+
 /*
  * shrink_page_list() returns the number of reclaimed pages
  */
@@ -677,16 +705,21 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                                      struct scan_control *sc,
                                      enum ttu_flags ttu_flags,
                                      unsigned long *ret_nr_dirty,
+                                     unsigned long *ret_nr_unqueued_dirty,
+                                     unsigned long *ret_nr_congested,
                                      unsigned long *ret_nr_writeback,
+                                     unsigned long *ret_nr_immediate,
                                      bool force_reclaim)
 {
        LIST_HEAD(ret_pages);
        LIST_HEAD(free_pages);
        int pgactivate = 0;
+       unsigned long nr_unqueued_dirty = 0;
        unsigned long nr_dirty = 0;
        unsigned long nr_congested = 0;
        unsigned long nr_reclaimed = 0;
        unsigned long nr_writeback = 0;
+       unsigned long nr_immediate = 0;
 
        cond_resched();
 
@@ -696,6 +729,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                struct page *page;
                int may_enter_fs;
                enum page_references references = PAGEREF_RECLAIM_CLEAN;
+               bool dirty, writeback;
 
                cond_resched();
 
@@ -723,25 +757,77 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                may_enter_fs = (sc->gfp_mask & __GFP_FS) ||
                        (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO));
 
+               /*
+                * The number of dirty pages determines if a zone is marked
+                * reclaim_congested which affects wait_iff_congested. kswapd
+                * will stall and start writing pages if the tail of the LRU
+                * is all dirty unqueued pages.
+                */
+               page_check_dirty_writeback(page, &dirty, &writeback);
+               if (dirty || writeback)
+                       nr_dirty++;
+
+               if (dirty && !writeback)
+                       nr_unqueued_dirty++;
+
+               /*
+                * Treat this page as congested if the underlying BDI is or if
+                * pages are cycling through the LRU so quickly that the
+                * pages marked for immediate reclaim are making it to the
+                * end of the LRU a second time.
+                */
+               mapping = page_mapping(page);
+               if ((mapping && bdi_write_congested(mapping->backing_dev_info)) ||
+                   (writeback && PageReclaim(page)))
+                       nr_congested++;
+
+               /*
+                * If a page at the tail of the LRU is under writeback, there
+                * are three cases to consider.
+                *
+                * 1) If reclaim is encountering an excessive number of pages
+                *    under writeback and this page is both under writeback and
+                *    PageReclaim then it indicates that pages are being queued
+                *    for IO but are being recycled through the LRU before the
+                *    IO can complete. Waiting on the page itself risks an
+                *    indefinite stall if it is impossible to writeback the
+                *    page due to IO error or disconnected storage so instead
+                *    note that the LRU is being scanned too quickly and the
+                *    caller can stall after page list has been processed.
+                *
+                * 2) Global reclaim encounters a page, memcg encounters a
+                *    page that is not marked for immediate reclaim or
+                *    the caller does not have __GFP_IO. In this case mark
+                *    the page for immediate reclaim and continue scanning.
+                *
+                *    __GFP_IO is checked  because a loop driver thread might
+                *    enter reclaim, and deadlock if it waits on a page for
+                *    which it is needed to do the write (loop masks off
+                *    __GFP_IO|__GFP_FS for this reason); but more thought
+                *    would probably show more reasons.
+                *
+                *    Don't require __GFP_FS, since we're not going into the
+                *    FS, just waiting on its writeback completion. Worryingly,
+                *    ext4 gfs2 and xfs allocate pages with
+                *    grab_cache_page_write_begin(,,AOP_FLAG_NOFS), so testing
+                *    may_enter_fs here is liable to OOM on them.
+                *
+                * 3) memcg encounters a page that is not already marked
+                *    PageReclaim. memcg does not have any dirty pages
+                *    throttling so we could easily OOM just because too many
+                *    pages are in writeback and there is nothing else to
+                *    reclaim. Wait for the writeback to complete.
+                */
                if (PageWriteback(page)) {
-                       /*
-                        * memcg doesn't have any dirty pages throttling so we
-                        * could easily OOM just because too many pages are in
-                        * writeback and there is nothing else to reclaim.
-                        *
-                        * Check __GFP_IO, certainly because a loop driver
-                        * thread might enter reclaim, and deadlock if it waits
-                        * on a page for which it is needed to do the write
-                        * (loop masks off __GFP_IO|__GFP_FS for this reason);
-                        * but more thought would probably show more reasons.
-                        *
-                        * Don't require __GFP_FS, since we're not going into
-                        * the FS, just waiting on its writeback completion.
-                        * Worryingly, ext4 gfs2 and xfs allocate pages with
-                        * grab_cache_page_write_begin(,,AOP_FLAG_NOFS), so
-                        * testing may_enter_fs here is liable to OOM on them.
-                        */
-                       if (global_reclaim(sc) ||
+                       /* Case 1 above */
+                       if (current_is_kswapd() &&
+                           PageReclaim(page) &&
+                           zone_is_reclaim_writeback(zone)) {
+                               nr_immediate++;
+                               goto keep_locked;
+
+                       /* Case 2 above */
+                       } else if (global_reclaim(sc) ||
                            !PageReclaim(page) || !(sc->gfp_mask & __GFP_IO)) {
                                /*
                                 * This is slightly racy - end_page_writeback()
@@ -756,9 +842,13 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                                 */
                                SetPageReclaim(page);
                                nr_writeback++;
+
                                goto keep_locked;
+
+                       /* Case 3 above */
+                       } else {
+                               wait_on_page_writeback(page);
                        }
-                       wait_on_page_writeback(page);
                }
 
                if (!force_reclaim)
@@ -784,9 +874,10 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        if (!add_to_swap(page, page_list))
                                goto activate_locked;
                        may_enter_fs = 1;
-               }
 
-               mapping = page_mapping(page);
+                       /* Adding to swap updated mapping */
+                       mapping = page_mapping(page);
+               }
 
                /*
                 * The page is mapped into the page tables of one or more
@@ -806,16 +897,14 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                }
 
                if (PageDirty(page)) {
-                       nr_dirty++;
-
                        /*
                         * Only kswapd can writeback filesystem pages to
-                        * avoid risk of stack overflow but do not writeback
-                        * unless under significant pressure.
+                        * avoid risk of stack overflow but only writeback
+                        * if many dirty pages have been encountered.
                         */
                        if (page_is_file_cache(page) &&
                                        (!current_is_kswapd() ||
-                                        sc->priority >= DEF_PRIORITY - 2)) {
+                                        !zone_is_reclaim_dirty(zone))) {
                                /*
                                 * Immediately reclaim when written back.
                                 * Similar in principal to deactivate_page()
@@ -838,7 +927,6 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        /* Page is dirty, try to write it out here */
                        switch (pageout(page, mapping, sc)) {
                        case PAGE_KEEP:
-                               nr_congested++;
                                goto keep_locked;
                        case PAGE_ACTIVATE:
                                goto activate_locked;
@@ -946,22 +1034,16 @@ keep:
                VM_BUG_ON(PageLRU(page) || PageUnevictable(page));
        }
 
-       /*
-        * Tag a zone as congested if all the dirty pages encountered were
-        * backed by a congested BDI. In this case, reclaimers should just
-        * back off and wait for congestion to clear because further reclaim
-        * will encounter the same problem
-        */
-       if (nr_dirty && nr_dirty == nr_congested && global_reclaim(sc))
-               zone_set_flag(zone, ZONE_CONGESTED);
-
        free_hot_cold_page_list(&free_pages, 1);
 
        list_splice(&ret_pages, page_list);
        count_vm_events(PGACTIVATE, pgactivate);
        mem_cgroup_uncharge_end();
        *ret_nr_dirty += nr_dirty;
+       *ret_nr_congested += nr_congested;
+       *ret_nr_unqueued_dirty += nr_unqueued_dirty;
        *ret_nr_writeback += nr_writeback;
+       *ret_nr_immediate += nr_immediate;
        return nr_reclaimed;
 }
 
@@ -973,7 +1055,7 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
                .priority = DEF_PRIORITY,
                .may_unmap = 1,
        };
-       unsigned long ret, dummy1, dummy2;
+       unsigned long ret, dummy1, dummy2, dummy3, dummy4, dummy5;
        struct page *page, *next;
        LIST_HEAD(clean_pages);
 
@@ -985,8 +1067,8 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
        }
 
        ret = shrink_page_list(&clean_pages, zone, &sc,
-                               TTU_UNMAP|TTU_IGNORE_ACCESS,
-                               &dummy1, &dummy2, true);
+                       TTU_UNMAP|TTU_IGNORE_ACCESS,
+                       &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, true);
        list_splice(&clean_pages, page_list);
        __mod_zone_page_state(zone, NR_ISOLATED_FILE, -ret);
        return ret;
@@ -1281,7 +1363,10 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
        unsigned long nr_reclaimed = 0;
        unsigned long nr_taken;
        unsigned long nr_dirty = 0;
+       unsigned long nr_congested = 0;
+       unsigned long nr_unqueued_dirty = 0;
        unsigned long nr_writeback = 0;
+       unsigned long nr_immediate = 0;
        isolate_mode_t isolate_mode = 0;
        int file = is_file_lru(lru);
        struct zone *zone = lruvec_zone(lruvec);
@@ -1323,7 +1408,9 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
                return 0;
 
        nr_reclaimed = shrink_page_list(&page_list, zone, sc, TTU_UNMAP,
-                                       &nr_dirty, &nr_writeback, false);
+                               &nr_dirty, &nr_unqueued_dirty, &nr_congested,
+                               &nr_writeback, &nr_immediate,
+                               false);
 
        spin_lock_irq(&zone->lru_lock);
 
@@ -1357,7 +1444,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
         * same way balance_dirty_pages() manages.
         *
         * This scales the number of dirty pages that must be under writeback
-        * before throttling depending on priority. It is a simple backoff
+        * before a zone gets flagged ZONE_WRITEBACK. It is a simple backoff
         * function that has the most effect in the range DEF_PRIORITY to
         * DEF_PRIORITY-2 which is the priority reclaim is considered to be
         * in trouble and reclaim is considered to be in trouble.
@@ -1368,9 +1455,53 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
         * ...
         * DEF_PRIORITY-6 For SWAP_CLUSTER_MAX isolated pages, throttle if any
         *                     isolated page is PageWriteback
+        *
+        * Once a zone is flagged ZONE_WRITEBACK, kswapd will count the number
+        * of pages under pages flagged for immediate reclaim and stall if any
+        * are encountered in the nr_immediate check below.
         */
        if (nr_writeback && nr_writeback >=
                        (nr_taken >> (DEF_PRIORITY - sc->priority)))
+               zone_set_flag(zone, ZONE_WRITEBACK);
+
+       /*
+        * memcg will stall in page writeback so only consider forcibly
+        * stalling for global reclaim
+        */
+       if (global_reclaim(sc)) {
+               /*
+                * Tag a zone as congested if all the dirty pages scanned were
+                * backed by a congested BDI and wait_iff_congested will stall.
+                */
+               if (nr_dirty && nr_dirty == nr_congested)
+                       zone_set_flag(zone, ZONE_CONGESTED);
+
+               /*
+                * If dirty pages are scanned that are not queued for IO, it
+                * implies that flushers are not keeping up. In this case, flag
+                * the zone ZONE_TAIL_LRU_DIRTY and kswapd will start writing
+                * pages from reclaim context. It will forcibly stall in the
+                * next check.
+                */
+               if (nr_unqueued_dirty == nr_taken)
+                       zone_set_flag(zone, ZONE_TAIL_LRU_DIRTY);
+
+               /*
+                * In addition, if kswapd scans pages marked marked for
+                * immediate reclaim and under writeback (nr_immediate), it
+                * implies that pages are cycling through the LRU faster than
+                * they are written so also forcibly stall.
+                */
+               if (nr_unqueued_dirty == nr_taken || nr_immediate)
+                       congestion_wait(BLK_RW_ASYNC, HZ/10);
+       }
+
+       /*
+        * Stall direct reclaim for IO completions if underlying BDIs or zone
+        * is congested. Allow kswapd to continue until it starts encountering
+        * unqueued dirty pages or cycling through the LRU too quickly.
+        */
+       if (!sc->hibernation_mode && !current_is_kswapd())
                wait_iff_congested(zone, BLK_RW_ASYNC, HZ/10);
 
        trace_mm_vmscan_lru_shrink_inactive(zone->zone_pgdat->node_id,
@@ -1822,17 +1953,25 @@ out:
 static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
 {
        unsigned long nr[NR_LRU_LISTS];
+       unsigned long targets[NR_LRU_LISTS];
        unsigned long nr_to_scan;
        enum lru_list lru;
        unsigned long nr_reclaimed = 0;
        unsigned long nr_to_reclaim = sc->nr_to_reclaim;
        struct blk_plug plug;
+       bool scan_adjusted = false;
 
        get_scan_count(lruvec, sc, nr);
 
+       /* Record the original scan target for proportional adjustments later */
+       memcpy(targets, nr, sizeof(nr));
+
        blk_start_plug(&plug);
        while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
                                        nr[LRU_INACTIVE_FILE]) {
+               unsigned long nr_anon, nr_file, percentage;
+               unsigned long nr_scanned;
+
                for_each_evictable_lru(lru) {
                        if (nr[lru]) {
                                nr_to_scan = min(nr[lru], SWAP_CLUSTER_MAX);
@@ -1842,17 +1981,60 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
                                                            lruvec, sc);
                        }
                }
+
+               if (nr_reclaimed < nr_to_reclaim || scan_adjusted)
+                       continue;
+
                /*
-                * On large memory systems, scan >> priority can become
-                * really large. This is fine for the starting priority;
-                * we want to put equal scanning pressure on each zone.
-                * However, if the VM has a harder time of freeing pages,
-                * with multiple processes reclaiming pages, the total
-                * freeing target can get unreasonably large.
+                * For global direct reclaim, reclaim only the number of pages
+                * requested. Less care is taken to scan proportionally as it
+                * is more important to minimise direct reclaim stall latency
+                * than it is to properly age the LRU lists.
                 */
-               if (nr_reclaimed >= nr_to_reclaim &&
-                   sc->priority < DEF_PRIORITY)
+               if (global_reclaim(sc) && !current_is_kswapd())
                        break;
+
+               /*
+                * For kswapd and memcg, reclaim at least the number of pages
+                * requested. Ensure that the anon and file LRUs shrink
+                * proportionally what was requested by get_scan_count(). We
+                * stop reclaiming one LRU and reduce the amount scanning
+                * proportional to the original scan target.
+                */
+               nr_file = nr[LRU_INACTIVE_FILE] + nr[LRU_ACTIVE_FILE];
+               nr_anon = nr[LRU_INACTIVE_ANON] + nr[LRU_ACTIVE_ANON];
+
+               if (nr_file > nr_anon) {
+                       unsigned long scan_target = targets[LRU_INACTIVE_ANON] +
+                                               targets[LRU_ACTIVE_ANON] + 1;
+                       lru = LRU_BASE;
+                       percentage = nr_anon * 100 / scan_target;
+               } else {
+                       unsigned long scan_target = targets[LRU_INACTIVE_FILE] +
+                                               targets[LRU_ACTIVE_FILE] + 1;
+                       lru = LRU_FILE;
+                       percentage = nr_file * 100 / scan_target;
+               }
+
+               /* Stop scanning the smaller of the LRU */
+               nr[lru] = 0;
+               nr[lru + LRU_ACTIVE] = 0;
+
+               /*
+                * Recalculate the other LRU scan count based on its original
+                * scan target and the percentage scanning already complete
+                */
+               lru = (lru == LRU_FILE) ? LRU_BASE : LRU_FILE;
+               nr_scanned = targets[lru] - nr[lru];
+               nr[lru] = targets[lru] * (100 - percentage) / 100;
+               nr[lru] -= min(nr[lru], nr_scanned);
+
+               lru += LRU_ACTIVE;
+               nr_scanned = targets[lru] - nr[lru];
+               nr[lru] = targets[lru] * (100 - percentage) / 100;
+               nr[lru] -= min(nr[lru], nr_scanned);
+
+               scan_adjusted = true;
        }
        blk_finish_plug(&plug);
        sc->nr_reclaimed += nr_reclaimed;
@@ -2222,17 +2404,6 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                                                WB_REASON_TRY_TO_FREE_PAGES);
                        sc->may_writepage = 1;
                }
-
-               /* Take a nap, wait for some writeback to complete */
-               if (!sc->hibernation_mode && sc->nr_scanned &&
-                   sc->priority < DEF_PRIORITY - 2) {
-                       struct zone *preferred_zone;
-
-                       first_zones_zonelist(zonelist, gfp_zone(sc->gfp_mask),
-                                               &cpuset_current_mems_allowed,
-                                               &preferred_zone);
-                       wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/10);
-               }
        } while (--sc->priority >= 0);
 
 out:
@@ -2600,6 +2771,91 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
        return pgdat_balanced(pgdat, order, classzone_idx);
 }
 
+/*
+ * kswapd shrinks the zone by the number of pages required to reach
+ * the high watermark.
+ *
+ * Returns true if kswapd scanned at least the requested number of pages to
+ * reclaim or if the lack of progress was due to pages under writeback.
+ * This is used to determine if the scanning priority needs to be raised.
+ */
+static bool kswapd_shrink_zone(struct zone *zone,
+                              int classzone_idx,
+                              struct scan_control *sc,
+                              unsigned long lru_pages,
+                              unsigned long *nr_attempted)
+{
+       unsigned long nr_slab;
+       int testorder = sc->order;
+       unsigned long balance_gap;
+       struct reclaim_state *reclaim_state = current->reclaim_state;
+       struct shrink_control shrink = {
+               .gfp_mask = sc->gfp_mask,
+       };
+       bool lowmem_pressure;
+
+       /* Reclaim above the high watermark. */
+       sc->nr_to_reclaim = max(SWAP_CLUSTER_MAX, high_wmark_pages(zone));
+
+       /*
+        * Kswapd reclaims only single pages with compaction enabled. Trying
+        * too hard to reclaim until contiguous free pages have become
+        * available can hurt performance by evicting too much useful data
+        * from memory. Do not reclaim more than needed for compaction.
+        */
+       if (IS_ENABLED(CONFIG_COMPACTION) && sc->order &&
+                       compaction_suitable(zone, sc->order) !=
+                               COMPACT_SKIPPED)
+               testorder = 0;
+
+       /*
+        * We put equal pressure on every zone, unless one zone has way too
+        * many pages free already. The "too many pages" is defined as the
+        * high wmark plus a "gap" where the gap is either the low
+        * watermark or 1% of the zone, whichever is smaller.
+        */
+       balance_gap = min(low_wmark_pages(zone),
+               (zone->managed_pages + KSWAPD_ZONE_BALANCE_GAP_RATIO-1) /
+               KSWAPD_ZONE_BALANCE_GAP_RATIO);
+
+       /*
+        * If there is no low memory pressure or the zone is balanced then no
+        * reclaim is necessary
+        */
+       lowmem_pressure = (buffer_heads_over_limit && is_highmem(zone));
+       if (!lowmem_pressure && zone_balanced(zone, testorder,
+                                               balance_gap, classzone_idx))
+               return true;
+
+       shrink_zone(zone, sc);
+
+       reclaim_state->reclaimed_slab = 0;
+       nr_slab = shrink_slab(&shrink, sc->nr_scanned, lru_pages);
+       sc->nr_reclaimed += reclaim_state->reclaimed_slab;
+
+       /* Account for the number of pages attempted to reclaim */
+       *nr_attempted += sc->nr_to_reclaim;
+
+       if (nr_slab == 0 && !zone_reclaimable(zone))
+               zone->all_unreclaimable = 1;
+
+       zone_clear_flag(zone, ZONE_WRITEBACK);
+
+       /*
+        * If a zone reaches its high watermark, consider it to be no longer
+        * congested. It's possible there are dirty pages backed by congested
+        * BDIs but as pressure is relieved, speculatively avoid congestion
+        * waits.
+        */
+       if (!zone->all_unreclaimable &&
+           zone_balanced(zone, testorder, 0, classzone_idx)) {
+               zone_clear_flag(zone, ZONE_CONGESTED);
+               zone_clear_flag(zone, ZONE_TAIL_LRU_DIRTY);
+       }
+
+       return sc->nr_scanned >= sc->nr_to_reclaim;
+}
+
 /*
  * For kswapd, balance_pgdat() will work across all this node's zones until
  * they are all at high_wmark_pages(zone).
@@ -2624,35 +2880,28 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
 static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
                                                        int *classzone_idx)
 {
-       bool pgdat_is_balanced = false;
        int i;
        int end_zone = 0;       /* Inclusive.  0 = ZONE_DMA */
-       struct reclaim_state *reclaim_state = current->reclaim_state;
        unsigned long nr_soft_reclaimed;
        unsigned long nr_soft_scanned;
        struct scan_control sc = {
                .gfp_mask = GFP_KERNEL,
+               .priority = DEF_PRIORITY,
                .may_unmap = 1,
                .may_swap = 1,
-               /*
-                * kswapd doesn't want to be bailed out while reclaim. because
-                * we want to put equal scanning pressure on each zone.
-                */
-               .nr_to_reclaim = ULONG_MAX,
+               .may_writepage = !laptop_mode,
                .order = order,
                .target_mem_cgroup = NULL,
        };
-       struct shrink_control shrink = {
-               .gfp_mask = sc.gfp_mask,
-       };
-loop_again:
-       sc.priority = DEF_PRIORITY;
-       sc.nr_reclaimed = 0;
-       sc.may_writepage = !laptop_mode;
        count_vm_event(PAGEOUTRUN);
 
        do {
                unsigned long lru_pages = 0;
+               unsigned long nr_attempted = 0;
+               bool raise_priority = true;
+               bool pgdat_needs_compaction = (order > 0);
+
+               sc.nr_reclaimed = 0;
 
                /*
                 * Scan in the highmem->dma direction for the highest
@@ -2689,22 +2938,45 @@ loop_again:
                                end_zone = i;
                                break;
                        } else {
-                               /* If balanced, clear the congested flag */
+                               /*
+                                * If balanced, clear the dirty and congested
+                                * flags
+                                */
                                zone_clear_flag(zone, ZONE_CONGESTED);
+                               zone_clear_flag(zone, ZONE_TAIL_LRU_DIRTY);
                        }
                }
 
-               if (i < 0) {
-                       pgdat_is_balanced = true;
+               if (i < 0)
                        goto out;
-               }
 
                for (i = 0; i <= end_zone; i++) {
                        struct zone *zone = pgdat->node_zones + i;
 
+                       if (!populated_zone(zone))
+                               continue;
+
                        lru_pages += zone_reclaimable_pages(zone);
+
+                       /*
+                        * If any zone is currently balanced then kswapd will
+                        * not call compaction as it is expected that the
+                        * necessary pages are already available.
+                        */
+                       if (pgdat_needs_compaction &&
+                                       zone_watermark_ok(zone, order,
+                                               low_wmark_pages(zone),
+                                               *classzone_idx, 0))
+                               pgdat_needs_compaction = false;
                }
 
+               /*
+                * If we're getting trouble reclaiming, start doing writepage
+                * even in laptop mode.
+                */
+               if (sc.priority < DEF_PRIORITY - 2)
+                       sc.may_writepage = 1;
+
                /*
                 * Now scan the zone in the dma->highmem direction, stopping
                 * at the last zone which needs scanning.
@@ -2716,8 +2988,6 @@ loop_again:
                 */
                for (i = 0; i <= end_zone; i++) {
                        struct zone *zone = pgdat->node_zones + i;
-                       int nr_slab, testorder;
-                       unsigned long balance_gap;
 
                        if (!populated_zone(zone))
                                continue;
@@ -2738,65 +3008,14 @@ loop_again:
                        sc.nr_reclaimed += nr_soft_reclaimed;
 
                        /*
-                        * We put equal pressure on every zone, unless
-                        * one zone has way too many pages free
-                        * already. The "too many pages" is defined
-                        * as the high wmark plus a "gap" where the
-                        * gap is either the low watermark or 1%
-                        * of the zone, whichever is smaller.
+                        * There should be no need to raise the scanning
+                        * priority if enough pages are already being scanned
+                        * that that high watermark would be met at 100%
+                        * efficiency.
                         */
-                       balance_gap = min(low_wmark_pages(zone),
-                               (zone->managed_pages +
-                                       KSWAPD_ZONE_BALANCE_GAP_RATIO-1) /
-                               KSWAPD_ZONE_BALANCE_GAP_RATIO);
-                       /*
-                        * Kswapd reclaims only single pages with compaction
-                        * enabled. Trying too hard to reclaim until contiguous
-                        * free pages have become available can hurt performance
-                        * by evicting too much useful data from memory.
-                        * Do not reclaim more than needed for compaction.
-                        */
-                       testorder = order;
-                       if (IS_ENABLED(CONFIG_COMPACTION) && order &&
-                                       compaction_suitable(zone, order) !=
-                                               COMPACT_SKIPPED)
-                               testorder = 0;
-
-                       if ((buffer_heads_over_limit && is_highmem_idx(i)) ||
-                           !zone_balanced(zone, testorder,
-                                          balance_gap, end_zone)) {
-                               shrink_zone(zone, &sc);
-
-                               reclaim_state->reclaimed_slab = 0;
-                               nr_slab = shrink_slab(&shrink, sc.nr_scanned, lru_pages);
-                               sc.nr_reclaimed += reclaim_state->reclaimed_slab;
-
-                               if (nr_slab == 0 && !zone_reclaimable(zone))
-                                       zone->all_unreclaimable = 1;
-                       }
-
-                       /*
-                        * If we're getting trouble reclaiming, start doing
-                        * writepage even in laptop mode.
-                        */
-                       if (sc.priority < DEF_PRIORITY - 2)
-                               sc.may_writepage = 1;
-
-                       if (zone->all_unreclaimable) {
-                               if (end_zone && end_zone == i)
-                                       end_zone--;
-                               continue;
-                       }
-
-                       if (zone_balanced(zone, testorder, 0, end_zone))
-                               /*
-                                * If a zone reaches its high watermark,
-                                * consider it to be no longer congested. It's
-                                * possible there are dirty pages backed by
-                                * congested BDIs but as pressure is relieved,
-                                * speculatively avoid congestion waits
-                                */
-                               zone_clear_flag(zone, ZONE_CONGESTED);
+                       if (kswapd_shrink_zone(zone, end_zone, &sc,
+                                       lru_pages, &nr_attempted))
+                               raise_priority = false;
                }
 
                /*
@@ -2808,74 +3027,38 @@ loop_again:
                                pfmemalloc_watermark_ok(pgdat))
                        wake_up(&pgdat->pfmemalloc_wait);
 
-               if (pgdat_balanced(pgdat, order, *classzone_idx)) {
-                       pgdat_is_balanced = true;
-                       break;          /* kswapd: all done */
-               }
-
                /*
-                * We do this so kswapd doesn't build up large priorities for
-                * example when it is freeing in parallel with allocators. It
-                * matches the direct reclaim path behaviour in terms of impact
-                * on zone->*_priority.
+                * Fragmentation may mean that the system cannot be rebalanced
+                * for high-order allocations in all zones. If twice the
+                * allocation size has been reclaimed and the zones are still
+                * not balanced then recheck the watermarks at order-0 to
+                * prevent kswapd reclaiming excessively. Assume that a
+                * process requested a high-order can direct reclaim/compact.
                 */
-               if (sc.nr_reclaimed >= SWAP_CLUSTER_MAX)
-                       break;
-       } while (--sc.priority >= 0);
-
-out:
-       if (!pgdat_is_balanced) {
-               cond_resched();
+               if (order && sc.nr_reclaimed >= 2UL << order)
+                       order = sc.order = 0;
 
-               try_to_freeze();
+               /* Check if kswapd should be suspending */
+               if (try_to_freeze() || kthread_should_stop())
+                       break;
 
                /*
-                * Fragmentation may mean that the system cannot be
-                * rebalanced for high-order allocations in all zones.
-                * At this point, if nr_reclaimed < SWAP_CLUSTER_MAX,
-                * it means the zones have been fully scanned and are still
-                * not balanced. For high-order allocations, there is
-                * little point trying all over again as kswapd may
-                * infinite loop.
-                *
-                * Instead, recheck all watermarks at order-0 as they
-                * are the most important. If watermarks are ok, kswapd will go
-                * back to sleep. High-order users can still perform direct
-                * reclaim if they wish.
+                * Compact if necessary and kswapd is reclaiming at least the
+                * high watermark number of pages as requsted
                 */
-               if (sc.nr_reclaimed < SWAP_CLUSTER_MAX)
-                       order = sc.order = 0;
-
-               goto loop_again;
-       }
-
-       /*
-        * If kswapd was reclaiming at a higher order, it has the option of
-        * sleeping without all zones being balanced. Before it does, it must
-        * ensure that the watermarks for order-0 on *all* zones are met and
-        * that the congestion flags are cleared. The congestion flag must
-        * be cleared as kswapd is the only mechanism that clears the flag
-        * and it is potentially going to sleep here.
-        */
-       if (order) {
-               int zones_need_compaction = 1;
-
-               for (i = 0; i <= end_zone; i++) {
-                       struct zone *zone = pgdat->node_zones + i;
-
-                       if (!populated_zone(zone))
-                               continue;
-
-                       /* Check if the memory needs to be defragmented. */
-                       if (zone_watermark_ok(zone, order,
-                                   low_wmark_pages(zone), *classzone_idx, 0))
-                               zones_need_compaction = 0;
-               }
-
-               if (zones_need_compaction)
+               if (pgdat_needs_compaction && sc.nr_reclaimed > nr_attempted)
                        compact_pgdat(pgdat, order);
-       }
 
+               /*
+                * Raise priority if scanning rate is too low or there was no
+                * progress in reclaiming pages
+                */
+               if (raise_priority || !sc.nr_reclaimed)
+                       sc.priority--;
+       } while (sc.priority >= 1 &&
+                !pgdat_balanced(pgdat, order, *classzone_idx));
+
+out:
        /*
         * Return the order we were reclaiming at so prepare_kswapd_sleep()
         * makes a decision on the order we were last reclaiming at. However,
index ace5e55fe5a32ed01fd8ca3c0c63c802632ac547..db7de80b88a2758ea25a630c3209f87d08faff7c 100644 (file)
@@ -2211,16 +2211,15 @@ int hci_register_dev(struct hci_dev *hdev)
        list_add(&hdev->list, &hci_dev_list);
        write_unlock(&hci_dev_list_lock);
 
-       hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
-                                         WQ_MEM_RECLAIM, 1);
+       hdev->workqueue = alloc_workqueue("%s", WQ_HIGHPRI | WQ_UNBOUND |
+                                         WQ_MEM_RECLAIM, 1, hdev->name);
        if (!hdev->workqueue) {
                error = -ENOMEM;
                goto err;
        }
 
-       hdev->req_workqueue = alloc_workqueue(hdev->name,
-                                             WQ_HIGHPRI | WQ_UNBOUND |
-                                             WQ_MEM_RECLAIM, 1);
+       hdev->req_workqueue = alloc_workqueue("%s", WQ_HIGHPRI | WQ_UNBOUND |
+                                             WQ_MEM_RECLAIM, 1, hdev->name);
        if (!hdev->req_workqueue) {
                destroy_workqueue(hdev->workqueue);
                error = -ENOMEM;
index 7e06641e36ae785239f32b1d5afb80e504e0c60b..cec539458307559814a6b0bfc527603594cbe99a 100644 (file)
@@ -93,7 +93,7 @@ void inet_frags_init(struct inet_frags *f)
        }
        rwlock_init(&f->lock);
 
-       f->rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
+       f->rnd = (u32) ((totalram_pages ^ (totalram_pages >> 7)) ^
                                   (jiffies ^ (jiffies >> 6)));
 
        setup_timer(&f->secret_timer, inet_frag_secret_rebuild,
index 8a7bfc47d5778fd7bbc3f561ecf483996c2041e1..8eae74ac4e1ecab21b8b8e7372c18e6a5299eaf1 100644 (file)
@@ -921,7 +921,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                hw->queues = IEEE80211_MAX_QUEUES;
 
        local->workqueue =
-               alloc_ordered_workqueue(wiphy_name(local->hw.wiphy), 0);
+               alloc_ordered_workqueue("%s", 0, wiphy_name(local->hw.wiphy));
        if (!local->workqueue) {
                result = -ENOMEM;
                goto fail_workqueue;
index 29b4ba93ab3cb795fb8dd307f6e248bfcc3a1495..b05ace4c5f124886f165e2f091713397dbe38df4 100644 (file)
@@ -1330,7 +1330,7 @@ static int wait_for_gss_proxy(struct net *net, struct file *file)
 static ssize_t write_gssp(struct file *file, const char __user *buf,
                         size_t count, loff_t *ppos)
 {
-       struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
+       struct net *net = PDE_DATA(file_inode(file));
        char tbuf[20];
        unsigned long i;
        int res;
@@ -1358,7 +1358,7 @@ static ssize_t write_gssp(struct file *file, const char __user *buf,
 static ssize_t read_gssp(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
-       struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
+       struct net *net = PDE_DATA(file_inode(file));
        unsigned long p = *ppos;
        char tbuf[10];
        size_t len;
index 5356b120dbf8e2fe61ba88081d1fab1941f135a9..77d251e0259315eeef4acd4de50def4382bba5e1 100644 (file)
@@ -254,7 +254,7 @@ static int rpc_wait_bit_killable(void *word)
 {
        if (fatal_signal_pending(current))
                return -ERESTARTSYS;
-       freezable_schedule();
+       freezable_schedule_unsafe();
        return 0;
 }
 
index 89a588b4478bda057fe6e4d66d0041545de952c5..b974571126fe90fce45ff6edc522366c463d5d8d 100644 (file)
@@ -740,7 +740,7 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
 
                __module_get(serv->sv_module);
                task = kthread_create_on_node(serv->sv_function, rqstp,
-                                             node, serv->sv_name);
+                                             node, "%s", serv->sv_name);
                if (IS_ERR(task)) {
                        error = PTR_ERR(task);
                        module_put(serv->sv_module);
index 826e09938bff4203def6e5af33db49c4360f3019..c4ce243824bb19c6e600dd98da2d8a6d16747dc1 100644 (file)
 #include <linux/mount.h>
 #include <net/checksum.h>
 #include <linux/security.h>
+#include <linux/freezer.h>
 
 struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
 EXPORT_SYMBOL_GPL(unix_socket_table);
@@ -1879,7 +1880,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
 
                set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
                unix_state_unlock(sk);
-               timeo = schedule_timeout(timeo);
+               timeo = freezable_schedule_timeout(timeo);
                unix_state_lock(sk);
                clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
        }
index b954de58304fc7387d947ac7c6d06374009536a4..6afcd1239ca5652e9f857e564fdd70bf46d531f1 100755 (executable)
@@ -27,9 +27,11 @@ my $summary = 1;
 my $mailback = 0;
 my $summary_file = 0;
 my $show_types = 0;
+my $fix = 0;
 my $root;
 my %debug;
 my %ignore_type = ();
+my %camelcase = ();
 my @ignore = ();
 my $help = 0;
 my $configuration_file = ".checkpatch.conf";
@@ -63,6 +65,11 @@ Options:
                              is all off)
   --test-only=WORD           report only warnings/errors containing WORD
                              literally
+  --fix                      EXPERIMENTAL - may create horrible results
+                             If correctable single-line errors exist, create
+                             "<inputfile>.EXPERIMENTAL-checkpatch-fixes"
+                             with potential errors corrected to the preferred
+                             checkpatch style
   -h, --help, --version      display this help and exit
 
 When FILE is - read standard input.
@@ -114,7 +121,7 @@ GetOptions(
        'summary!'      => \$summary,
        'mailback!'     => \$mailback,
        'summary-file!' => \$summary_file,
-
+       'fix!'          => \$fix,
        'debug=s'       => \%debug,
        'test-only=s'   => \$tst_only,
        'h|help'        => \$help,
@@ -230,17 +237,22 @@ our $Inline       = qr{inline|__always_inline|noinline};
 our $Member    = qr{->$Ident|\.$Ident|\[[^]]*\]};
 our $Lval      = qr{$Ident(?:$Member)*};
 
+our $Int_type  = qr{(?i)llu|ull|ll|lu|ul|l|u};
+our $Binary    = qr{(?i)0b[01]+$Int_type?};
+our $Hex       = qr{(?i)0x[0-9a-f]+$Int_type?};
+our $Int       = qr{[0-9]+$Int_type?};
 our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?};
 our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?};
 our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?};
 our $Float     = qr{$Float_hex|$Float_dec|$Float_int};
-our $Constant  = qr{$Float|(?i)(?:0x[0-9a-f]+|[0-9]+)[ul]*};
+our $Constant  = qr{$Float|$Binary|$Hex|$Int};
 our $Assignment        = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=};
 our $Compare    = qr{<=|>=|==|!=|<|>};
+our $Arithmetic = qr{\+|-|\*|\/|%};
 our $Operators = qr{
                        <=|>=|==|!=|
                        =>|->|<<|>>|<|>|!|~|
-                       &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%
+                       &&|\|\||,|\^|\+\+|--|&|\||$Arithmetic
                  }x;
 
 our $NonptrType;
@@ -269,7 +281,7 @@ our $typeTypedefs = qr{(?x:
 
 our $logFunctions = qr{(?x:
        printk(?:_ratelimited|_once|)|
-       [a-z0-9]+_(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
+       (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
        WARN(?:_RATELIMIT|_ONCE|)|
        panic|
        MODULE_[A-Z_]+
@@ -338,7 +350,6 @@ sub build_types {
 }
 build_types();
 
-
 our $Typecast  = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
 
 # Using $balanced_parens, $LvalOrFunc, or $FuncArg
@@ -358,10 +369,79 @@ sub deparenthesize {
        return $string;
 }
 
+sub seed_camelcase_file {
+       my ($file) = @_;
+
+       return if (!(-f $file));
+
+       local $/;
+
+       open(my $include_file, '<', "$file")
+           or warn "$P: Can't read '$file' $!\n";
+       my $text = <$include_file>;
+       close($include_file);
+
+       my @lines = split('\n', $text);
+
+       foreach my $line (@lines) {
+               next if ($line !~ /(?:[A-Z][a-z]|[a-z][A-Z])/);
+               if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) {
+                       $camelcase{$1} = 1;
+               }
+               elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*\(/) {
+                       $camelcase{$1} = 1;
+               }
+       }
+}
+
+my $camelcase_seeded = 0;
+sub seed_camelcase_includes {
+       return if ($camelcase_seeded);
+
+       my $files;
+       my $camelcase_git_file = "";
+
+       if (-d ".git") {
+               my $git_last_include_commit = `git log --no-merges --pretty=format:"%h%n" -1 -- include`;
+               chomp $git_last_include_commit;
+               $camelcase_git_file = ".checkpatch-camelcase.$git_last_include_commit";
+               if (-f $camelcase_git_file) {
+                       open(my $camelcase_file, '<', "$camelcase_git_file")
+                           or warn "$P: Can't read '$camelcase_git_file' $!\n";
+                       while (<$camelcase_file>) {
+                               chomp;
+                               $camelcase{$_} = 1;
+                       }
+                       close($camelcase_file);
+
+                       return;
+               }
+               $files = `git ls-files include`;
+       } else {
+               $files = `find $root/include -name "*.h"`;
+       }
+       my @include_files = split('\n', $files);
+       foreach my $file (@include_files) {
+               seed_camelcase_file($file);
+       }
+       $camelcase_seeded = 1;
+
+       if ($camelcase_git_file ne "") {
+               unlink glob ".checkpatch-camelcase.*";
+               open(my $camelcase_file, '>', "$camelcase_git_file")
+                   or warn "$P: Can't write '$camelcase_git_file' $!\n";
+               foreach (sort { lc($a) cmp lc($b) } keys(%camelcase)) {
+                       print $camelcase_file ("$_\n");
+               }
+               close($camelcase_file);
+       }
+}
+
 $chk_signoff = 0 if ($file);
 
 my @rawlines = ();
 my @lines = ();
+my @fixed = ();
 my $vname;
 for my $filename (@ARGV) {
        my $FILE;
@@ -389,6 +469,7 @@ for my $filename (@ARGV) {
        }
        @rawlines = ();
        @lines = ();
+       @fixed = ();
 }
 
 exit($exit);
@@ -429,7 +510,7 @@ sub parse_email {
                $comment = $2 if defined $2;
                $formatted_email =~ s/$address.*$//;
                $name = $formatted_email;
-               $name =~ s/^\s+|\s+$//g;
+               $name = trim($name);
                $name =~ s/^\"|\"$//g;
                # If there's a name left after stripping spaces and
                # leading quotes, and the address doesn't have both
@@ -444,9 +525,9 @@ sub parse_email {
                }
        }
 
-       $name =~ s/^\s+|\s+$//g;
+       $name = trim($name);
        $name =~ s/^\"|\"$//g;
-       $address =~ s/^\s+|\s+$//g;
+       $address = trim($address);
        $address =~ s/^\<|\>$//g;
 
        if ($name =~ /[^\w \-]/i) { ##has "must quote" chars
@@ -462,9 +543,9 @@ sub format_email {
 
        my $formatted_email;
 
-       $name =~ s/^\s+|\s+$//g;
+       $name = trim($name);
        $name =~ s/^\"|\"$//g;
-       $address =~ s/^\s+|\s+$//g;
+       $address = trim($address);
 
        if ($name =~ /[^\w \-]/i) { ##has "must quote" chars
                $name =~ s/(?<!\\)"/\\"/g; ##escape quotes
@@ -1286,19 +1367,25 @@ sub ERROR {
        if (report("ERROR", $_[0], $_[1])) {
                our $clean = 0;
                our $cnt_error++;
+               return 1;
        }
+       return 0;
 }
 sub WARN {
        if (report("WARNING", $_[0], $_[1])) {
                our $clean = 0;
                our $cnt_warn++;
+               return 1;
        }
+       return 0;
 }
 sub CHK {
        if ($check && report("CHECK", $_[0], $_[1])) {
                our $clean = 0;
                our $cnt_chk++;
+               return 1;
        }
+       return 0;
 }
 
 sub check_absolute_file {
@@ -1329,6 +1416,29 @@ sub check_absolute_file {
        }
 }
 
+sub trim {
+       my ($string) = @_;
+
+       $string =~ s/(^\s+|\s+$)//g;
+
+       return $string;
+}
+
+sub tabify {
+       my ($leading) = @_;
+
+       my $source_indent = 8;
+       my $max_spaces_before_tab = $source_indent - 1;
+       my $spaces_to_tab = " " x $source_indent;
+
+       #convert leading spaces to tabs
+       1 while $leading =~ s@^([\t]*)$spaces_to_tab@$1\t@g;
+       #Remove spaces before a tab
+       1 while $leading =~ s@^([\t]*)( {1,$max_spaces_before_tab})\t@$1\t@g;
+
+       return "$leading";
+}
+
 sub pos_last_openparen {
        my ($line) = @_;
 
@@ -1406,7 +1516,6 @@ sub process {
        my %suppress_export;
        my $suppress_statement = 0;
 
-       my %camelcase = ();
 
        # Pre-scan the patch sanitizing the lines.
        # Pre-scan the patch looking for any __setup documentation.
@@ -1420,6 +1529,8 @@ sub process {
                $linenr++;
                $line = $rawline;
 
+               push(@fixed, $rawline) if ($fix);
+
                if ($rawline=~/^\+\+\+\s+(\S+)/) {
                        $setup_docs = 0;
                        if ($1 =~ m@Documentation/kernel-parameters.txt$@) {
@@ -1611,16 +1722,29 @@ sub process {
                                     "Non-standard signature: $sign_off\n" . $herecurr);
                        }
                        if (defined $space_before && $space_before ne "") {
-                               WARN("BAD_SIGN_OFF",
-                                    "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr);
+                               if (WARN("BAD_SIGN_OFF",
+                                        "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr) &&
+                                   $fix) {
+                                       $fixed[$linenr - 1] =
+                                           "$ucfirst_sign_off $email";
+                               }
                        }
                        if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) {
-                               WARN("BAD_SIGN_OFF",
-                                    "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr);
+                               if (WARN("BAD_SIGN_OFF",
+                                        "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr) &&
+                                   $fix) {
+                                       $fixed[$linenr - 1] =
+                                           "$ucfirst_sign_off $email";
+                               }
+
                        }
                        if (!defined $space_after || $space_after ne " ") {
-                               WARN("BAD_SIGN_OFF",
-                                    "Use a single space after $ucfirst_sign_off\n" . $herecurr);
+                               if (WARN("BAD_SIGN_OFF",
+                                        "Use a single space after $ucfirst_sign_off\n" . $herecurr) &&
+                                   $fix) {
+                                       $fixed[$linenr - 1] =
+                                           "$ucfirst_sign_off $email";
+                               }
                        }
 
                        my ($email_name, $email_address, $comment) = parse_email($email);
@@ -1710,8 +1834,12 @@ sub process {
 
                } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
-                       ERROR("TRAILING_WHITESPACE",
-                             "trailing whitespace\n" . $herevet);
+                       if (ERROR("TRAILING_WHITESPACE",
+                                 "trailing whitespace\n" . $herevet) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/^(\+.*?)\s+$/$1/;
+                       }
+
                        $rpt_cleaners = 1;
                }
 
@@ -1806,8 +1934,12 @@ sub process {
 
 # check for spaces before a quoted newline
                if ($rawline =~ /^.*\".*\s\\n/) {
-                       WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
-                            "unnecessary whitespace before a quoted newline\n" . $herecurr);
+                       if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
+                                "unnecessary whitespace before a quoted newline\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/^(\+.*\".*)\s+\\n/$1\\n/;
+                       }
+
                }
 
 # check for adding lines without a newline.
@@ -1838,16 +1970,23 @@ sub process {
                if ($rawline =~ /^\+\s* \t\s*\S/ ||
                    $rawline =~ /^\+\s*        \s*/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
-                       ERROR("CODE_INDENT",
-                             "code indent should use tabs where possible\n" . $herevet);
                        $rpt_cleaners = 1;
+                       if (ERROR("CODE_INDENT",
+                                 "code indent should use tabs where possible\n" . $herevet) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e;
+                       }
                }
 
 # check for space before tabs.
                if ($rawline =~ /^\+/ && $rawline =~ / \t/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
-                       WARN("SPACE_BEFORE_TAB",
-                            "please, no space before tabs\n" . $herevet);
+                       if (WARN("SPACE_BEFORE_TAB",
+                               "please, no space before tabs\n" . $herevet) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/(^\+.*) +\t/$1\t/;
+                       }
                }
 
 # check for && or || at the start of a line
@@ -1875,24 +2014,41 @@ sub process {
 
                                if ($newindent ne $goodtabindent &&
                                    $newindent ne $goodspaceindent) {
-                                       CHK("PARENTHESIS_ALIGNMENT",
-                                           "Alignment should match open parenthesis\n" . $hereprev);
+
+                                       if (CHK("PARENTHESIS_ALIGNMENT",
+                                               "Alignment should match open parenthesis\n" . $hereprev) &&
+                                           $fix && $line =~ /^\+/) {
+                                               $fixed[$linenr - 1] =~
+                                                   s/^\+[ \t]*/\+$goodtabindent/;
+                                       }
                                }
                        }
                }
 
-               if ($line =~ /^\+.*\*[ \t]*\)[ \t]+/) {
-                       CHK("SPACING",
-                           "No space is necessary after a cast\n" . $hereprev);
+               if ($line =~ /^\+.*\*[ \t]*\)[ \t]+(?!$Assignment|$Arithmetic)/) {
+                       if (CHK("SPACING",
+                               "No space is necessary after a cast\n" . $hereprev) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/^(\+.*\*[ \t]*\))[ \t]+/$1/;
+                       }
                }
 
                if ($realfile =~ m@^(drivers/net/|net/)@ &&
-                   $rawline =~ /^\+[ \t]*\/\*[ \t]*$/ &&
-                   $prevrawline =~ /^\+[ \t]*$/) {
+                   $prevrawline =~ /^\+[ \t]*\/\*[ \t]*$/ &&
+                   $rawline =~ /^\+[ \t]*\*/) {
                        WARN("NETWORKING_BLOCK_COMMENT_STYLE",
                             "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev);
                }
 
+               if ($realfile =~ m@^(drivers/net/|net/)@ &&
+                   $prevrawline =~ /^\+[ \t]*\/\*/ &&          #starting /*
+                   $prevrawline !~ /\*\/[ \t]*$/ &&            #no trailing */
+                   $rawline !~ /^\+[ \t]*\*/) {                #no leading *
+                       WARN("NETWORKING_BLOCK_COMMENT_STYLE",
+                            "networking block comments start with * on subsequent lines\n" . $hereprev);
+               }
+
                if ($realfile =~ m@^(drivers/net/|net/)@ &&
                    $rawline !~ m@^\+[ \t]*\*/[ \t]*$@ &&       #trailing */
                    $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ &&      #inline /*...*/
@@ -1907,10 +2063,13 @@ sub process {
 #  1) within comments
 #  2) indented preprocessor commands
 #  3) hanging labels
-               if ($rawline =~ /^\+ / && $line !~ /\+ *(?:$;|#|$Ident:)/)  {
+               if ($rawline =~ /^\+ / && $line !~ /^\+ *(?:$;|#|$Ident:)/)  {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
-                       WARN("LEADING_SPACE",
-                            "please, no spaces at the start of a line\n" . $herevet);
+                       if (WARN("LEADING_SPACE",
+                                "please, no spaces at the start of a line\n" . $herevet) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e;
+                       }
                }
 
 # check we are in a valid C source file if not then ignore this hunk
@@ -2200,7 +2359,7 @@ sub process {
                $prev_values = substr($curr_values, -1);
 
 #ignore lines not being added
-               if ($line=~/^[^\+]/) {next;}
+               next if ($line =~ /^[^\+]/);
 
 # TEST: allow direct testing of the type matcher.
                if ($dbg_type) {
@@ -2251,8 +2410,15 @@ sub process {
 
 # no C99 // comments
                if ($line =~ m{//}) {
-                       ERROR("C99_COMMENTS",
-                             "do not use C99 // comments\n" . $herecurr);
+                       if (ERROR("C99_COMMENTS",
+                                 "do not use C99 // comments\n" . $herecurr) &&
+                           $fix) {
+                               my $line = $fixed[$linenr - 1];
+                               if ($line =~ /\/\/(.*)$/) {
+                                       my $comment = trim($1);
+                                       $fixed[$linenr - 1] =~ s@\/\/(.*)$@/\* $comment \*/@;
+                               }
+                       }
                }
                # Remove C99 comments.
                $line =~ s@//.*@@;
@@ -2351,7 +2517,7 @@ sub process {
                # (char*[ const])
                while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) {
                        #print "AA<$1>\n";
-                       my ($from, $to) = ($2, $2);
+                       my ($ident, $from, $to) = ($1, $2, $2);
 
                        # Should start with a space.
                        $to =~ s/^(\S)/ $1/;
@@ -2361,15 +2527,22 @@ sub process {
                        while ($to =~ s/\*\s+\*/\*\*/) {
                        }
 
-                       #print "from<$from> to<$to>\n";
+##                     print "1: from<$from> to<$to> ident<$ident>\n";
                        if ($from ne $to) {
-                               ERROR("POINTER_LOCATION",
-                                     "\"(foo$from)\" should be \"(foo$to)\"\n" .  $herecurr);
+                               if (ERROR("POINTER_LOCATION",
+                                         "\"(foo$from)\" should be \"(foo$to)\"\n" .  $herecurr) &&
+                                   $fix) {
+                                       my $sub_from = $ident;
+                                       my $sub_to = $ident;
+                                       $sub_to =~ s/\Q$from\E/$to/;
+                                       $fixed[$linenr - 1] =~
+                                           s@\Q$sub_from\E@$sub_to@;
+                               }
                        }
                }
                while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) {
                        #print "BB<$1>\n";
-                       my ($from, $to, $ident) = ($2, $2, $3);
+                       my ($match, $from, $to, $ident) = ($1, $2, $2, $3);
 
                        # Should start with a space.
                        $to =~ s/^(\S)/ $1/;
@@ -2381,10 +2554,18 @@ sub process {
                        # Modifiers should have spaces.
                        $to =~ s/(\b$Modifier$)/$1 /;
 
-                       #print "from<$from> to<$to> ident<$ident>\n";
+##                     print "2: from<$from> to<$to> ident<$ident>\n";
                        if ($from ne $to && $ident !~ /^$Modifier$/) {
-                               ERROR("POINTER_LOCATION",
-                                     "\"foo${from}bar\" should be \"foo${to}bar\"\n" .  $herecurr);
+                               if (ERROR("POINTER_LOCATION",
+                                         "\"foo${from}bar\" should be \"foo${to}bar\"\n" .  $herecurr) &&
+                                   $fix) {
+
+                                       my $sub_from = $match;
+                                       my $sub_to = $match;
+                                       $sub_to =~ s/\Q$from\E/$to/;
+                                       $fixed[$linenr - 1] =~
+                                           s@\Q$sub_from\E@$sub_to@;
+                               }
                        }
                }
 
@@ -2470,9 +2651,13 @@ sub process {
                }
 
 # missing space after union, struct or enum definition
-               if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) {
-                   WARN("SPACING",
-                        "missing space after $1 definition\n" . $herecurr);
+               if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident){1,2}[=\{]/) {
+                       if (WARN("SPACING",
+                                "missing space after $1 definition\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/^(.\s*(?:typedef\s+)?(?:enum|union|struct)(?:\s+$Ident){1,2})([=\{])/$1 $2/;
+                       }
                }
 
 # check for spacing round square brackets; allowed:
@@ -2484,8 +2669,12 @@ sub process {
                        if ($prefix !~ /$Type\s+$/ &&
                            ($where != 0 || $prefix !~ /^.\s+$/) &&
                            $prefix !~ /[{,]\s+$/) {
-                               ERROR("BRACKET_SPACE",
-                                     "space prohibited before open square bracket '['\n" . $herecurr);
+                               if (ERROR("BRACKET_SPACE",
+                                         "space prohibited before open square bracket '['\n" . $herecurr) &&
+                                   $fix) {
+                                   $fixed[$linenr - 1] =~
+                                       s/^(\+.*?)\s+\[/$1\[/;
+                               }
                        }
                }
 
@@ -2502,7 +2691,6 @@ sub process {
                                __attribute__|format|__extension__|
                                asm|__asm__)$/x)
                        {
-
                        # cpp #define statements have non-optional spaces, ie
                        # if there is a space between the name and the open
                        # parenthesis it is simply not a parameter group.
@@ -2516,19 +2704,20 @@ sub process {
                        } elsif ($ctx =~ /$Type$/) {
 
                        } else {
-                               WARN("SPACING",
-                                    "space prohibited between function name and open parenthesis '('\n" . $herecurr);
+                               if (WARN("SPACING",
+                                        "space prohibited between function name and open parenthesis '('\n" . $herecurr) &&
+                                            $fix) {
+                                       $fixed[$linenr - 1] =~
+                                           s/\b$name\s+\(/$name\(/;
+                               }
                        }
                }
 
-# check for whitespace before a non-naked semicolon
-               if ($line =~ /^\+.*\S\s+;/) {
-                       WARN("SPACING",
-                            "space prohibited before semicolon\n" . $herecurr);
-               }
-
 # Check operator spacing.
                if (!($line=~/\#\s*include/)) {
+                       my $fixed_line = "";
+                       my $line_fixed = 0;
+
                        my $ops = qr{
                                <<=|>>=|<=|>=|==|!=|
                                \+=|-=|\*=|\/=|%=|\^=|\|=|&=|
@@ -2537,11 +2726,30 @@ sub process {
                                \?|:
                        }x;
                        my @elements = split(/($ops|;)/, $opline);
+
+##                     print("element count: <" . $#elements . ">\n");
+##                     foreach my $el (@elements) {
+##                             print("el: <$el>\n");
+##                     }
+
+                       my @fix_elements = ();
                        my $off = 0;
 
+                       foreach my $el (@elements) {
+                               push(@fix_elements, substr($rawline, $off, length($el)));
+                               $off += length($el);
+                       }
+
+                       $off = 0;
+
                        my $blank = copy_spacing($opline);
 
                        for (my $n = 0; $n < $#elements; $n += 2) {
+
+                               my $good = $fix_elements[$n] . $fix_elements[$n + 1];
+
+##                             print("n: <$n> good: <$good>\n");
+
                                $off += length($elements[$n]);
 
                                # Pick up the preceding and succeeding characters.
@@ -2598,8 +2806,11 @@ sub process {
                                } elsif ($op eq ';') {
                                        if ($ctx !~ /.x[WEBC]/ &&
                                            $cc !~ /^\\/ && $cc !~ /^;/) {
-                                               ERROR("SPACING",
-                                                     "space required after that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space required after that '$op' $at\n" . $hereptr)) {
+                                                       $good = trim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       $line_fixed = 1;
+                                               }
                                        }
 
                                # // is a comment
@@ -2610,15 +2821,24 @@ sub process {
                                #   :   when part of a bitfield
                                } elsif ($op eq '->' || $opv eq ':B') {
                                        if ($ctx =~ /Wx.|.xW/) {
-                                               ERROR("SPACING",
-                                                     "spaces prohibited around that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "spaces prohibited around that '$op' $at\n" . $hereptr)) {
+                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
+                                                       $line_fixed = 1;
+                                                       if (defined $fix_elements[$n + 2]) {
+                                                               $fix_elements[$n + 2] =~ s/^\s+//;
+                                                       }
+                                               }
                                        }
 
                                # , must have a space on the right.
                                } elsif ($op eq ',') {
                                        if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
-                                               ERROR("SPACING",
-                                                     "space required after that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space required after that '$op' $at\n" . $hereptr)) {
+                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]) . " ";
+                                                       $line_fixed = 1;
+                                               }
                                        }
 
                                # '*' as part of a type definition -- reported already.
@@ -2632,34 +2852,58 @@ sub process {
                                         $opv eq '*U' || $opv eq '-U' ||
                                         $opv eq '&U' || $opv eq '&&U') {
                                        if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
-                                               ERROR("SPACING",
-                                                     "space required before that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space required before that '$op' $at\n" . $hereptr)) {
+                                                       $good = trim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]);
+                                                       $line_fixed = 1;
+                                               }
                                        }
                                        if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
                                                # A unary '*' may be const
 
                                        } elsif ($ctx =~ /.xW/) {
-                                               ERROR("SPACING",
-                                                     "space prohibited after that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space prohibited after that '$op' $at\n" . $hereptr)) {
+                                                       $fixed_line =~ s/\s+$//;
+                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
+                                                       $line_fixed = 1;
+                                                       if (defined $fix_elements[$n + 2]) {
+                                                               $fix_elements[$n + 2] =~ s/^\s+//;
+                                                       }
+                                               }
                                        }
 
                                # unary ++ and unary -- are allowed no space on one side.
                                } elsif ($op eq '++' or $op eq '--') {
                                        if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {
-                                               ERROR("SPACING",
-                                                     "space required one side of that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space required one side of that '$op' $at\n" . $hereptr)) {
+                                                       $fixed_line =~ s/\s+$//;
+                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]) . " ";
+                                                       $line_fixed = 1;
+                                               }
                                        }
                                        if ($ctx =~ /Wx[BE]/ ||
                                            ($ctx =~ /Wx./ && $cc =~ /^;/)) {
-                                               ERROR("SPACING",
-                                                     "space prohibited before that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space prohibited before that '$op' $at\n" . $hereptr)) {
+                                                       $fixed_line =~ s/\s+$//;
+                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
+                                                       $line_fixed = 1;
+                                               }
                                        }
                                        if ($ctx =~ /ExW/) {
-                                               ERROR("SPACING",
-                                                     "space prohibited after that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space prohibited after that '$op' $at\n" . $hereptr)) {
+                                                       $fixed_line =~ s/\s+$//;
+                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
+                                                       $line_fixed = 1;
+                                                       if (defined $fix_elements[$n + 2]) {
+                                                               $fix_elements[$n + 2] =~ s/^\s+//;
+                                                       }
+                                               }
                                        }
 
-
                                # << and >> may either have or not have spaces both sides
                                } elsif ($op eq '<<' or $op eq '>>' or
                                         $op eq '&' or $op eq '^' or $op eq '|' or
@@ -2668,17 +2912,23 @@ sub process {
                                         $op eq '%')
                                {
                                        if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
-                                               ERROR("SPACING",
-                                                     "need consistent spacing around '$op' $at\n" .
-                                                       $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "need consistent spacing around '$op' $at\n" . $hereptr)) {
+                                                       $fixed_line =~ s/\s+$//;
+                                                       $good = trim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       $line_fixed = 1;
+                                               }
                                        }
 
                                # A colon needs no spaces before when it is
                                # terminating a case value or a label.
                                } elsif ($opv eq ':C' || $opv eq ':L') {
                                        if ($ctx =~ /Wx./) {
-                                               ERROR("SPACING",
-                                                     "space prohibited before that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "space prohibited before that '$op' $at\n" . $hereptr)) {
+                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
+                                                       $line_fixed = 1;
+                                               }
                                        }
 
                                # All the others need spaces both sides.
@@ -2701,11 +2951,39 @@ sub process {
                                        }
 
                                        if ($ok == 0) {
-                                               ERROR("SPACING",
-                                                     "spaces required around that '$op' $at\n" . $hereptr);
+                                               if (ERROR("SPACING",
+                                                         "spaces required around that '$op' $at\n" . $hereptr)) {
+                                                       $good = trim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       $good = $fix_elements[$n] . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       $line_fixed = 1;
+                                               }
                                        }
                                }
                                $off += length($elements[$n + 1]);
+
+##                             print("n: <$n> GOOD: <$good>\n");
+
+                               $fixed_line = $fixed_line . $good;
+                       }
+
+                       if (($#elements % 2) == 0) {
+                               $fixed_line = $fixed_line . $fix_elements[$#elements];
+                       }
+
+                       if ($fix && $line_fixed && $fixed_line ne $fixed[$linenr - 1]) {
+                               $fixed[$linenr - 1] = $fixed_line;
+                       }
+
+
+               }
+
+# check for whitespace before a non-naked semicolon
+               if ($line =~ /^\+.*\S\s+;/) {
+                       if (WARN("SPACING",
+                                "space prohibited before semicolon\n" . $herecurr) &&
+                           $fix) {
+                               1 while $fixed[$linenr - 1] =~
+                                   s/^(\+.*\S)\s+;/$1;/;
                        }
                }
 
@@ -2734,10 +3012,22 @@ sub process {
 #need space before brace following if, while, etc
                if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) ||
                    $line =~ /do{/) {
-                       ERROR("SPACING",
-                             "space required before the open brace '{'\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "space required before the open brace '{'\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/^(\+.*(?:do|\))){/$1 {/;
+                       }
                }
 
+## # check for blank lines before declarations
+##             if ($line =~ /^.\t+$Type\s+$Ident(?:\s*=.*)?;/ &&
+##                 $prevrawline =~ /^.\s*$/) {
+##                     WARN("SPACING",
+##                          "No blank lines before declarations\n" . $hereprev);
+##             }
+##
+
 # closing brace should have a space following it when it has anything
 # on the line
                if ($line =~ /}(?!(?:,|;|\)))\S/) {
@@ -2747,32 +3037,52 @@ sub process {
 
 # check spacing on square brackets
                if ($line =~ /\[\s/ && $line !~ /\[\s*$/) {
-                       ERROR("SPACING",
-                             "space prohibited after that open square bracket '['\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "space prohibited after that open square bracket '['\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\[\s+/\[/;
+                       }
                }
                if ($line =~ /\s\]/) {
-                       ERROR("SPACING",
-                             "space prohibited before that close square bracket ']'\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "space prohibited before that close square bracket ']'\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\s+\]/\]/;
+                       }
                }
 
 # check spacing on parentheses
                if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
                    $line !~ /for\s*\(\s+;/) {
-                       ERROR("SPACING",
-                             "space prohibited after that open parenthesis '('\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "space prohibited after that open parenthesis '('\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\(\s+/\(/;
+                       }
                }
                if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
                    $line !~ /for\s*\(.*;\s+\)/ &&
                    $line !~ /:\s+\)/) {
-                       ERROR("SPACING",
-                             "space prohibited before that close parenthesis ')'\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "space prohibited before that close parenthesis ')'\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\s+\)/\)/;
+                       }
                }
 
 #goto labels aren't indented, allow a single space however
                if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
                   !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
-                       WARN("INDENTED_LABEL",
-                            "labels should not be indented\n" . $herecurr);
+                       if (WARN("INDENTED_LABEL",
+                                "labels should not be indented\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/^(.)\s+/$1/;
+                       }
                }
 
 # Return is not a function.
@@ -2809,8 +3119,13 @@ sub process {
                }
 
 # Need a space before open parenthesis after if, while etc
-               if ($line=~/\b(if|while|for|switch)\(/) {
-                       ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr);
+               if ($line =~ /\b(if|while|for|switch)\(/) {
+                       if (ERROR("SPACING",
+                                 "space required before the open parenthesis '('\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\b(if|while|for|switch)\(/$1 \(/;
+                       }
                }
 
 # Check for illegal assignment in if conditional -- and check for trailing
@@ -2934,16 +3249,29 @@ sub process {
                        }
                }
 
-#CamelCase
+#Specific variable tests
                while ($line =~ m{($Constant|$Lval)}g) {
                        my $var = $1;
-                       if ($var !~ /$Constant/ &&
-                           $var =~ /[A-Z]\w*[a-z]|[a-z]\w*[A-Z]/ &&
-                           $var !~ /"^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
-                           !defined $camelcase{$var}) {
-                               $camelcase{$var} = 1;
-                               WARN("CAMELCASE",
-                                    "Avoid CamelCase: <$var>\n" . $herecurr);
+
+#gcc binary extension
+                       if ($var =~ /^$Binary$/) {
+                               WARN("GCC_BINARY_CONSTANT",
+                                    "Avoid gcc v4.3+ binary constant extension: <$var>\n" . $herecurr);
+                       }
+
+#CamelCase
+                       if ($var !~ /^$Constant$/ &&
+                           $var =~ /[A-Z][a-z]|[a-z][A-Z]/ &&
+#Ignore Page<foo> variants
+                           $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
+#Ignore SI style variants like nS, mV and dB (ie: max_uV, regulator_min_uA_show)
+                           $var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/) {
+                               seed_camelcase_includes() if ($check);
+                               if (!defined $camelcase{$var}) {
+                                       $camelcase{$var} = 1;
+                                       CHK("CAMELCASE",
+                                           "Avoid CamelCase: <$var>\n" . $herecurr);
+                               }
                        }
                }
 
@@ -3021,7 +3349,7 @@ sub process {
                        if ($dstat ne '' &&
                            $dstat !~ /^(?:$Ident|-?$Constant),$/ &&                    # 10, // foo(),
                            $dstat !~ /^(?:$Ident|-?$Constant);$/ &&                    # foo();
-                           $dstat !~ /^[!~-]?(?:$Ident|$Constant)$/ &&         # 10 // foo() // !foo // ~foo // -foo
+                           $dstat !~ /^[!~-]?(?:$Lval|$Constant)$/ &&          # 10 // foo() // !foo // ~foo // -foo // foo->bar // foo.bar->baz
                            $dstat !~ /^'X'$/ &&                                        # character constants
                            $dstat !~ /$exceptions/ &&
                            $dstat !~ /^\.$Ident\s*=/ &&                                # .foo =
@@ -3230,11 +3558,11 @@ sub process {
                }
 
 # check for unnecessary blank lines around braces
-               if (($line =~ /^.\s*}\s*$/ && $prevline =~ /^.\s*$/)) {
+               if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) {
                        CHK("BRACES",
                            "Blank lines aren't necessary before a close brace '}'\n" . $hereprev);
                }
-               if (($line =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) {
+               if (($rawline =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) {
                        CHK("BRACES",
                            "Blank lines aren't necessary after an open brace '{'\n" . $hereprev);
                }
@@ -3279,6 +3607,18 @@ sub process {
                        }
                }
 
+# check for comparisons of jiffies
+               if ($line =~ /\bjiffies\s*$Compare|$Compare\s*jiffies\b/) {
+                       WARN("JIFFIES_COMPARISON",
+                            "Comparing jiffies is almost always wrong; prefer time_after, time_before and friends\n" . $herecurr);
+               }
+
+# check for comparisons of get_jiffies_64()
+               if ($line =~ /\bget_jiffies_64\s*\(\s*\)\s*$Compare|$Compare\s*get_jiffies_64\s*\(\s*\)/) {
+                       WARN("JIFFIES_COMPARISON",
+                            "Comparing get_jiffies_64() is almost always wrong; prefer time_after64, time_before64 and friends\n" . $herecurr);
+               }
+
 # warn about #ifdefs in C files
 #              if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
 #                      print "#ifdef in C files should be avoided\n";
@@ -3288,8 +3628,13 @@ sub process {
 
 # warn about spacing in #ifdefs
                if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
-                       ERROR("SPACING",
-                             "exactly one space required after that #$1\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "exactly one space required after that #$1\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 /;
+                       }
+
                }
 
 # check for spinlock_t definitions without a comment.
@@ -3495,6 +3840,14 @@ sub process {
                             "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
                }
 
+# alloc style
+# p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...)
+               if ($^V && $^V ge 5.10.0 &&
+                   $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*([kv][mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) {
+                       CHK("ALLOC_SIZEOF_STRUCT",
+                           "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr);
+               }
+
 # check for krealloc arg reuse
                if ($^V && $^V ge 5.10.0 &&
                    $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/) {
@@ -3540,6 +3893,33 @@ sub process {
                             "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n"  . $herecurr);
                }
 
+# check for comparisons against true and false
+               if ($line =~ /\+\s*(.*?)\b(true|false|$Lval)\s*(==|\!=)\s*(true|false|$Lval)\b(.*)$/i) {
+                       my $lead = $1;
+                       my $arg = $2;
+                       my $test = $3;
+                       my $otype = $4;
+                       my $trail = $5;
+                       my $op = "!";
+
+                       ($arg, $otype) = ($otype, $arg) if ($arg =~ /^(?:true|false)$/i);
+
+                       my $type = lc($otype);
+                       if ($type =~ /^(?:true|false)$/) {
+                               if (("$test" eq "==" && "$type" eq "true") ||
+                                   ("$test" eq "!=" && "$type" eq "false")) {
+                                       $op = "";
+                               }
+
+                               CHK("BOOL_COMPARISON",
+                                   "Using comparison to $otype is error prone\n" . $herecurr);
+
+## maybe suggesting a correct construct would better
+##                                 "Using comparison to $otype is error prone.  Perhaps use '${lead}${op}${arg}${trail}'\n" . $herecurr);
+
+                       }
+               }
+
 # check for semaphores initialized locked
                if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
                        WARN("CONSIDER_COMPLETION",
@@ -3717,6 +4097,40 @@ sub process {
            print "\n\n";
        }
 
+       if ($clean == 0 && $fix && "@rawlines" ne "@fixed") {
+               my $newfile = $filename . ".EXPERIMENTAL-checkpatch-fixes";
+               my $linecount = 0;
+               my $f;
+
+               open($f, '>', $newfile)
+                   or die "$P: Can't open $newfile for write\n";
+               foreach my $fixed_line (@fixed) {
+                       $linecount++;
+                       if ($file) {
+                               if ($linecount > 3) {
+                                       $fixed_line =~ s/^\+//;
+                                       print $f $fixed_line. "\n";
+                               }
+                       } else {
+                               print $f $fixed_line . "\n";
+                       }
+               }
+               close($f);
+
+               if (!$quiet) {
+                       print << "EOM";
+Wrote EXPERIMENTAL --fix correction(s) to '$newfile'
+
+Do _NOT_ trust the results written to this file.
+Do _NOT_ submit these changes without inspecting them for correctness.
+
+This EXPERIMENTAL file is simply a convenience to help rewrite patches.
+No warranties, expressed or implied...
+
+EOM
+               }
+       }
+
        if ($clean == 1 && $quiet == 0) {
                print "$vname has no obvious style problems and is ready for submission.\n"
        }
index e66d4d258e1a5eec2a8584e3403c9727cb1580eb..bb5d115ca671c5b19073526fa815baa5f728fb2c 100644 (file)
@@ -177,5 +177,11 @@ int main(void)
        DEVID(mei_cl_device_id);
        DEVID_FIELD(mei_cl_device_id, name);
 
+       DEVID(rio_device_id);
+       DEVID_FIELD(rio_device_id, did);
+       DEVID_FIELD(rio_device_id, vid);
+       DEVID_FIELD(rio_device_id, asm_did);
+       DEVID_FIELD(rio_device_id, asm_vid);
+
        return 0;
 }
index 45f9a3377dcd8d60f1df08542ca804537e443225..d9e67b719f08e013d4d8da8aaf579332e19f9c23 100644 (file)
@@ -1145,6 +1145,26 @@ static int do_mei_entry(const char *filename, void *symval,
 }
 ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry);
 
+/* Looks like: rapidio:vNdNavNadN */
+static int do_rio_entry(const char *filename,
+                       void *symval, char *alias)
+{
+       DEF_FIELD(symval, rio_device_id, did);
+       DEF_FIELD(symval, rio_device_id, vid);
+       DEF_FIELD(symval, rio_device_id, asm_did);
+       DEF_FIELD(symval, rio_device_id, asm_vid);
+
+       strcpy(alias, "rapidio:");
+       ADD(alias, "v", vid != RIO_ANY_ID, vid);
+       ADD(alias, "d", did != RIO_ANY_ID, did);
+       ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid);
+       ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did);
+
+       add_wildcard(alias);
+       return 1;
+}
+ADD_TO_DEVTABLE("rapidio", rio_device_id, do_rio_entry);
+
 /* Does namelen bytes of name exactly match the symbol? */
 static bool sym_is(const char *name, unsigned namelen, const char *symbol)
 {
index a4be8e112bb63c2ece5baa423e9aef65c92a1ad1..3d155dd27eb6da8eab9a81767fe30796be1cf4d3 100644 (file)
@@ -884,7 +884,7 @@ static void check_section(const char *modname, struct elf_info *elf,
 #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
 
 #define DATA_SECTIONS ".data$", ".data.rel$"
-#define TEXT_SECTIONS ".text$"
+#define TEXT_SECTIONS ".text$", ".text.unlikely$"
 
 #define INIT_SECTIONS      ".init.*"
 #define CPU_INIT_SECTIONS  ".cpuinit.*"
index 1f10e89d15b4d03a07523e6c89482b5b0edfdc3d..f9ce1160419be2a81b7dabf097fc453fdb1ce9c3 100644 (file)
 #include <tools/be_byteshift.h>
 #include <tools/le_byteshift.h>
 
+#ifndef EM_AARCH64
+#define EM_AARCH64     183
+#endif
+
 static int fd_map;     /* File descriptor for file being modified. */
 static int mmap_failed; /* Boolean flag. */
 static void *ehdr_curr; /* current ElfXX_Ehdr *  for resource cleanup */
@@ -249,6 +253,7 @@ do_file(char const *const fname)
                custom_sort = sort_relative_table;
                break;
        case EM_ARM:
+       case EM_AARCH64:
        case EM_MIPS:
                break;
        }  /* end switch */
index 3ae28db5a64fb8595aadf512ebca42020e4e8106..031d2d9dd6950b7e6c1bf6f3b16f2a37a9ab9e22 100644 (file)
@@ -88,7 +88,7 @@ static const char *const aa_audit_type[] = {
        "HINT",
        "STATUS",
        "ERROR",
-       "KILLED"
+       "KILLED",
        "AUTO"
 };
 
index 8a9b5027c81387079840e09437760175b9964390..d5af1d15f26d6feeec7acc5e421cbb25ca9de9ce 100644 (file)
@@ -68,6 +68,23 @@ void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
        aa_get_profile(new->onexec);
 }
 
+/**
+ * aa_get_task_profile - Get another task's profile
+ * @task: task to query  (NOT NULL)
+ *
+ * Returns: counted reference to @task's profile
+ */
+struct aa_profile *aa_get_task_profile(struct task_struct *task)
+{
+       struct aa_profile *p;
+
+       rcu_read_lock();
+       p = aa_get_profile(__aa_task_profile(task));
+       rcu_read_unlock();
+
+       return p;
+}
+
 /**
  * aa_replace_current_profile - replace the current tasks profiles
  * @profile: new profile  (NOT NULL)
@@ -76,7 +93,7 @@ void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
  */
 int aa_replace_current_profile(struct aa_profile *profile)
 {
-       struct aa_task_cxt *cxt = current_cred()->security;
+       struct aa_task_cxt *cxt = current_cxt();
        struct cred *new;
        BUG_ON(!profile);
 
@@ -87,17 +104,13 @@ int aa_replace_current_profile(struct aa_profile *profile)
        if (!new)
                return -ENOMEM;
 
-       cxt = new->security;
-       if (unconfined(profile) || (cxt->profile->ns != profile->ns)) {
+       cxt = cred_cxt(new);
+       if (unconfined(profile) || (cxt->profile->ns != profile->ns))
                /* if switching to unconfined or a different profile namespace
                 * clear out context state
                 */
-               aa_put_profile(cxt->previous);
-               aa_put_profile(cxt->onexec);
-               cxt->previous = NULL;
-               cxt->onexec = NULL;
-               cxt->token = 0;
-       }
+               aa_clear_task_cxt_trans(cxt);
+
        /* be careful switching cxt->profile, when racing replacement it
         * is possible that cxt->profile->replacedby is the reference keeping
         * @profile valid, so make sure to get its reference before dropping
@@ -123,7 +136,7 @@ int aa_set_current_onexec(struct aa_profile *profile)
        if (!new)
                return -ENOMEM;
 
-       cxt = new->security;
+       cxt = cred_cxt(new);
        aa_get_profile(profile);
        aa_put_profile(cxt->onexec);
        cxt->onexec = profile;
@@ -150,7 +163,7 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)
                return -ENOMEM;
        BUG_ON(!profile);
 
-       cxt = new->security;
+       cxt = cred_cxt(new);
        if (!cxt->previous) {
                /* transfer refcount */
                cxt->previous = cxt->profile;
@@ -187,7 +200,7 @@ int aa_restore_previous_profile(u64 token)
        if (!new)
                return -ENOMEM;
 
-       cxt = new->security;
+       cxt = cred_cxt(new);
        if (cxt->token != token) {
                abort_creds(new);
                return -EACCES;
@@ -205,11 +218,10 @@ int aa_restore_previous_profile(u64 token)
                aa_get_profile(cxt->profile);
                aa_put_profile(cxt->previous);
        }
-       /* clear exec && prev information when restoring to previous context */
+       /* ref has been transfered so avoid putting ref in clear_task_cxt */
        cxt->previous = NULL;
-       cxt->token = 0;
-       aa_put_profile(cxt->onexec);
-       cxt->onexec = NULL;
+       /* clear exec && prev information when restoring to previous context */
+       aa_clear_task_cxt_trans(cxt);
 
        commit_creds(new);
        return 0;
index 859abdaac1eafb62fddb202eb6fcdf3777e9daa2..01b7bd669a88d8d130f32097d0d3200a6068cbe5 100644 (file)
@@ -62,17 +62,14 @@ static int may_change_ptraced_domain(struct task_struct *task,
                                     struct aa_profile *to_profile)
 {
        struct task_struct *tracer;
-       const struct cred *cred = NULL;
        struct aa_profile *tracerp = NULL;
        int error = 0;
 
        rcu_read_lock();
        tracer = ptrace_parent(task);
-       if (tracer) {
+       if (tracer)
                /* released below */
-               cred = get_task_cred(tracer);
-               tracerp = aa_cred_profile(cred);
-       }
+               tracerp = aa_get_task_profile(tracer);
 
        /* not ptraced */
        if (!tracer || unconfined(tracerp))
@@ -82,8 +79,7 @@ static int may_change_ptraced_domain(struct task_struct *task,
 
 out:
        rcu_read_unlock();
-       if (cred)
-               put_cred(cred);
+       aa_put_profile(tracerp);
 
        return error;
 }
@@ -360,7 +356,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
        if (bprm->cred_prepared)
                return 0;
 
-       cxt = bprm->cred->security;
+       cxt = cred_cxt(bprm->cred);
        BUG_ON(!cxt);
 
        profile = aa_get_profile(aa_newest_version(cxt->profile));
@@ -443,6 +439,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                        } else {
                                error = -ENOENT;
                                info = "profile not found";
+                               /* remove MAY_EXEC to audit as failure */
+                               perms.allow &= ~MAY_EXEC;
                        }
                }
        } else if (COMPLAIN_MODE(profile)) {
@@ -514,11 +512,7 @@ x_clear:
        cxt->profile = new_profile;
 
        /* clear out all temporary/transitional state from the context */
-       aa_put_profile(cxt->previous);
-       aa_put_profile(cxt->onexec);
-       cxt->previous = NULL;
-       cxt->onexec = NULL;
-       cxt->token = 0;
+       aa_clear_task_cxt_trans(cxt);
 
 audit:
        error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
@@ -557,7 +551,7 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm)
 void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
 {
        struct aa_profile *profile = __aa_current_profile();
-       struct aa_task_cxt *new_cxt = bprm->cred->security;
+       struct aa_task_cxt *new_cxt = cred_cxt(bprm->cred);
 
        /* bail out if unconfined or not changing profile */
        if ((new_cxt->profile == profile) ||
@@ -634,7 +628,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
 
        /* released below */
        cred = get_current_cred();
-       cxt = cred->security;
+       cxt = cred_cxt(cred);
        profile = aa_cred_profile(cred);
        previous_profile = cxt->previous;
 
@@ -750,7 +744,6 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
                      bool permtest)
 {
        const struct cred *cred;
-       struct aa_task_cxt *cxt;
        struct aa_profile *profile, *target = NULL;
        struct aa_namespace *ns = NULL;
        struct file_perms perms = {};
@@ -770,7 +763,6 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
        }
 
        cred = get_current_cred();
-       cxt = cred->security;
        profile = aa_cred_profile(cred);
 
        /*
index 40aedd9f73eaf76c7ccab0374d5ae48db3ee2a31..1ba2ca56a6efe0245327b16ee4891981746c5b7a 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef __APPARMOR_H
 #define __APPARMOR_H
 
+#include <linux/slab.h>
 #include <linux/fs.h>
 
 #include "match.h"
@@ -64,9 +65,18 @@ extern int apparmor_initialized __initdata;
 /* fn's in lib */
 char *aa_split_fqname(char *args, char **ns_name);
 void aa_info_message(const char *str);
-void *kvmalloc(size_t size);
+void *__aa_kvmalloc(size_t size, gfp_t flags);
 void kvfree(void *buffer);
 
+static inline void *kvmalloc(size_t size)
+{
+       return __aa_kvmalloc(size, 0);
+}
+
+static inline void *kvzalloc(size_t size)
+{
+       return __aa_kvmalloc(size, __GFP_ZERO);
+}
 
 /**
  * aa_strneq - compare null terminated @str to a non null terminated substring
index a9cbee4d9e48de15a972ea8ce292323283459c73..d44ba5802e3dc03f56c6d183a9d97a3d608ee8e9 100644 (file)
@@ -21,6 +21,9 @@
 
 #include "policy.h"
 
+#define cred_cxt(X) (X)->security
+#define current_cxt() cred_cxt(current_cred())
+
 /* struct aa_file_cxt - the AppArmor context the file was opened in
  * @perms: the permission the file was opened with
  *
@@ -80,23 +83,8 @@ int aa_replace_current_profile(struct aa_profile *profile);
 int aa_set_current_onexec(struct aa_profile *profile);
 int aa_set_current_hat(struct aa_profile *profile, u64 token);
 int aa_restore_previous_profile(u64 cookie);
+struct aa_profile *aa_get_task_profile(struct task_struct *task);
 
-/**
- * __aa_task_is_confined - determine if @task has any confinement
- * @task: task to check confinement of  (NOT NULL)
- *
- * If @task != current needs to be called in RCU safe critical section
- */
-static inline bool __aa_task_is_confined(struct task_struct *task)
-{
-       struct aa_task_cxt *cxt = __task_cred(task)->security;
-
-       BUG_ON(!cxt || !cxt->profile);
-       if (unconfined(aa_newest_version(cxt->profile)))
-               return 0;
-
-       return 1;
-}
 
 /**
  * aa_cred_profile - obtain cred's profiles
@@ -108,11 +96,35 @@ static inline bool __aa_task_is_confined(struct task_struct *task)
  */
 static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
 {
-       struct aa_task_cxt *cxt = cred->security;
+       struct aa_task_cxt *cxt = cred_cxt(cred);
        BUG_ON(!cxt || !cxt->profile);
        return aa_newest_version(cxt->profile);
 }
 
+/**
+ * __aa_task_profile - retrieve another task's profile
+ * @task: task to query  (NOT NULL)
+ *
+ * Returns: @task's profile without incrementing its ref count
+ *
+ * If @task != current needs to be called in RCU safe critical section
+ */
+static inline struct aa_profile *__aa_task_profile(struct task_struct *task)
+{
+       return aa_cred_profile(__task_cred(task));
+}
+
+/**
+ * __aa_task_is_confined - determine if @task has any confinement
+ * @task: task to check confinement of  (NOT NULL)
+ *
+ * If @task != current needs to be called in RCU safe critical section
+ */
+static inline bool __aa_task_is_confined(struct task_struct *task)
+{
+       return !unconfined(__aa_task_profile(task));
+}
+
 /**
  * __aa_current_profile - find the current tasks confining profile
  *
@@ -136,7 +148,7 @@ static inline struct aa_profile *__aa_current_profile(void)
  */
 static inline struct aa_profile *aa_current_profile(void)
 {
-       const struct aa_task_cxt *cxt = current_cred()->security;
+       const struct aa_task_cxt *cxt = current_cxt();
        struct aa_profile *profile;
        BUG_ON(!cxt || !cxt->profile);
 
@@ -151,4 +163,17 @@ static inline struct aa_profile *aa_current_profile(void)
        return profile;
 }
 
+/**
+ * aa_clear_task_cxt_trans - clear transition tracking info from the cxt
+ * @cxt: task context to clear (NOT NULL)
+ */
+static inline void aa_clear_task_cxt_trans(struct aa_task_cxt *cxt)
+{
+       aa_put_profile(cxt->previous);
+       aa_put_profile(cxt->onexec);
+       cxt->previous = NULL;
+       cxt->onexec = NULL;
+       cxt->token = 0;
+}
+
 #endif /* __AA_CONTEXT_H */
index 967b2deda376a2b3ff63821301b26ba600260fc6..2c922b86bd44f5ba7e4b519df43c663b21c34ad3 100644 (file)
@@ -186,11 +186,6 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules)
        aa_free_domain_entries(&rules->trans);
 }
 
-#define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40))
-
-/* from namei.c */
-#define MAP_OPEN_FLAGS(x) ((((x) + 1) & O_ACCMODE) ? (x) + 1 : (x))
-
 /**
  * aa_map_file_perms - map file flags to AppArmor permissions
  * @file: open file to map flags to AppArmor permissions
@@ -199,8 +194,13 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules)
  */
 static inline u32 aa_map_file_to_perms(struct file *file)
 {
-       int flags = MAP_OPEN_FLAGS(file->f_flags);
-       u32 perms = ACC_FMODE(file->f_mode);
+       int flags = file->f_flags;
+       u32 perms = 0;
+
+       if (file->f_mode & FMODE_WRITE)
+               perms |= MAY_WRITE;
+       if (file->f_mode & FMODE_READ)
+               perms |= MAY_READ;
 
        if ((flags & O_APPEND) && (perms & MAY_WRITE))
                perms = (perms & ~MAY_WRITE) | MAY_APPEND;
index 775843e7f984b93dc9d68d1f84df7b3c5d99a7ab..001c43aa04065b99bdc3f6484b85213de3a2bf7e 100644 (file)
@@ -4,7 +4,7 @@
  * This file contains AppArmor policy dfa matching engine definitions.
  *
  * Copyright (C) 1998-2008 Novell/SUSE
- * Copyright 2009-2010 Canonical Ltd.
+ * Copyright 2009-2012 Canonical Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
 #define __AA_MATCH_H
 
 #include <linux/kref.h>
-#include <linux/workqueue.h>
 
 #define DFA_NOMATCH                    0
 #define DFA_START                      1
 
-#define DFA_VALID_PERM_MASK            0xffffffff
-#define DFA_VALID_PERM2_MASK           0xffffffff
 
 /**
  * The format used for transition tables is based on the GNU flex table
  * file format (--tables-file option; see Table File Format in the flex
  * info pages and the flex sources for documentation). The magic number
  * used in the header is 0x1B5E783D instead of 0xF13C57B1 though, because
- * the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used
- * slightly differently (see the apparmor-parser package).
+ * new tables have been defined and others YY_ID_CHK (check) and YY_ID_DEF
+ * (default) tables are used slightly differently (see the apparmor-parser
+ * package).
+ *
+ *
+ * The data in the packed dfa is stored in network byte order, and the tables
+ * are arranged for flexibility.  We convert the table data to host native
+ * byte order.
+ *
+ * The dfa begins with a table set header, and is followed by the actual
+ * tables.
  */
 
 #define YYTH_MAGIC     0x1B5E783D
-#define YYTH_DEF_RECURSE 0x1                   /* DEF Table is recursive */
 
 struct table_set_header {
        u32 th_magic;           /* YYTH_MAGIC */
@@ -63,7 +68,7 @@ struct table_set_header {
 #define YYTD_DATA32    4
 #define YYTD_DATA64    8
 
-/* Each ACCEPT2 table gets 6 dedicated flags, YYTD_DATAX define the
+/* ACCEPT & ACCEPT2 tables gets 6 dedicated flags, YYTD_DATAX define the
  * first flags
  */
 #define ACCEPT1_FLAGS(X) ((X) & 0x3f)
index bda4569fdd838bf7fa0f86f98a9a193ad5172d8d..b25491a3046a2a1dd14f16b31828c52d19d5df7e 100644 (file)
 extern const char *const profile_mode_names[];
 #define APPARMOR_NAMES_MAX_INDEX 3
 
-#define COMPLAIN_MODE(_profile)        \
-       ((aa_g_profile_mode == APPARMOR_COMPLAIN) || \
-        ((_profile)->mode == APPARMOR_COMPLAIN))
+#define PROFILE_MODE(_profile, _mode)          \
+       ((aa_g_profile_mode == (_mode)) ||      \
+        ((_profile)->mode == (_mode)))
 
-#define KILL_MODE(_profile) \
-       ((aa_g_profile_mode == APPARMOR_KILL) || \
-        ((_profile)->mode == APPARMOR_KILL))
+#define COMPLAIN_MODE(_profile)        PROFILE_MODE((_profile), APPARMOR_COMPLAIN)
+
+#define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL)
 
 #define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
 
@@ -105,6 +105,7 @@ struct aa_ns_acct {
  * @acct: accounting for the namespace
  * @unconfined: special unconfined profile for the namespace
  * @sub_ns: list of namespaces under the current namespace.
+ * @uniq_null: uniq value used for null learning profiles
  *
  * An aa_namespace defines the set profiles that are searched to determine
  * which profile to attach to a task.  Profiles can not be shared between
@@ -127,6 +128,7 @@ struct aa_namespace {
        struct aa_ns_acct acct;
        struct aa_profile *unconfined;
        struct list_head sub_ns;
+       atomic_t uniq_null;
 };
 
 /* struct aa_policydb - match engine for a policy
@@ -148,7 +150,6 @@ struct aa_policydb {
  * @rename: optional profile name that this profile renamed
  * @xmatch: optional extended matching for unconfined executables names
  * @xmatch_len: xmatch prefix len, used to determine xmatch priority
- * @sid: the unique security id number of this profile
  * @audit: the auditing mode of the profile
  * @mode: the enforcement mode of the profile
  * @flags: flags controlling profile behavior
@@ -184,7 +185,6 @@ struct aa_profile {
 
        struct aa_dfa *xmatch;
        int xmatch_len;
-       u32 sid;
        enum audit_mode audit;
        enum profile_mode mode;
        u32 flags;
index 544aa6b766a4209b47d3df2b50a1c3c46e315b7e..6bd5f33d9533ab166907b5dceb9eb9f8cc591549 100644 (file)
@@ -21,6 +21,5 @@
 int aa_getprocattr(struct aa_profile *profile, char **string);
 int aa_setprocattr_changehat(char *args, size_t size, int test);
 int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
-int aa_setprocattr_permipc(char *fqname);
 
 #endif /* __AA_PROCATTR_H */
index 020db35c301026cd9b2e80c7cb934b3039ee1019..513ca0e48965a8a78bf4e6322794b528534fe500 100644 (file)
@@ -16,7 +16,9 @@
 
 #include <linux/types.h>
 
-struct aa_profile;
+/* sid value that will not be allocated */
+#define AA_SID_INVALID 0
+#define AA_SID_ALLOC AA_SID_INVALID
 
 u32 aa_alloc_sid(void);
 void aa_free_sid(u32 sid);
index cf1071b14232a48e4f963db40a14a4c3937ce8e1..c51d2266587e8b62d09394c0d8320a4b53001569 100644 (file)
@@ -95,23 +95,18 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
         *       - tracer profile has CAP_SYS_PTRACE
         */
 
-       struct aa_profile *tracer_p;
-       /* cred released below */
-       const struct cred *cred = get_task_cred(tracer);
+       struct aa_profile *tracer_p = aa_get_task_profile(tracer);
        int error = 0;
-       tracer_p = aa_cred_profile(cred);
 
        if (!unconfined(tracer_p)) {
-               /* lcred released below */
-               const struct cred *lcred = get_task_cred(tracee);
-               struct aa_profile *tracee_p = aa_cred_profile(lcred);
+               struct aa_profile *tracee_p = aa_get_task_profile(tracee);
 
                error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode);
                error = aa_audit_ptrace(tracer_p, tracee_p, error);
 
-               put_cred(lcred);
+               aa_put_profile(tracee_p);
        }
-       put_cred(cred);
+       aa_put_profile(tracer_p);
 
        return error;
 }
index 7430298116d6b2b71b9e6c0c55d6b2ff4867ee96..fcfe0233574cb2f32197dcbe84d5170da663d779 100644 (file)
@@ -45,8 +45,10 @@ char *aa_split_fqname(char *fqname, char **ns_name)
                *ns_name = skip_spaces(&name[1]);
                if (split) {
                        /* overwrite ':' with \0 */
-                       *split = 0;
-                       name = skip_spaces(split + 1);
+                       *split++ = 0;
+                       if (strncmp(split, "//", 2) == 0)
+                               split += 2;
+                       name = skip_spaces(split);
                } else
                        /* a ns name without a following profile is allowed */
                        name = NULL;
@@ -75,15 +77,16 @@ void aa_info_message(const char *str)
 }
 
 /**
- * kvmalloc - do allocation preferring kmalloc but falling back to vmalloc
- * @size: size of allocation
+ * __aa_kvmalloc - do allocation preferring kmalloc but falling back to vmalloc
+ * @size: how many bytes of memory are required
+ * @flags: the type of memory to allocate (see kmalloc).
  *
  * Return: allocated buffer or NULL if failed
  *
  * It is possible that policy being loaded from the user is larger than
  * what can be allocated by kmalloc, in those cases fall back to vmalloc.
  */
-void *kvmalloc(size_t size)
+void *__aa_kvmalloc(size_t size, gfp_t flags)
 {
        void *buffer = NULL;
 
@@ -92,31 +95,21 @@ void *kvmalloc(size_t size)
 
        /* do not attempt kmalloc if we need more than 16 pages at once */
        if (size <= (16*PAGE_SIZE))
-               buffer = kmalloc(size, GFP_NOIO | __GFP_NOWARN);
+               buffer = kmalloc(size, flags | GFP_NOIO | __GFP_NOWARN);
        if (!buffer) {
                /* see kvfree for why size must be at least work_struct size
                 * when allocated via vmalloc
                 */
                if (size < sizeof(struct work_struct))
                        size = sizeof(struct work_struct);
-               buffer = vmalloc(size);
+               if (flags & __GFP_ZERO)
+                       buffer = vzalloc(size);
+               else
+                       buffer = vmalloc(size);
        }
        return buffer;
 }
 
-/**
- * do_vfree - workqueue routine for freeing vmalloced memory
- * @work: data to be freed
- *
- * The work_struct is overlaid to the data being freed, as at the point
- * the work is scheduled the data is no longer valid, be its freeing
- * needs to be delayed until safe.
- */
-static void do_vfree(struct work_struct *work)
-{
-       vfree(work);
-}
-
 /**
  * kvfree - free an allocation do by kvmalloc
  * @buffer: buffer to free (MAYBE_NULL)
@@ -125,13 +118,8 @@ static void do_vfree(struct work_struct *work)
  */
 void kvfree(void *buffer)
 {
-       if (is_vmalloc_addr(buffer)) {
-               /* Data is no longer valid so just use the allocated space
-                * as the work_struct
-                */
-               struct work_struct *work = (struct work_struct *) buffer;
-               INIT_WORK(work, do_vfree);
-               schedule_work(work);
-       } else
+       if (is_vmalloc_addr(buffer))
+               vfree(buffer);
+       else
                kfree(buffer);
 }
index b21830eced4185204d22d7d635fdb8741c1af700..2e2a0dd4a73f1234425ded75027baea3b1e0b03e 100644 (file)
@@ -48,8 +48,8 @@ int apparmor_initialized __initdata;
  */
 static void apparmor_cred_free(struct cred *cred)
 {
-       aa_free_task_context(cred->security);
-       cred->security = NULL;
+       aa_free_task_context(cred_cxt(cred));
+       cred_cxt(cred) = NULL;
 }
 
 /*
@@ -62,7 +62,7 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
        if (!cxt)
                return -ENOMEM;
 
-       cred->security = cxt;
+       cred_cxt(cred) = cxt;
        return 0;
 }
 
@@ -77,8 +77,8 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
        if (!cxt)
                return -ENOMEM;
 
-       aa_dup_task_context(cxt, old->security);
-       new->security = cxt;
+       aa_dup_task_context(cxt, cred_cxt(old));
+       cred_cxt(new) = cxt;
        return 0;
 }
 
@@ -87,8 +87,8 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
  */
 static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
 {
-       const struct aa_task_cxt *old_cxt = old->security;
-       struct aa_task_cxt *new_cxt = new->security;
+       const struct aa_task_cxt *old_cxt = cred_cxt(old);
+       struct aa_task_cxt *new_cxt = cred_cxt(new);
 
        aa_dup_task_context(new_cxt, old_cxt);
 }
@@ -469,7 +469,6 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd)
 static int common_mmap(int op, struct file *file, unsigned long prot,
                       unsigned long flags)
 {
-       struct dentry *dentry;
        int mask = 0;
 
        if (!file || !file->f_security)
@@ -486,7 +485,6 @@ static int common_mmap(int op, struct file *file, unsigned long prot,
        if (prot & PROT_EXEC)
                mask |= AA_EXEC_MMAP;
 
-       dentry = file->f_path.dentry;
        return common_file_perm(op, file, mask);
 }
 
@@ -507,11 +505,9 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
                                char **value)
 {
        int error = -ENOENT;
-       struct aa_profile *profile;
        /* released below */
        const struct cred *cred = get_task_cred(task);
-       struct aa_task_cxt *cxt = cred->security;
-       profile = aa_cred_profile(cred);
+       struct aa_task_cxt *cxt = cred_cxt(cred);
 
        if (strcmp(name, "current") == 0)
                error = aa_getprocattr(aa_newest_version(cxt->profile),
@@ -533,6 +529,8 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
 static int apparmor_setprocattr(struct task_struct *task, char *name,
                                void *value, size_t size)
 {
+       struct common_audit_data sa;
+       struct apparmor_audit_data aad = {0,};
        char *command, *args = value;
        size_t arg_size;
        int error;
@@ -576,30 +574,31 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
                } else if (strcmp(command, "permprofile") == 0) {
                        error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
                                                             AA_DO_TEST);
-               } else if (strcmp(command, "permipc") == 0) {
-                       error = aa_setprocattr_permipc(args);
-               } else {
-                       struct common_audit_data sa;
-                       struct apparmor_audit_data aad = {0,};
-                       sa.type = LSM_AUDIT_DATA_NONE;
-                       sa.aad = &aad;
-                       aad.op = OP_SETPROCATTR;
-                       aad.info = name;
-                       aad.error = -EINVAL;
-                       return aa_audit(AUDIT_APPARMOR_DENIED,
-                                       __aa_current_profile(), GFP_KERNEL,
-                                       &sa, NULL);
-               }
+               } else
+                       goto fail;
        } else if (strcmp(name, "exec") == 0) {
-               error = aa_setprocattr_changeprofile(args, AA_ONEXEC,
-                                                    !AA_DO_TEST);
-       } else {
+               if (strcmp(command, "exec") == 0)
+                       error = aa_setprocattr_changeprofile(args, AA_ONEXEC,
+                                                            !AA_DO_TEST);
+               else
+                       goto fail;
+       } else
                /* only support the "current" and "exec" process attributes */
                return -EINVAL;
-       }
+
        if (!error)
                error = size;
        return error;
+
+fail:
+       sa.type = LSM_AUDIT_DATA_NONE;
+       sa.aad = &aad;
+       aad.profile = aa_current_profile();
+       aad.op = OP_SETPROCATTR;
+       aad.info = name;
+       aad.error = -EINVAL;
+       aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL);
+       return -EINVAL;
 }
 
 static int apparmor_task_setrlimit(struct task_struct *task,
@@ -886,7 +885,7 @@ static int __init set_init_cxt(void)
                return -ENOMEM;
 
        cxt->profile = aa_get_profile(root_ns->unconfined);
-       cred->security = cxt;
+       cred_cxt(cred) = cxt;
 
        return 0;
 }
@@ -915,8 +914,11 @@ static int __init apparmor_init(void)
 
        error = register_security(&apparmor_ops);
        if (error) {
+               struct cred *cred = (struct cred *)current->real_cred;
+               aa_free_task_context(cred_cxt(cred));
+               cred_cxt(cred) = NULL;
                AA_ERROR("Unable to register AppArmor\n");
-               goto set_init_cxt_out;
+               goto register_security_out;
        }
 
        /* Report that AppArmor successfully initialized */
@@ -930,9 +932,6 @@ static int __init apparmor_init(void)
 
        return error;
 
-set_init_cxt_out:
-       aa_free_task_context(current->real_cred->security);
-
 register_security_out:
        aa_free_root_ns();
 
index 90971a8c37898256b1d60b211bdf27865d1f75e4..727eb4200d5c922d8818a6f0a84ace38fd759306 100644 (file)
@@ -4,7 +4,7 @@
  * This file contains AppArmor dfa based regular expression matching engine
  *
  * Copyright (C) 1998-2008 Novell/SUSE
- * Copyright 2009-2010 Canonical Ltd.
+ * Copyright 2009-2012 Canonical Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -23,6 +23,8 @@
 #include "include/apparmor.h"
 #include "include/match.h"
 
+#define base_idx(X) ((X) & 0xffffff)
+
 /**
  * unpack_table - unpack a dfa table (one of accept, default, base, next check)
  * @blob: data to unpack (NOT NULL)
@@ -30,7 +32,7 @@
  *
  * Returns: pointer to table else NULL on failure
  *
- * NOTE: must be freed by kvfree (not kmalloc)
+ * NOTE: must be freed by kvfree (not kfree)
  */
 static struct table_header *unpack_table(char *blob, size_t bsize)
 {
@@ -57,7 +59,7 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
        if (bsize < tsize)
                goto out;
 
-       table = kvmalloc(tsize);
+       table = kvzalloc(tsize);
        if (table) {
                *table = th;
                if (th.td_flags == YYTD_DATA8)
@@ -137,8 +139,7 @@ static int verify_dfa(struct aa_dfa *dfa, int flags)
                for (i = 0; i < state_count; i++) {
                        if (DEFAULT_TABLE(dfa)[i] >= state_count)
                                goto out;
-                       /* TODO: do check that DEF state recursion terminates */
-                       if (BASE_TABLE(dfa)[i] + 255 >= trans_count) {
+                       if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
                                printk(KERN_ERR "AppArmor DFA next/check upper "
                                       "bounds error\n");
                                goto out;
@@ -314,7 +315,7 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
                u8 *equiv = EQUIV_TABLE(dfa);
                /* default is direct to next state */
                for (; len; len--) {
-                       pos = base[state] + equiv[(u8) *str++];
+                       pos = base_idx(base[state]) + equiv[(u8) *str++];
                        if (check[pos] == state)
                                state = next[pos];
                        else
@@ -323,7 +324,7 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
        } else {
                /* default is direct to next state */
                for (; len; len--) {
-                       pos = base[state] + (u8) *str++;
+                       pos = base_idx(base[state]) + (u8) *str++;
                        if (check[pos] == state)
                                state = next[pos];
                        else
@@ -364,7 +365,7 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
                u8 *equiv = EQUIV_TABLE(dfa);
                /* default is direct to next state */
                while (*str) {
-                       pos = base[state] + equiv[(u8) *str++];
+                       pos = base_idx(base[state]) + equiv[(u8) *str++];
                        if (check[pos] == state)
                                state = next[pos];
                        else
@@ -373,7 +374,7 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
        } else {
                /* default is direct to next state */
                while (*str) {
-                       pos = base[state] + (u8) *str++;
+                       pos = base_idx(base[state]) + (u8) *str++;
                        if (check[pos] == state)
                                state = next[pos];
                        else
@@ -409,14 +410,14 @@ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
                u8 *equiv = EQUIV_TABLE(dfa);
                /* default is direct to next state */
 
-               pos = base[state] + equiv[(u8) c];
+               pos = base_idx(base[state]) + equiv[(u8) c];
                if (check[pos] == state)
                        state = next[pos];
                else
                        state = def[state];
        } else {
                /* default is direct to next state */
-               pos = base[state] + (u8) c;
+               pos = base_idx(base[state]) + (u8) c;
                if (check[pos] == state)
                        state = next[pos];
                else
index e91ffee80162832414fc3222b12624bb0abb46e6..35b394a75d762dd6a4e935f3ffe1d5b4566a2885 100644 (file)
@@ -174,7 +174,7 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer,
        if (info && error) {
                if (error == -ENOENT)
                        *info = "Failed name lookup - deleted entry";
-               else if (error == -ESTALE)
+               else if (error == -EACCES)
                        *info = "Failed name lookup - disconnected path";
                else if (error == -ENAMETOOLONG)
                        *info = "Failed name lookup - name too long";
index 813200384d97cfc7f06a76e9b2f6286be7dfa7ab..0f345c4dee5f46d7a6bb015d19105a0654a2f7d1 100644 (file)
@@ -87,7 +87,6 @@
 #include "include/policy.h"
 #include "include/policy_unpack.h"
 #include "include/resource.h"
-#include "include/sid.h"
 
 
 /* root profile namespace */
@@ -292,7 +291,6 @@ static struct aa_namespace *alloc_namespace(const char *prefix,
        if (!ns->unconfined)
                goto fail_unconfined;
 
-       ns->unconfined->sid = aa_alloc_sid();
        ns->unconfined->flags = PFLAG_UNCONFINED | PFLAG_IX_ON_NAME_ERROR |
            PFLAG_IMMUTABLE;
 
@@ -303,6 +301,8 @@ static struct aa_namespace *alloc_namespace(const char *prefix,
         */
        ns->unconfined->ns = aa_get_namespace(ns);
 
+       atomic_set(&ns->uniq_null, 0);
+
        return ns;
 
 fail_unconfined:
@@ -497,7 +497,6 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new)
        /* released when @new is freed */
        new->parent = aa_get_profile(old->parent);
        new->ns = aa_get_namespace(old->ns);
-       new->sid = old->sid;
        __list_add_profile(&policy->profiles, new);
        /* inherit children */
        list_for_each_entry_safe(child, tmp, &old->base.profiles, base.list) {
@@ -635,83 +634,6 @@ void __init aa_free_root_ns(void)
         aa_put_namespace(ns);
 }
 
-/**
- * aa_alloc_profile - allocate, initialize and return a new profile
- * @hname: name of the profile  (NOT NULL)
- *
- * Returns: refcount profile or NULL on failure
- */
-struct aa_profile *aa_alloc_profile(const char *hname)
-{
-       struct aa_profile *profile;
-
-       /* freed by free_profile - usually through aa_put_profile */
-       profile = kzalloc(sizeof(*profile), GFP_KERNEL);
-       if (!profile)
-               return NULL;
-
-       if (!policy_init(&profile->base, NULL, hname)) {
-               kzfree(profile);
-               return NULL;
-       }
-
-       /* refcount released by caller */
-       return profile;
-}
-
-/**
- * aa_new_null_profile - create a new null-X learning profile
- * @parent: profile that caused this profile to be created (NOT NULL)
- * @hat: true if the null- learning profile is a hat
- *
- * Create a null- complain mode profile used in learning mode.  The name of
- * the profile is unique and follows the format of parent//null-sid.
- *
- * null profiles are added to the profile list but the list does not
- * hold a count on them so that they are automatically released when
- * not in use.
- *
- * Returns: new refcounted profile else NULL on failure
- */
-struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
-{
-       struct aa_profile *profile = NULL;
-       char *name;
-       u32 sid = aa_alloc_sid();
-
-       /* freed below */
-       name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL);
-       if (!name)
-               goto fail;
-       sprintf(name, "%s//null-%x", parent->base.hname, sid);
-
-       profile = aa_alloc_profile(name);
-       kfree(name);
-       if (!profile)
-               goto fail;
-
-       profile->sid = sid;
-       profile->mode = APPARMOR_COMPLAIN;
-       profile->flags = PFLAG_NULL;
-       if (hat)
-               profile->flags |= PFLAG_HAT;
-
-       /* released on free_profile */
-       profile->parent = aa_get_profile(parent);
-       profile->ns = aa_get_namespace(parent->ns);
-
-       write_lock(&profile->ns->lock);
-       __list_add_profile(&parent->base.profiles, profile);
-       write_unlock(&profile->ns->lock);
-
-       /* refcount released by caller */
-       return profile;
-
-fail:
-       aa_free_sid(sid);
-       return NULL;
-}
-
 /**
  * free_profile - free a profile
  * @profile: the profile to free  (MAYBE NULL)
@@ -749,7 +671,6 @@ static void free_profile(struct aa_profile *profile)
        aa_free_cap_rules(&profile->caps);
        aa_free_rlimit_rules(&profile->rlimits);
 
-       aa_free_sid(profile->sid);
        aa_put_dfa(profile->xmatch);
        aa_put_dfa(profile->policy.dfa);
 
@@ -790,6 +711,81 @@ void aa_free_profile_kref(struct kref *kref)
        free_profile(p);
 }
 
+/**
+ * aa_alloc_profile - allocate, initialize and return a new profile
+ * @hname: name of the profile  (NOT NULL)
+ *
+ * Returns: refcount profile or NULL on failure
+ */
+struct aa_profile *aa_alloc_profile(const char *hname)
+{
+       struct aa_profile *profile;
+
+       /* freed by free_profile - usually through aa_put_profile */
+       profile = kzalloc(sizeof(*profile), GFP_KERNEL);
+       if (!profile)
+               return NULL;
+
+       if (!policy_init(&profile->base, NULL, hname)) {
+               kzfree(profile);
+               return NULL;
+       }
+
+       /* refcount released by caller */
+       return profile;
+}
+
+/**
+ * aa_new_null_profile - create a new null-X learning profile
+ * @parent: profile that caused this profile to be created (NOT NULL)
+ * @hat: true if the null- learning profile is a hat
+ *
+ * Create a null- complain mode profile used in learning mode.  The name of
+ * the profile is unique and follows the format of parent//null-<uniq>.
+ *
+ * null profiles are added to the profile list but the list does not
+ * hold a count on them so that they are automatically released when
+ * not in use.
+ *
+ * Returns: new refcounted profile else NULL on failure
+ */
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
+{
+       struct aa_profile *profile = NULL;
+       char *name;
+       int uniq = atomic_inc_return(&parent->ns->uniq_null);
+
+       /* freed below */
+       name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL);
+       if (!name)
+               goto fail;
+       sprintf(name, "%s//null-%x", parent->base.hname, uniq);
+
+       profile = aa_alloc_profile(name);
+       kfree(name);
+       if (!profile)
+               goto fail;
+
+       profile->mode = APPARMOR_COMPLAIN;
+       profile->flags = PFLAG_NULL;
+       if (hat)
+               profile->flags |= PFLAG_HAT;
+
+       /* released on free_profile */
+       profile->parent = aa_get_profile(parent);
+       profile->ns = aa_get_namespace(parent->ns);
+
+       write_lock(&profile->ns->lock);
+       __list_add_profile(&parent->base.profiles, profile);
+       write_unlock(&profile->ns->lock);
+
+       /* refcount released by caller */
+       return profile;
+
+fail:
+       return NULL;
+}
+
 /* TODO: profile accounting - setup in remove */
 
 /**
@@ -972,7 +968,6 @@ static void __add_new_profile(struct aa_namespace *ns, struct aa_policy *policy,
                profile->parent = aa_get_profile((struct aa_profile *) policy);
        __list_add_profile(&policy->profiles, profile);
        /* released on free_profile */
-       profile->sid = aa_alloc_sid();
        profile->ns = aa_get_namespace(ns);
 }
 
@@ -1110,14 +1105,8 @@ audit:
        if (!error) {
                if (rename_profile)
                        __replace_profile(rename_profile, new_profile);
-               if (old_profile) {
-                       /* when there are both rename and old profiles
-                        * inherit old profiles sid
-                        */
-                       if (rename_profile)
-                               aa_free_sid(new_profile->sid);
+               if (old_profile)
                        __replace_profile(old_profile, new_profile);
-               }
                if (!(old_profile || rename_profile))
                        __add_new_profile(ns, policy, new_profile);
        }
@@ -1167,14 +1156,12 @@ ssize_t aa_remove_profiles(char *fqname, size_t size)
        if (fqname[0] == ':') {
                char *ns_name;
                name = aa_split_fqname(fqname, &ns_name);
-               if (ns_name) {
-                       /* released below */
-                       ns = aa_find_namespace(root, ns_name);
-                       if (!ns) {
-                               info = "namespace does not exist";
-                               error = -ENOENT;
-                               goto fail;
-                       }
+               /* released below */
+               ns = aa_find_namespace(root, ns_name);
+               if (!ns) {
+                       info = "namespace does not exist";
+                       error = -ENOENT;
+                       goto fail;
                }
        } else
                /* released below */
index 329b1fd30749791083d5cbb9e0cb639f87c87367..6dac7d77cb4d53c1241402d7a267466c31dbb613 100644 (file)
@@ -27,7 +27,6 @@
 #include "include/match.h"
 #include "include/policy.h"
 #include "include/policy_unpack.h"
-#include "include/sid.h"
 
 /*
  * The AppArmor interface treats data as a type byte followed by the
@@ -290,6 +289,9 @@ static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
        return res;
 }
 
+#define DFA_VALID_PERM_MASK            0xffffffff
+#define DFA_VALID_PERM2_MASK           0xffffffff
+
 /**
  * verify_accept - verify the accept tables of a dfa
  * @dfa: dfa to verify accept tables of (NOT NULL)
index 1b41c542d376721646ba67dc4f17a3e21e1f241f..6c9390179b8909882e8a86e91e4f61349d79dd09 100644 (file)
@@ -163,9 +163,3 @@ int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)
        name = aa_split_fqname(fqname, &ns_name);
        return aa_change_profile(ns_name, name, onexec, test);
 }
-
-int aa_setprocattr_permipc(char *fqname)
-{
-       /* TODO: add ipc permission querying */
-       return -ENOTSUPP;
-}
index e1f3d7ef2c54f75861d5bc85990f647cf7524b58..748bf0ca6c9f74572c601ebdaf033c6da224a20e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/audit.h>
 
 #include "include/audit.h"
+#include "include/context.h"
 #include "include/resource.h"
 #include "include/policy.h"
 
@@ -90,17 +91,25 @@ int aa_map_resource(int resource)
 int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task,
                      unsigned int resource, struct rlimit *new_rlim)
 {
+       struct aa_profile *task_profile;
        int error = 0;
 
+       rcu_read_lock();
+       task_profile = aa_get_profile(aa_cred_profile(__task_cred(task)));
+       rcu_read_unlock();
+
        /* TODO: extend resource control to handle other (non current)
-        * processes.  AppArmor rules currently have the implicit assumption
-        * that the task is setting the resource of the current process
+        * profiles.  AppArmor rules currently have the implicit assumption
+        * that the task is setting the resource of a task confined with
+        * the same profile.
         */
-       if ((task != current->group_leader) ||
+       if (profile != task_profile ||
            (profile->rlimits.mask & (1 << resource) &&
             new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max))
                error = -EACCES;
 
+       aa_put_profile(task_profile);
+
        return audit_resource(profile, resource, new_rlim->rlim_max, error);
 }
 
index dd0dc574d78dd0774fd0e183f62ac677caa091e0..e8aad69f0d696c70b21dc8af16b0d28d990b3eda 100644 (file)
@@ -49,8 +49,6 @@ struct dev_cgroup {
        struct cgroup_subsys_state css;
        struct list_head exceptions;
        enum devcg_behavior behavior;
-       /* temporary list for pending propagation operations */
-       struct list_head propagate_pending;
 };
 
 static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
@@ -241,7 +239,6 @@ static struct cgroup_subsys_state *devcgroup_css_alloc(struct cgroup *cgroup)
        if (!dev_cgroup)
                return ERR_PTR(-ENOMEM);
        INIT_LIST_HEAD(&dev_cgroup->exceptions);
-       INIT_LIST_HEAD(&dev_cgroup->propagate_pending);
        dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
 
        return &dev_cgroup->css;
@@ -444,34 +441,6 @@ static void revalidate_active_exceptions(struct dev_cgroup *devcg)
        }
 }
 
-/**
- * get_online_devcg - walks the cgroup tree and fills a list with the online
- *                   groups
- * @root: cgroup used as starting point
- * @online: list that will be filled with online groups
- *
- * Must be called with devcgroup_mutex held. Grabs RCU lock.
- * Because devcgroup_mutex is held, no devcg will become online or offline
- * during the tree walk (see devcgroup_online, devcgroup_offline)
- * A separated list is needed because propagate_behavior() and
- * propagate_exception() need to allocate memory and can block.
- */
-static void get_online_devcg(struct cgroup *root, struct list_head *online)
-{
-       struct cgroup *pos;
-       struct dev_cgroup *devcg;
-
-       lockdep_assert_held(&devcgroup_mutex);
-
-       rcu_read_lock();
-       cgroup_for_each_descendant_pre(pos, root) {
-               devcg = cgroup_to_devcgroup(pos);
-               if (is_devcg_online(devcg))
-                       list_add_tail(&devcg->propagate_pending, online);
-       }
-       rcu_read_unlock();
-}
-
 /**
  * propagate_exception - propagates a new exception to the children
  * @devcg_root: device cgroup that added a new exception
@@ -482,15 +451,24 @@ static void get_online_devcg(struct cgroup *root, struct list_head *online)
 static int propagate_exception(struct dev_cgroup *devcg_root,
                               struct dev_exception_item *ex)
 {
-       struct cgroup *root = devcg_root->css.cgroup;
-       struct dev_cgroup *devcg, *parent, *tmp;
+       struct cgroup *root = devcg_root->css.cgroup, *pos;
        int rc = 0;
-       LIST_HEAD(pending);
 
-       get_online_devcg(root, &pending);
+       rcu_read_lock();
 
-       list_for_each_entry_safe(devcg, tmp, &pending, propagate_pending) {
-               parent = cgroup_to_devcgroup(devcg->css.cgroup->parent);
+       cgroup_for_each_descendant_pre(pos, root) {
+               struct dev_cgroup *devcg = cgroup_to_devcgroup(pos);
+
+               /*
+                * Because devcgroup_mutex is held, no devcg will become
+                * online or offline during the tree walk (see on/offline
+                * methods), and online ones are safe to access outside RCU
+                * read lock without bumping refcnt.
+                */
+               if (!is_devcg_online(devcg))
+                       continue;
+
+               rcu_read_unlock();
 
                /*
                 * in case both root's behavior and devcg is allow, a new
@@ -512,8 +490,10 @@ static int propagate_exception(struct dev_cgroup *devcg_root,
                }
                revalidate_active_exceptions(devcg);
 
-               list_del_init(&devcg->propagate_pending);
+               rcu_read_lock();
        }
+
+       rcu_read_unlock();
        return rc;
 }
 
index 4bb3a775a996041c02fe6db7373e340e73a5f7ac..245c6d92065b36ae748c6936d696d4a2222d9b9d 100644 (file)
@@ -17,6 +17,21 @@ config INTEGRITY_SIGNATURE
          This is useful for evm and module keyrings, when keys are
          usually only added from initramfs.
 
+config INTEGRITY_AUDIT
+       bool "Enables integrity auditing support "
+       depends on INTEGRITY && AUDIT
+       default y
+       help
+         In addition to enabling integrity auditing support, this
+         option adds a kernel parameter 'integrity_audit', which
+         controls the level of integrity auditing messages.
+         0 - basic integrity auditing messages (default)
+         1 - additional integrity auditing messages
+
+         Additional informational integrity auditing messages would
+         be enabled by specifying 'integrity_audit=1' on the kernel
+         command line.
+
 config INTEGRITY_ASYMMETRIC_KEYS
        boolean "Enable asymmetric keys support"
        depends on INTEGRITY_SIGNATURE
index ebb6409b3fcb97caeb15d211e1427a1148050f60..0f9cffb1f9ade08400a916d7a5e3694679266e49 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_INTEGRITY) += integrity.o
+obj-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
 obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
 obj-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
 
index cdbde1762189f56ebdcd133e3cf6fdfba37b3933..df0fa451a8718312ba319d4d27f2edfdf7a3b8e4 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/module.h>
 #include <linux/crypto.h>
+#include <linux/audit.h>
 #include <linux/xattr.h>
 #include <linux/integrity.h>
 #include <linux/evm.h>
@@ -24,6 +25,9 @@
 
 int evm_initialized;
 
+static char *integrity_status_msg[] = {
+       "pass", "fail", "no_label", "no_xattrs", "unknown"
+};
 char *evm_hmac = "hmac(sha1)";
 char *evm_hash = "sha1";
 int evm_hmac_version = CONFIG_EVM_HMAC_VERSION;
@@ -262,9 +266,15 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
                if ((evm_status == INTEGRITY_PASS) ||
                    (evm_status == INTEGRITY_NOXATTRS))
                        return 0;
-               return -EPERM;
+               goto out;
        }
        evm_status = evm_verify_current_integrity(dentry);
+out:
+       if (evm_status != INTEGRITY_PASS)
+               integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
+                                   dentry->d_name.name, "appraise_metadata",
+                                   integrity_status_msg[evm_status],
+                                   -EPERM, 0);
        return evm_status == INTEGRITY_PASS ? 0 : -EPERM;
 }
 
@@ -357,6 +367,9 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
        if ((evm_status == INTEGRITY_PASS) ||
            (evm_status == INTEGRITY_NOXATTRS))
                return 0;
+       integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
+                           dentry->d_name.name, "appraise_metadata",
+                           integrity_status_msg[evm_status], -EPERM, 0);
        return -EPERM;
 }
 
index d232c73647ae46ee0f8295a4965419f5b044ca99..39196abaff0d69d7d600ecd53847ba62b8cebed1 100644 (file)
@@ -38,18 +38,6 @@ config IMA_MEASURE_PCR_IDX
          that IMA uses to maintain the integrity aggregate of the
          measurement list.  If unsure, use the default 10.
 
-config IMA_AUDIT
-       bool "Enables auditing support"
-       depends on IMA
-       depends on AUDIT
-       default y
-       help
-         This option adds a kernel parameter 'ima_audit', which
-         allows informational auditing messages to be enabled
-         at boot.  If this option is selected, informational integrity
-         auditing messages can be enabled with 'ima_audit=1' on
-         the kernel command line.
-
 config IMA_LSM_RULES
        bool
        depends on IMA && AUDIT && (SECURITY_SELINUX || SECURITY_SMACK)
index 3f2ca6bdc384ecbb5b3de4dc53d32c9a802d5958..56dfee7cbf61c6605adf103dbf91393b33fe9256 100644 (file)
@@ -7,5 +7,4 @@ obj-$(CONFIG_IMA) += ima.o
 
 ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
         ima_policy.o
-ima-$(CONFIG_IMA_AUDIT) += ima_audit.o
 ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
index a41c9c18e5e0706498d44a26e3ece7d49f307e4c..b3dd616560f72054e13ddeaedaa39017585c2e5c 100644 (file)
@@ -62,20 +62,6 @@ struct ima_queue_entry {
 };
 extern struct list_head ima_measurements;      /* list of all measurements */
 
-#ifdef CONFIG_IMA_AUDIT
-/* declarations */
-void integrity_audit_msg(int audit_msgno, struct inode *inode,
-                        const unsigned char *fname, const char *op,
-                        const char *cause, int result, int info);
-#else
-static inline void integrity_audit_msg(int audit_msgno, struct inode *inode,
-                                      const unsigned char *fname,
-                                      const char *op, const char *cause,
-                                      int result, int info)
-{
-}
-#endif
-
 /* Internal IMA function definitions */
 int ima_init(void);
 void ima_cleanup(void);
index 6c491a63128efe7327e33e34b266a64dfc6e6385..e9508d5bbfcff7ee087d069697c6088da7da0210 100644 (file)
@@ -57,7 +57,7 @@ __setup("ima_hash=", hash_setup);
 static void ima_rdwr_violation_check(struct file *file)
 {
        struct dentry *dentry = file->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file_inode(file);
        fmode_t mode = file->f_mode;
        int must_measure;
        bool send_tomtou = false, send_writers = false;
index 84c37c4db914ac46cd07adae4ee4040fe9446390..c42fb7a70dee78dfdf1ebbc5f1d3a43fb6c6c233 100644 (file)
@@ -113,5 +113,19 @@ static inline int asymmetric_verify(struct key *keyring, const char *sig,
 }
 #endif
 
+#ifdef CONFIG_INTEGRITY_AUDIT
+/* declarations */
+void integrity_audit_msg(int audit_msgno, struct inode *inode,
+                        const unsigned char *fname, const char *op,
+                        const char *cause, int result, int info);
+#else
+static inline void integrity_audit_msg(int audit_msgno, struct inode *inode,
+                                      const unsigned char *fname,
+                                      const char *op, const char *cause,
+                                      int result, int info)
+{
+}
+#endif
+
 /* set during initialization */
 extern int iint_initialized;
similarity index 85%
rename from security/integrity/ima/ima_audit.c
rename to security/integrity/integrity_audit.c
index c586faae8fd6c7901baf6b37b3db0500157f8644..d7efb30404aaed01d860a5bf274477ce56e2e481 100644 (file)
 #include <linux/fs.h>
 #include <linux/gfp.h>
 #include <linux/audit.h>
-#include "ima.h"
+#include "integrity.h"
 
-static int ima_audit;
+static int integrity_audit_info;
 
 /* ima_audit_setup - enable informational auditing messages */
-static int __init ima_audit_setup(char *str)
+static int __init integrity_audit_setup(char *str)
 {
        unsigned long audit;
 
        if (!strict_strtoul(str, 0, &audit))
-               ima_audit = audit ? 1 : 0;
+               integrity_audit_info = audit ? 1 : 0;
        return 1;
 }
-__setup("ima_audit=", ima_audit_setup);
+__setup("integrity_audit=", integrity_audit_setup);
 
 void integrity_audit_msg(int audit_msgno, struct inode *inode,
                         const unsigned char *fname, const char *op,
@@ -34,7 +34,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
 {
        struct audit_buffer *ab;
 
-       if (!ima_audit && audit_info == 1) /* Skip informational messages */
+       if (!integrity_audit_info && audit_info == 1)   /* Skip info messages */
                return;
 
        ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno);
index 5c6f2cd2d095ee8b2a4e828123c00f7966639b6a..db1fca990a2468a4ac292f50daba582df4dc113e 100644 (file)
@@ -1547,6 +1547,18 @@ static inline int path_has_perm(const struct cred *cred,
        return inode_has_perm(cred, inode, av, &ad, 0);
 }
 
+/* Same as path_has_perm, but uses the inode from the file struct. */
+static inline int file_path_has_perm(const struct cred *cred,
+                                    struct file *file,
+                                    u32 av)
+{
+       struct common_audit_data ad;
+
+       ad.type = LSM_AUDIT_DATA_PATH;
+       ad.u.path = file->f_path;
+       return inode_has_perm(cred, file_inode(file), av, &ad, 0);
+}
+
 /* Check whether a task can use an open file descriptor to
    access an inode in a given way.  Check access to the
    descriptor itself, and then use dentry_has_perm to
@@ -2141,14 +2153,14 @@ static inline void flush_unauthorized_files(const struct cred *cred,
                        struct tty_file_private *file_priv;
 
                        /* Revalidate access to controlling tty.
-                          Use path_has_perm on the tty path directly rather
-                          than using file_has_perm, as this particular open
-                          file may belong to another process and we are only
-                          interested in the inode-based check here. */
+                          Use file_path_has_perm on the tty path directly
+                          rather than using file_has_perm, as this particular
+                          open file may belong to another process and we are
+                          only interested in the inode-based check here. */
                        file_priv = list_first_entry(&tty->tty_files,
                                                struct tty_file_private, list);
                        file = file_priv->file;
-                       if (path_has_perm(cred, &file->f_path, FILE__READ | FILE__WRITE))
+                       if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE))
                                drop_tty = 1;
                }
                spin_unlock(&tty_files_lock);
@@ -3259,7 +3271,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)
         * new inode label or new policy.
         * This check is not redundant - do not remove.
         */
-       return path_has_perm(cred, &file->f_path, open_file_to_av(file));
+       return file_path_has_perm(cred, file, open_file_to_av(file));
 }
 
 /* task security operations */
index 8ad30955e15d85287a3822ac16ed819b5772da11..339614c76e636f2a6d2ae9a88023502421a936a9 100644 (file)
 #define SMK_LABELLEN   24
 #define SMK_LONGLABEL  256
 
+/*
+ * This is the repository for labels seen so that it is
+ * not necessary to keep allocating tiny chuncks of memory
+ * and so that they can be shared.
+ *
+ * Labels are never modified in place. Anytime a label
+ * is imported (e.g. xattrset on a file) the list is checked
+ * for it and it is added if it doesn't exist. The address
+ * is passed out in either case. Entries are added, but
+ * never deleted.
+ *
+ * Since labels are hanging around anyway it doesn't
+ * hurt to maintain a secid for those awkward situations
+ * where kernel components that ought to use LSM independent
+ * interfaces don't. The secid should go away when all of
+ * these components have been repaired.
+ *
+ * The cipso value associated with the label gets stored here, too.
+ *
+ * Keep the access rules for this subject label here so that
+ * the entire set of rules does not need to be examined every
+ * time.
+ */
+struct smack_known {
+       struct list_head                list;
+       char                            *smk_known;
+       u32                             smk_secid;
+       struct netlbl_lsm_secattr       smk_netlabel;   /* on wire labels */
+       struct list_head                smk_rules;      /* access rules */
+       struct mutex                    smk_rules_lock; /* lock for rules */
+};
+
 /*
  * Maximum number of bytes for the levels in a CIPSO IP option.
  * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
@@ -46,25 +78,25 @@ struct superblock_smack {
 };
 
 struct socket_smack {
-       char            *smk_out;       /* outbound label */
-       char            *smk_in;        /* inbound label */
-       char            *smk_packet;    /* TCP peer label */
+       struct smack_known      *smk_out;       /* outbound label */
+       char                    *smk_in;        /* inbound label */
+       char                    *smk_packet;    /* TCP peer label */
 };
 
 /*
  * Inode smack data
  */
 struct inode_smack {
-       char            *smk_inode;     /* label of the fso */
-       char            *smk_task;      /* label of the task */
-       char            *smk_mmap;      /* label of the mmap domain */
-       struct mutex    smk_lock;       /* initialization lock */
-       int             smk_flags;      /* smack inode flags */
+       char                    *smk_inode;     /* label of the fso */
+       struct smack_known      *smk_task;      /* label of the task */
+       struct smack_known      *smk_mmap;      /* label of the mmap domain */
+       struct mutex            smk_lock;       /* initialization lock */
+       int                     smk_flags;      /* smack inode flags */
 };
 
 struct task_smack {
-       char                    *smk_task;      /* label for access control */
-       char                    *smk_forked;    /* label when forked */
+       struct smack_known      *smk_task;      /* label for access control */
+       struct smack_known      *smk_forked;    /* label when forked */
        struct list_head        smk_rules;      /* per task access rules */
        struct mutex            smk_rules_lock; /* lock for the rules */
 };
@@ -78,7 +110,7 @@ struct task_smack {
  */
 struct smack_rule {
        struct list_head        list;
-       char                    *smk_subject;
+       struct smack_known      *smk_subject;
        char                    *smk_object;
        int                     smk_access;
 };
@@ -94,35 +126,14 @@ struct smk_netlbladdr {
 };
 
 /*
- * This is the repository for labels seen so that it is
- * not necessary to keep allocating tiny chuncks of memory
- * and so that they can be shared.
- *
- * Labels are never modified in place. Anytime a label
- * is imported (e.g. xattrset on a file) the list is checked
- * for it and it is added if it doesn't exist. The address
- * is passed out in either case. Entries are added, but
- * never deleted.
- *
- * Since labels are hanging around anyway it doesn't
- * hurt to maintain a secid for those awkward situations
- * where kernel components that ought to use LSM independent
- * interfaces don't. The secid should go away when all of
- * these components have been repaired.
- *
- * The cipso value associated with the label gets stored here, too.
- *
- * Keep the access rules for this subject label here so that
- * the entire set of rules does not need to be examined every
- * time.
+ * An entry in the table identifying ports.
  */
-struct smack_known {
-       struct list_head                list;
-       char                            *smk_known;
-       u32                             smk_secid;
-       struct netlbl_lsm_secattr       smk_netlabel;   /* on wire labels */
-       struct list_head                smk_rules;      /* access rules */
-       struct mutex                    smk_rules_lock; /* lock for rules */
+struct smk_port_label {
+       struct list_head        list;
+       struct sock             *smk_sock;      /* socket initialized on */
+       unsigned short          smk_port;       /* the port number */
+       char                    *smk_in;        /* incoming label */
+       struct smack_known      *smk_out;       /* outgoing label */
 };
 
 /*
@@ -132,6 +143,7 @@ struct smack_known {
 #define SMK_FSFLOOR    "smackfsfloor="
 #define SMK_FSHAT      "smackfshat="
 #define SMK_FSROOT     "smackfsroot="
+#define SMK_FSTRANS    "smackfstransmute="
 
 #define SMACK_CIPSO_OPTION     "-CIPSO"
 
@@ -203,9 +215,9 @@ struct inode_smack *new_inode_smack(char *);
  * These functions are in smack_access.c
  */
 int smk_access_entry(char *, char *, struct list_head *);
-int smk_access(char *, char *, int, struct smk_audit_info *);
+int smk_access(struct smack_known *, char *, int, struct smk_audit_info *);
 int smk_curacc(char *, u32, struct smk_audit_info *);
-char *smack_from_secid(const u32);
+struct smack_known *smack_from_secid(const u32);
 char *smk_parse_smack(const char *string, int len);
 int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
 char *smk_import(const char *, int);
@@ -218,7 +230,7 @@ u32 smack_to_secid(const char *);
  */
 extern int smack_cipso_direct;
 extern int smack_cipso_mapped;
-extern char *smack_net_ambient;
+extern struct smack_known *smack_net_ambient;
 extern char *smack_onlycap;
 extern const char *smack_cipso_option;
 
@@ -254,17 +266,17 @@ static inline char *smk_of_inode(const struct inode *isp)
 }
 
 /*
- * Present a pointer to the smack label in an task blob.
+ * Present a pointer to the smack label entry in an task blob.
  */
-static inline char *smk_of_task(const struct task_smack *tsp)
+static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
 {
        return tsp->smk_task;
 }
 
 /*
- * Present a pointer to the forked smack label in an task blob.
+ * Present a pointer to the forked smack label entry in an task blob.
  */
-static inline char *smk_of_forked(const struct task_smack *tsp)
+static inline struct smack_known *smk_of_forked(const struct task_smack *tsp)
 {
        return tsp->smk_forked;
 }
@@ -272,7 +284,7 @@ static inline char *smk_of_forked(const struct task_smack *tsp)
 /*
  * Present a pointer to the smack label in the current task blob.
  */
-static inline char *smk_of_current(void)
+static inline struct smack_known *smk_of_current(void)
 {
        return smk_of_task(current_security());
 }
@@ -283,9 +295,11 @@ static inline char *smk_of_current(void)
  */
 static inline int smack_privileged(int cap)
 {
+       struct smack_known *skp = smk_of_current();
+
        if (!capable(cap))
                return 0;
-       if (smack_onlycap == NULL || smack_onlycap == smk_of_current())
+       if (smack_onlycap == NULL || smack_onlycap == skp->smk_known)
                return 1;
        return 0;
 }
index 2e397a88d410f8b4d94118f605566d526812259e..6a0377f38620acd318444a399c2fc4ef8227c3db 100644 (file)
@@ -93,7 +93,7 @@ int smk_access_entry(char *subject_label, char *object_label,
 
        list_for_each_entry_rcu(srp, rule_list, list) {
                if (srp->smk_object == object_label &&
-                   srp->smk_subject == subject_label) {
+                   srp->smk_subject->smk_known == subject_label) {
                        may = srp->smk_access;
                        break;
                }
@@ -104,7 +104,7 @@ int smk_access_entry(char *subject_label, char *object_label,
 
 /**
  * smk_access - determine if a subject has a specific access to an object
- * @subject_label: a pointer to the subject's Smack label
+ * @subject_known: a pointer to the subject's Smack label entry
  * @object_label: a pointer to the object's Smack label
  * @request: the access requested, in "MAY" format
  * @a : a pointer to the audit data
@@ -115,10 +115,9 @@ int smk_access_entry(char *subject_label, char *object_label,
  *
  * Smack labels are shared on smack_list
  */
-int smk_access(char *subject_label, char *object_label, int request,
-              struct smk_audit_info *a)
+int smk_access(struct smack_known *subject_known, char *object_label,
+               int request, struct smk_audit_info *a)
 {
-       struct smack_known *skp;
        int may = MAY_NOT;
        int rc = 0;
 
@@ -127,7 +126,7 @@ int smk_access(char *subject_label, char *object_label, int request,
         *
         * A star subject can't access any object.
         */
-       if (subject_label == smack_known_star.smk_known) {
+       if (subject_known == &smack_known_star) {
                rc = -EACCES;
                goto out_audit;
        }
@@ -137,7 +136,7 @@ int smk_access(char *subject_label, char *object_label, int request,
         * An internet subject can access any object.
         */
        if (object_label == smack_known_web.smk_known ||
-           subject_label == smack_known_web.smk_known)
+           subject_known == &smack_known_web)
                goto out_audit;
        /*
         * A star object can be accessed by any subject.
@@ -148,7 +147,7 @@ int smk_access(char *subject_label, char *object_label, int request,
         * An object can be accessed in any way by a subject
         * with the same label.
         */
-       if (subject_label == object_label)
+       if (subject_known->smk_known == object_label)
                goto out_audit;
        /*
         * A hat subject can read any object.
@@ -157,7 +156,7 @@ int smk_access(char *subject_label, char *object_label, int request,
        if ((request & MAY_ANYREAD) == request) {
                if (object_label == smack_known_floor.smk_known)
                        goto out_audit;
-               if (subject_label == smack_known_hat.smk_known)
+               if (subject_known == &smack_known_hat)
                        goto out_audit;
        }
        /*
@@ -167,9 +166,9 @@ int smk_access(char *subject_label, char *object_label, int request,
         * good. A negative response from smk_access_entry()
         * indicates there is no entry for this pair.
         */
-       skp = smk_find_entry(subject_label);
        rcu_read_lock();
-       may = smk_access_entry(subject_label, object_label, &skp->smk_rules);
+       may = smk_access_entry(subject_known->smk_known, object_label,
+                               &subject_known->smk_rules);
        rcu_read_unlock();
 
        if (may > 0 && (request & may) == request)
@@ -179,7 +178,8 @@ int smk_access(char *subject_label, char *object_label, int request,
 out_audit:
 #ifdef CONFIG_AUDIT
        if (a)
-               smack_log(subject_label, object_label, request, rc, a);
+               smack_log(subject_known->smk_known, object_label, request,
+                               rc, a);
 #endif
        return rc;
 }
@@ -198,20 +198,21 @@ out_audit:
 int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
 {
        struct task_smack *tsp = current_security();
-       char *sp = smk_of_task(tsp);
+       struct smack_known *skp = smk_of_task(tsp);
        int may;
        int rc;
 
        /*
         * Check the global rule list
         */
-       rc = smk_access(sp, obj_label, mode, NULL);
+       rc = smk_access(skp, obj_label, mode, NULL);
        if (rc == 0) {
                /*
                 * If there is an entry in the task's rule list
                 * it can further restrict access.
                 */
-               may = smk_access_entry(sp, obj_label, &tsp->smk_rules);
+               may = smk_access_entry(skp->smk_known, obj_label,
+                                       &tsp->smk_rules);
                if (may < 0)
                        goto out_audit;
                if ((mode & may) == mode)
@@ -228,7 +229,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
 out_audit:
 #ifdef CONFIG_AUDIT
        if (a)
-               smack_log(sp, obj_label, mode, rc, a);
+               smack_log(skp->smk_known, obj_label, mode, rc, a);
 #endif
        return rc;
 }
@@ -402,6 +403,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
        sap->flags |= NETLBL_SECATTR_MLS_CAT;
        sap->attr.mls.lvl = level;
        sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
+       if (!sap->attr.mls.cat)
+               return -ENOMEM;
        sap->attr.mls.cat->startbit = 0;
 
        for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
@@ -513,10 +516,10 @@ char *smk_import(const char *string, int len)
  * smack_from_secid - find the Smack label associated with a secid
  * @secid: an integer that might be associated with a Smack label
  *
- * Returns a pointer to the appropriate Smack label if there is one,
+ * Returns a pointer to the appropriate Smack label entry if there is one,
  * otherwise a pointer to the invalid Smack label.
  */
-char *smack_from_secid(const u32 secid)
+struct smack_known *smack_from_secid(const u32 secid)
 {
        struct smack_known *skp;
 
@@ -524,7 +527,7 @@ char *smack_from_secid(const u32 secid)
        list_for_each_entry_rcu(skp, &smack_known_list, list) {
                if (skp->smk_secid == secid) {
                        rcu_read_unlock();
-                       return skp->smk_known;
+                       return skp;
                }
        }
 
@@ -533,7 +536,7 @@ char *smack_from_secid(const u32 secid)
         * of a secid that is not on the list.
         */
        rcu_read_unlock();
-       return smack_known_invalid.smk_known;
+       return &smack_known_invalid;
 }
 
 /**
index d52c780bdb788add9fa45684f1ae72a63d91663f..6a083303501dd8cf702c26ea0af8df72e7b89650 100644 (file)
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
+#include <linux/dccp.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/pipe_fs_i.h>
 #include <net/cipso_ipv4.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
 #include <linux/audit.h>
 #include <linux/magic.h>
 #include <linux/dcache.h>
 #define TRANS_TRUE     "TRUE"
 #define TRANS_TRUE_SIZE        4
 
+#define SMK_CONNECTING 0
+#define SMK_RECEIVING  1
+#define SMK_SENDING    2
+
+LIST_HEAD(smk_ipv6_port_list);
+
 /**
  * smk_fetch - Fetch the smack label from a file.
  * @ip: a pointer to the inode
  * Returns a pointer to the master list entry for the Smack label
  * or NULL if there was no label to fetch.
  */
-static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)
+static struct smack_known *smk_fetch(const char *name, struct inode *ip,
+                                       struct dentry *dp)
 {
        int rc;
        char *buffer;
-       char *result = NULL;
+       struct smack_known *skp = NULL;
 
        if (ip->i_op->getxattr == NULL)
                return NULL;
@@ -68,11 +78,11 @@ static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)
 
        rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL);
        if (rc > 0)
-               result = smk_import(buffer, rc);
+               skp = smk_import_entry(buffer, rc);
 
        kfree(buffer);
 
-       return result;
+       return skp;
 }
 
 /**
@@ -102,7 +112,8 @@ struct inode_smack *new_inode_smack(char *smack)
  *
  * Returns the new blob or NULL if there's no memory available
  */
-static struct task_smack *new_task_smack(char *task, char *forked, gfp_t gfp)
+static struct task_smack *new_task_smack(struct smack_known *task,
+                                       struct smack_known *forked, gfp_t gfp)
 {
        struct task_smack *tsp;
 
@@ -164,17 +175,17 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
 {
        int rc;
        struct smk_audit_info ad;
-       char *tsp;
+       struct smack_known *skp;
 
        rc = cap_ptrace_access_check(ctp, mode);
        if (rc != 0)
                return rc;
 
-       tsp = smk_of_task(task_security(ctp));
+       skp = smk_of_task(task_security(ctp));
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, ctp);
 
-       rc = smk_curacc(tsp, MAY_READWRITE, &ad);
+       rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad);
        return rc;
 }
 
@@ -190,17 +201,17 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
 {
        int rc;
        struct smk_audit_info ad;
-       char *tsp;
+       struct smack_known *skp;
 
        rc = cap_ptrace_traceme(ptp);
        if (rc != 0)
                return rc;
 
-       tsp = smk_of_task(task_security(ptp));
+       skp = smk_of_task(task_security(ptp));
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, ptp);
 
-       rc = smk_curacc(tsp, MAY_READWRITE, &ad);
+       rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad);
        return rc;
 }
 
@@ -215,12 +226,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
 static int smack_syslog(int typefrom_file)
 {
        int rc = 0;
-       char *sp = smk_of_current();
+       struct smack_known *skp = smk_of_current();
 
        if (smack_privileged(CAP_MAC_OVERRIDE))
                return 0;
 
-        if (sp != smack_known_floor.smk_known)
+        if (skp != &smack_known_floor)
                rc = -EACCES;
 
        return rc;
@@ -250,8 +261,9 @@ static int smack_sb_alloc_security(struct super_block *sb)
        sbsp->smk_default = smack_known_floor.smk_known;
        sbsp->smk_floor = smack_known_floor.smk_known;
        sbsp->smk_hat = smack_known_hat.smk_known;
-       sbsp->smk_initialized = 0;
-
+       /*
+        * smk_initialized will be zero from kzalloc.
+        */
        sb->s_security = sbsp;
 
        return 0;
@@ -295,6 +307,8 @@ static int smack_sb_copy_data(char *orig, char *smackopts)
                        dp = smackopts;
                else if (strstr(cp, SMK_FSROOT) == cp)
                        dp = smackopts;
+               else if (strstr(cp, SMK_FSTRANS) == cp)
+                       dp = smackopts;
                else
                        dp = otheropts;
 
@@ -330,8 +344,9 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
        char *op;
        char *commap;
        char *nsp;
+       int transmute = 0;
 
-       if (sp->smk_initialized != 0)
+       if (sp->smk_initialized)
                return 0;
 
        sp->smk_initialized = 1;
@@ -362,6 +377,13 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
                        nsp = smk_import(op, 0);
                        if (nsp != NULL)
                                sp->smk_root = nsp;
+               } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
+                       op += strlen(SMK_FSTRANS);
+                       nsp = smk_import(op, 0);
+                       if (nsp != NULL) {
+                               sp->smk_root = nsp;
+                               transmute = 1;
+                       }
                }
        }
 
@@ -369,11 +391,15 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
         * Initialize the root inode.
         */
        isp = inode->i_security;
-       if (isp == NULL)
+       if (inode->i_security == NULL) {
                inode->i_security = new_inode_smack(sp->smk_root);
-       else
+               isp = inode->i_security;
+       } else
                isp->smk_inode = sp->smk_root;
 
+       if (transmute)
+               isp->smk_flags |= SMK_INODE_TRANSMUTE;
+
        return 0;
 }
 
@@ -524,7 +550,9 @@ static int smack_bprm_secureexec(struct linux_binprm *bprm)
  */
 static int smack_inode_alloc_security(struct inode *inode)
 {
-       inode->i_security = new_inode_smack(smk_of_current());
+       struct smack_known *skp = smk_of_current();
+
+       inode->i_security = new_inode_smack(skp->smk_known);
        if (inode->i_security == NULL)
                return -ENOMEM;
        return 0;
@@ -557,9 +585,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
                                     const struct qstr *qstr, char **name,
                                     void **value, size_t *len)
 {
-       struct smack_known *skp;
        struct inode_smack *issp = inode->i_security;
-       char *csp = smk_of_current();
+       struct smack_known *skp = smk_of_current();
        char *isp = smk_of_inode(inode);
        char *dsp = smk_of_inode(dir);
        int may;
@@ -571,9 +598,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
        }
 
        if (value) {
-               skp = smk_find_entry(csp);
                rcu_read_lock();
-               may = smk_access_entry(csp, dsp, &skp->smk_rules);
+               may = smk_access_entry(skp->smk_known, dsp, &skp->smk_rules);
                rcu_read_unlock();
 
                /*
@@ -862,29 +888,31 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
 static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
                                      const void *value, size_t size, int flags)
 {
-       char *nsp;
+       struct smack_known *skp;
        struct inode_smack *isp = dentry->d_inode->i_security;
 
+       if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
+               isp->smk_flags |= SMK_INODE_TRANSMUTE;
+               return;
+       }
+
+       skp = smk_import_entry(value, size);
        if (strcmp(name, XATTR_NAME_SMACK) == 0) {
-               nsp = smk_import(value, size);
-               if (nsp != NULL)
-                       isp->smk_inode = nsp;
+               if (skp != NULL)
+                       isp->smk_inode = skp->smk_known;
                else
                        isp->smk_inode = smack_known_invalid.smk_known;
        } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
-               nsp = smk_import(value, size);
-               if (nsp != NULL)
-                       isp->smk_task = nsp;
+               if (skp != NULL)
+                       isp->smk_task = skp;
                else
-                       isp->smk_task = smack_known_invalid.smk_known;
+                       isp->smk_task = &smack_known_invalid;
        } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
-               nsp = smk_import(value, size);
-               if (nsp != NULL)
-                       isp->smk_mmap = nsp;
+               if (skp != NULL)
+                       isp->smk_mmap = skp;
                else
-                       isp->smk_mmap = smack_known_invalid.smk_known;
-       } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0)
-               isp->smk_flags |= SMK_INODE_TRANSMUTE;
+                       isp->smk_mmap = &smack_known_invalid;
+       }
 
        return;
 }
@@ -990,7 +1018,7 @@ static int smack_inode_getsecurity(const struct inode *inode,
        if (strcmp(name, XATTR_SMACK_IPIN) == 0)
                isp = ssp->smk_in;
        else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
-               isp = ssp->smk_out;
+               isp = ssp->smk_out->smk_known;
        else
                return -EOPNOTSUPP;
 
@@ -1070,7 +1098,9 @@ static int smack_file_permission(struct file *file, int mask)
  */
 static int smack_file_alloc_security(struct file *file)
 {
-       file->f_security = smk_of_current();
+       struct smack_known *skp = smk_of_current();
+
+       file->f_security = skp->smk_known;
        return 0;
 }
 
@@ -1181,10 +1211,9 @@ static int smack_mmap_file(struct file *file,
                           unsigned long flags)
 {
        struct smack_known *skp;
+       struct smack_known *mkp;
        struct smack_rule *srp;
        struct task_smack *tsp;
-       char *sp;
-       char *msmack;
        char *osmack;
        struct inode_smack *isp;
        int may;
@@ -1198,11 +1227,10 @@ static int smack_mmap_file(struct file *file,
        isp = file_inode(file)->i_security;
        if (isp->smk_mmap == NULL)
                return 0;
-       msmack = isp->smk_mmap;
+       mkp = isp->smk_mmap;
 
        tsp = current_security();
-       sp = smk_of_current();
-       skp = smk_find_entry(sp);
+       skp = smk_of_current();
        rc = 0;
 
        rcu_read_lock();
@@ -1216,13 +1244,13 @@ static int smack_mmap_file(struct file *file,
                /*
                 * Matching labels always allows access.
                 */
-               if (msmack == osmack)
+               if (mkp->smk_known == osmack)
                        continue;
                /*
                 * If there is a matching local rule take
                 * that into account as well.
                 */
-               may = smk_access_entry(srp->smk_subject, osmack,
+               may = smk_access_entry(srp->smk_subject->smk_known, osmack,
                                        &tsp->smk_rules);
                if (may == -ENOENT)
                        may = srp->smk_access;
@@ -1240,8 +1268,8 @@ static int smack_mmap_file(struct file *file,
                 * If there isn't one a SMACK64MMAP subject
                 * can't have as much access as current.
                 */
-               skp = smk_find_entry(msmack);
-               mmay = smk_access_entry(msmack, osmack, &skp->smk_rules);
+               mmay = smk_access_entry(mkp->smk_known, osmack,
+                                               &mkp->smk_rules);
                if (mmay == -ENOENT) {
                        rc = -EACCES;
                        break;
@@ -1250,7 +1278,8 @@ static int smack_mmap_file(struct file *file,
                 * If there is a local entry it modifies the
                 * potential access, too.
                 */
-               tmay = smk_access_entry(msmack, osmack, &tsp->smk_rules);
+               tmay = smk_access_entry(mkp->smk_known, osmack,
+                                               &tsp->smk_rules);
                if (tmay != -ENOENT)
                        mmay &= tmay;
 
@@ -1279,7 +1308,9 @@ static int smack_mmap_file(struct file *file,
  */
 static int smack_file_set_fowner(struct file *file)
 {
-       file->f_security = smk_of_current();
+       struct smack_known *skp = smk_of_current();
+
+       file->f_security = skp->smk_known;
        return 0;
 }
 
@@ -1297,9 +1328,10 @@ static int smack_file_set_fowner(struct file *file)
 static int smack_file_send_sigiotask(struct task_struct *tsk,
                                     struct fown_struct *fown, int signum)
 {
+       struct smack_known *skp;
+       struct smack_known *tkp = smk_of_task(tsk->cred->security);
        struct file *file;
        int rc;
-       char *tsp = smk_of_task(tsk->cred->security);
        struct smk_audit_info ad;
 
        /*
@@ -1308,13 +1340,14 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
        file = container_of(fown, struct file, f_owner);
 
        /* we don't log here as rc can be overriden */
-       rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL);
+       skp = smk_find_entry(file->f_security);
+       rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL);
        if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
                rc = 0;
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, tsk);
-       smack_log(file->f_security, tsp, MAY_WRITE, rc, &ad);
+       smack_log(file->f_security, tkp->smk_known, MAY_WRITE, rc, &ad);
        return rc;
 }
 
@@ -1469,12 +1502,12 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
 static int smack_kernel_act_as(struct cred *new, u32 secid)
 {
        struct task_smack *new_tsp = new->security;
-       char *smack = smack_from_secid(secid);
+       struct smack_known *skp = smack_from_secid(secid);
 
-       if (smack == NULL)
+       if (skp == NULL)
                return -EINVAL;
 
-       new_tsp->smk_task = smack;
+       new_tsp->smk_task = skp;
        return 0;
 }
 
@@ -1492,8 +1525,8 @@ static int smack_kernel_create_files_as(struct cred *new,
        struct inode_smack *isp = inode->i_security;
        struct task_smack *tsp = new->security;
 
-       tsp->smk_forked = isp->smk_inode;
-       tsp->smk_task = isp->smk_inode;
+       tsp->smk_forked = smk_find_entry(isp->smk_inode);
+       tsp->smk_task = tsp->smk_forked;
        return 0;
 }
 
@@ -1509,10 +1542,11 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
                                const char *caller)
 {
        struct smk_audit_info ad;
+       struct smack_known *skp = smk_of_task(task_security(p));
 
        smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, p);
-       return smk_curacc(smk_of_task(task_security(p)), access, &ad);
+       return smk_curacc(skp->smk_known, access, &ad);
 }
 
 /**
@@ -1558,7 +1592,9 @@ static int smack_task_getsid(struct task_struct *p)
  */
 static void smack_task_getsecid(struct task_struct *p, u32 *secid)
 {
-       *secid = smack_to_secid(smk_of_task(task_security(p)));
+       struct smack_known *skp = smk_of_task(task_security(p));
+
+       *secid = skp->smk_secid;
 }
 
 /**
@@ -1662,6 +1698,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
                           int sig, u32 secid)
 {
        struct smk_audit_info ad;
+       struct smack_known *skp;
+       struct smack_known *tkp = smk_of_task(task_security(p));
 
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
        smk_ad_setfield_u_tsk(&ad, p);
@@ -1670,15 +1708,14 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
         * can write the receiver.
         */
        if (secid == 0)
-               return smk_curacc(smk_of_task(task_security(p)), MAY_WRITE,
-                                 &ad);
+               return smk_curacc(tkp->smk_known, MAY_WRITE, &ad);
        /*
         * If the secid isn't 0 we're dealing with some USB IO
         * specific behavior. This is not clean. For one thing
         * we can't take privilege into account.
         */
-       return smk_access(smack_from_secid(secid),
-                         smk_of_task(task_security(p)), MAY_WRITE, &ad);
+       skp = smack_from_secid(secid);
+       return smk_access(skp, tkp->smk_known, MAY_WRITE, &ad);
 }
 
 /**
@@ -1710,7 +1747,9 @@ static int smack_task_wait(struct task_struct *p)
 static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
 {
        struct inode_smack *isp = inode->i_security;
-       isp->smk_inode = smk_of_task(task_security(p));
+       struct smack_known *skp = smk_of_task(task_security(p));
+
+       isp->smk_inode = skp->smk_known;
 }
 
 /*
@@ -1729,15 +1768,15 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
  */
 static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
 {
-       char *csp = smk_of_current();
+       struct smack_known *skp = smk_of_current();
        struct socket_smack *ssp;
 
        ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
        if (ssp == NULL)
                return -ENOMEM;
 
-       ssp->smk_in = csp;
-       ssp->smk_out = csp;
+       ssp->smk_in = skp->smk_known;
+       ssp->smk_out = skp;
        ssp->smk_packet = NULL;
 
        sk->sk_security = ssp;
@@ -1824,7 +1863,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
            labeled == SMACK_UNLABELED_SOCKET)
                netlbl_sock_delattr(sk);
        else {
-               skp = smk_find_entry(ssp->smk_out);
+               skp = ssp->smk_out;
                rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel);
        }
 
@@ -1847,6 +1886,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
  */
 static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
 {
+       struct smack_known *skp;
        int rc;
        int sk_lbl;
        char *hostsp;
@@ -1865,7 +1905,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
                ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr;
 #endif
                sk_lbl = SMACK_UNLABELED_SOCKET;
-               rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad);
+               skp = ssp->smk_out;
+               rc = smk_access(skp, hostsp, MAY_WRITE, &ad);
        } else {
                sk_lbl = SMACK_CIPSO_SOCKET;
                rc = 0;
@@ -1877,6 +1918,155 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
        return smack_netlabel(sk, sk_lbl);
 }
 
+/**
+ * smk_ipv6_port_label - Smack port access table management
+ * @sock: socket
+ * @address: address
+ *
+ * Create or update the port list entry
+ */
+static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_in6 *addr6;
+       struct socket_smack *ssp = sock->sk->sk_security;
+       struct smk_port_label *spp;
+       unsigned short port = 0;
+
+       if (address == NULL) {
+               /*
+                * This operation is changing the Smack information
+                * on the bound socket. Take the changes to the port
+                * as well.
+                */
+               list_for_each_entry(spp, &smk_ipv6_port_list, list) {
+                       if (sk != spp->smk_sock)
+                               continue;
+                       spp->smk_in = ssp->smk_in;
+                       spp->smk_out = ssp->smk_out;
+                       return;
+               }
+               /*
+                * A NULL address is only used for updating existing
+                * bound entries. If there isn't one, it's OK.
+                */
+               return;
+       }
+
+       addr6 = (struct sockaddr_in6 *)address;
+       port = ntohs(addr6->sin6_port);
+       /*
+        * This is a special case that is safely ignored.
+        */
+       if (port == 0)
+               return;
+
+       /*
+        * Look for an existing port list entry.
+        * This is an indication that a port is getting reused.
+        */
+       list_for_each_entry(spp, &smk_ipv6_port_list, list) {
+               if (spp->smk_port != port)
+                       continue;
+               spp->smk_port = port;
+               spp->smk_sock = sk;
+               spp->smk_in = ssp->smk_in;
+               spp->smk_out = ssp->smk_out;
+               return;
+       }
+
+       /*
+        * A new port entry is required.
+        */
+       spp = kzalloc(sizeof(*spp), GFP_KERNEL);
+       if (spp == NULL)
+               return;
+
+       spp->smk_port = port;
+       spp->smk_sock = sk;
+       spp->smk_in = ssp->smk_in;
+       spp->smk_out = ssp->smk_out;
+
+       list_add(&spp->list, &smk_ipv6_port_list);
+       return;
+}
+
+/**
+ * smk_ipv6_port_check - check Smack port access
+ * @sock: socket
+ * @address: address
+ *
+ * Create or update the port list entry
+ */
+static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address,
+                               int act)
+{
+       __be16 *bep;
+       __be32 *be32p;
+       struct sockaddr_in6 *addr6;
+       struct smk_port_label *spp;
+       struct socket_smack *ssp = sk->sk_security;
+       struct smack_known *skp;
+       unsigned short port = 0;
+       char *object;
+       struct smk_audit_info ad;
+#ifdef CONFIG_AUDIT
+       struct lsm_network_audit net;
+#endif
+
+       if (act == SMK_RECEIVING) {
+               skp = smack_net_ambient;
+               object = ssp->smk_in;
+       } else {
+               skp = ssp->smk_out;
+               object = smack_net_ambient->smk_known;
+       }
+
+       /*
+        * Get the IP address and port from the address.
+        */
+       addr6 = (struct sockaddr_in6 *)address;
+       port = ntohs(addr6->sin6_port);
+       bep = (__be16 *)(&addr6->sin6_addr);
+       be32p = (__be32 *)(&addr6->sin6_addr);
+
+       /*
+        * It's remote, so port lookup does no good.
+        */
+       if (be32p[0] || be32p[1] || be32p[2] || bep[6] || ntohs(bep[7]) != 1)
+               goto auditout;
+
+       /*
+        * It's local so the send check has to have passed.
+        */
+       if (act == SMK_RECEIVING) {
+               skp = &smack_known_web;
+               goto auditout;
+       }
+
+       list_for_each_entry(spp, &smk_ipv6_port_list, list) {
+               if (spp->smk_port != port)
+                       continue;
+               object = spp->smk_in;
+               if (act == SMK_CONNECTING)
+                       ssp->smk_packet = spp->smk_out->smk_known;
+               break;
+       }
+
+auditout:
+
+#ifdef CONFIG_AUDIT
+       smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+       ad.a.u.net->family = sk->sk_family;
+       ad.a.u.net->dport = port;
+       if (act == SMK_RECEIVING)
+               ad.a.u.net->v6info.saddr = addr6->sin6_addr;
+       else
+               ad.a.u.net->v6info.daddr = addr6->sin6_addr;
+#endif
+       return smk_access(skp, object, MAY_WRITE, &ad);
+}
+
 /**
  * smack_inode_setsecurity - set smack xattrs
  * @inode: the object
@@ -1892,7 +2082,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
 static int smack_inode_setsecurity(struct inode *inode, const char *name,
                                   const void *value, size_t size, int flags)
 {
-       char *sp;
+       struct smack_known *skp;
        struct inode_smack *nsp = inode->i_security;
        struct socket_smack *ssp;
        struct socket *sock;
@@ -1901,12 +2091,12 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
        if (value == NULL || size > SMK_LONGLABEL || size == 0)
                return -EACCES;
 
-       sp = smk_import(value, size);
-       if (sp == NULL)
+       skp = smk_import_entry(value, size);
+       if (skp == NULL)
                return -EINVAL;
 
        if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
-               nsp->smk_inode = sp;
+               nsp->smk_inode = skp->smk_known;
                nsp->smk_flags |= SMK_INODE_INSTANT;
                return 0;
        }
@@ -1923,10 +2113,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
        ssp = sock->sk->sk_security;
 
        if (strcmp(name, XATTR_SMACK_IPIN) == 0)
-               ssp->smk_in = sp;
+               ssp->smk_in = skp->smk_known;
        else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
-               ssp->smk_out = sp;
-               if (sock->sk->sk_family != PF_UNIX) {
+               ssp->smk_out = skp;
+               if (sock->sk->sk_family == PF_INET) {
                        rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
                        if (rc != 0)
                                printk(KERN_WARNING
@@ -1936,6 +2126,9 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
        } else
                return -EOPNOTSUPP;
 
+       if (sock->sk->sk_family == PF_INET6)
+               smk_ipv6_port_label(sock, NULL);
+
        return 0;
 }
 
@@ -1962,6 +2155,25 @@ static int smack_socket_post_create(struct socket *sock, int family,
        return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
 }
 
+/**
+ * smack_socket_bind - record port binding information.
+ * @sock: the socket
+ * @address: the port address
+ * @addrlen: size of the address
+ *
+ * Records the label bound to a port.
+ *
+ * Returns 0
+ */
+static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
+                               int addrlen)
+{
+       if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
+               smk_ipv6_port_label(sock, address);
+
+       return 0;
+}
+
 /**
  * smack_socket_connect - connect access check
  * @sock: the socket
@@ -1975,12 +2187,24 @@ static int smack_socket_post_create(struct socket *sock, int family,
 static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
                                int addrlen)
 {
-       if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
+       int rc = 0;
+
+       if (sock->sk == NULL)
                return 0;
-       if (addrlen < sizeof(struct sockaddr_in))
-               return -EINVAL;
 
-       return smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
+       switch (sock->sk->sk_family) {
+       case PF_INET:
+               if (addrlen < sizeof(struct sockaddr_in))
+                       return -EINVAL;
+               rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
+               break;
+       case PF_INET6:
+               if (addrlen < sizeof(struct sockaddr_in6))
+                       return -EINVAL;
+               rc = smk_ipv6_port_check(sock->sk, sap, SMK_CONNECTING);
+               break;
+       }
+       return rc;
 }
 
 /**
@@ -2011,7 +2235,9 @@ static int smack_flags_to_may(int flags)
  */
 static int smack_msg_msg_alloc_security(struct msg_msg *msg)
 {
-       msg->security = smk_of_current();
+       struct smack_known *skp = smk_of_current();
+
+       msg->security = skp->smk_known;
        return 0;
 }
 
@@ -2046,8 +2272,9 @@ static char *smack_of_shm(struct shmid_kernel *shp)
 static int smack_shm_alloc_security(struct shmid_kernel *shp)
 {
        struct kern_ipc_perm *isp = &shp->shm_perm;
+       struct smack_known *skp = smk_of_current();
 
-       isp->security = smk_of_current();
+       isp->security = skp->smk_known;
        return 0;
 }
 
@@ -2169,8 +2396,9 @@ static char *smack_of_sem(struct sem_array *sma)
 static int smack_sem_alloc_security(struct sem_array *sma)
 {
        struct kern_ipc_perm *isp = &sma->sem_perm;
+       struct smack_known *skp = smk_of_current();
 
-       isp->security = smk_of_current();
+       isp->security = skp->smk_known;
        return 0;
 }
 
@@ -2287,8 +2515,9 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
 static int smack_msg_queue_alloc_security(struct msg_queue *msq)
 {
        struct kern_ipc_perm *kisp = &msq->q_perm;
+       struct smack_known *skp = smk_of_current();
 
-       kisp->security = smk_of_current();
+       kisp->security = skp->smk_known;
        return 0;
 }
 
@@ -2460,8 +2689,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
        struct super_block *sbp;
        struct superblock_smack *sbsp;
        struct inode_smack *isp;
-       char *csp = smk_of_current();
-       char *fetched;
+       struct smack_known *skp;
+       struct smack_known *ckp = smk_of_current();
        char *final;
        char trattr[TRANS_TRUE_SIZE];
        int transflag = 0;
@@ -2528,7 +2757,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 * Programs that change smack have to treat the
                 * pty with respect.
                 */
-               final = csp;
+               final = ckp->smk_known;
                break;
        case SOCKFS_MAGIC:
                /*
@@ -2583,9 +2812,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 * Get the dentry for xattr.
                 */
                dp = dget(opt_dentry);
-               fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp);
-               if (fetched != NULL)
-                       final = fetched;
+               skp = smk_fetch(XATTR_NAME_SMACK, inode, dp);
+               if (skp != NULL)
+                       final = skp->smk_known;
 
                /*
                 * Transmuting directory
@@ -2625,7 +2854,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
        }
 
        if (final == NULL)
-               isp->smk_inode = csp;
+               isp->smk_inode = ckp->smk_known;
        else
                isp->smk_inode = final;
 
@@ -2648,13 +2877,14 @@ unlockandout:
  */
 static int smack_getprocattr(struct task_struct *p, char *name, char **value)
 {
+       struct smack_known *skp = smk_of_task(task_security(p));
        char *cp;
        int slen;
 
        if (strcmp(name, "current") != 0)
                return -EINVAL;
 
-       cp = kstrdup(smk_of_task(task_security(p)), GFP_KERNEL);
+       cp = kstrdup(skp->smk_known, GFP_KERNEL);
        if (cp == NULL)
                return -ENOMEM;
 
@@ -2680,7 +2910,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
 {
        struct task_smack *tsp;
        struct cred *new;
-       char *newsmack;
+       struct smack_known *skp;
 
        /*
         * Changing another process' Smack value is too dangerous
@@ -2698,14 +2928,14 @@ static int smack_setprocattr(struct task_struct *p, char *name,
        if (strcmp(name, "current") != 0)
                return -EINVAL;
 
-       newsmack = smk_import(value, size);
-       if (newsmack == NULL)
+       skp = smk_import_entry(value, size);
+       if (skp == NULL)
                return -EINVAL;
 
        /*
         * No process is ever allowed the web ("@") label.
         */
-       if (newsmack == smack_known_web.smk_known)
+       if (skp == &smack_known_web)
                return -EPERM;
 
        new = prepare_creds();
@@ -2713,7 +2943,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
                return -ENOMEM;
 
        tsp = new->security;
-       tsp->smk_task = newsmack;
+       tsp->smk_task = skp;
 
        commit_creds(new);
        return size;
@@ -2731,6 +2961,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
 static int smack_unix_stream_connect(struct sock *sock,
                                     struct sock *other, struct sock *newsk)
 {
+       struct smack_known *skp;
        struct socket_smack *ssp = sock->sk_security;
        struct socket_smack *osp = other->sk_security;
        struct socket_smack *nsp = newsk->sk_security;
@@ -2744,15 +2975,17 @@ static int smack_unix_stream_connect(struct sock *sock,
        smk_ad_setfield_u_net_sk(&ad, other);
 #endif
 
-       if (!smack_privileged(CAP_MAC_OVERRIDE))
-               rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
+       if (!smack_privileged(CAP_MAC_OVERRIDE)) {
+               skp = ssp->smk_out;
+               rc = smk_access(skp, osp->smk_in, MAY_WRITE, &ad);
+       }
 
        /*
         * Cross reference the peer labels for SO_PEERSEC.
         */
        if (rc == 0) {
-               nsp->smk_packet = ssp->smk_out;
-               ssp->smk_packet = osp->smk_out;
+               nsp->smk_packet = ssp->smk_out->smk_known;
+               ssp->smk_packet = osp->smk_out->smk_known;
        }
 
        return rc;
@@ -2770,8 +3003,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
 {
        struct socket_smack *ssp = sock->sk->sk_security;
        struct socket_smack *osp = other->sk->sk_security;
+       struct smack_known *skp;
        struct smk_audit_info ad;
-       int rc = 0;
 
 #ifdef CONFIG_AUDIT
        struct lsm_network_audit net;
@@ -2780,10 +3013,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
        smk_ad_setfield_u_net_sk(&ad, other->sk);
 #endif
 
-       if (!smack_privileged(CAP_MAC_OVERRIDE))
-               rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
+       if (smack_privileged(CAP_MAC_OVERRIDE))
+               return 0;
 
-       return rc;
+       skp = ssp->smk_out;
+       return smk_access(skp, osp->smk_in, MAY_WRITE, &ad);
 }
 
 /**
@@ -2792,22 +3026,32 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
  * @msg: the message
  * @size: the size of the message
  *
- * Return 0 if the current subject can write to the destination
- * host. This is only a question if the destination is a single
- * label host.
+ * Return 0 if the current subject can write to the destination host.
+ * For IPv4 this is only a question if the destination is a single label host.
+ * For IPv6 this is a check against the label of the port.
  */
 static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                int size)
 {
        struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
+       struct sockaddr *sap = (struct sockaddr *) msg->msg_name;
+       int rc = 0;
 
        /*
         * Perfectly reasonable for this to be NULL
         */
-       if (sip == NULL || sip->sin_family != AF_INET)
+       if (sip == NULL)
                return 0;
 
-       return smack_netlabel_send(sock->sk, sip);
+       switch (sip->sin_family) {
+       case AF_INET:
+               rc = smack_netlabel_send(sock->sk, sip);
+               break;
+       case AF_INET6:
+               rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
+               break;
+       }
+       return rc;
 }
 
 /**
@@ -2815,13 +3059,12 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
  * @sap: netlabel secattr
  * @ssp: socket security information
  *
- * Returns a pointer to a Smack label found on the label list.
+ * Returns a pointer to a Smack label entry found on the label list.
  */
-static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
-                               struct socket_smack *ssp)
+static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
+                                               struct socket_smack *ssp)
 {
-       struct smack_known *kp;
-       char *sp;
+       struct smack_known *skp;
        int found = 0;
 
        if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
@@ -2836,11 +3079,11 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
                 * ambient value.
                 */
                rcu_read_lock();
-               list_for_each_entry(kp, &smack_known_list, list) {
-                       if (sap->attr.mls.lvl != kp->smk_netlabel.attr.mls.lvl)
+               list_for_each_entry(skp, &smack_known_list, list) {
+                       if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl)
                                continue;
                        if (memcmp(sap->attr.mls.cat,
-                               kp->smk_netlabel.attr.mls.cat,
+                               skp->smk_netlabel.attr.mls.cat,
                                SMK_CIPSOLEN) != 0)
                                continue;
                        found = 1;
@@ -2849,17 +3092,17 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
                rcu_read_unlock();
 
                if (found)
-                       return kp->smk_known;
+                       return skp;
 
                if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known)
-                       return smack_known_web.smk_known;
-               return smack_known_star.smk_known;
+                       return &smack_known_web;
+               return &smack_known_star;
        }
        if ((sap->flags & NETLBL_SECATTR_SECID) != 0) {
                /*
                 * Looks like a fallback, which gives us a secid.
                 */
-               sp = smack_from_secid(sap->attr.secid);
+               skp = smack_from_secid(sap->attr.secid);
                /*
                 * This has got to be a bug because it is
                 * impossible to specify a fallback without
@@ -2867,8 +3110,8 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
                 * it has a secid, and the only way to get a
                 * secid is from a fallback.
                 */
-               BUG_ON(sp == NULL);
-               return sp;
+               BUG_ON(skp == NULL);
+               return skp;
        }
        /*
         * Without guidance regarding the smack value
@@ -2878,6 +3121,54 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
        return smack_net_ambient;
 }
 
+static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr *sap)
+{
+       struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap;
+       u8 nexthdr;
+       int offset;
+       int proto = -EINVAL;
+       struct ipv6hdr _ipv6h;
+       struct ipv6hdr *ip6;
+       __be16 frag_off;
+       struct tcphdr _tcph, *th;
+       struct udphdr _udph, *uh;
+       struct dccp_hdr _dccph, *dh;
+
+       sip->sin6_port = 0;
+
+       offset = skb_network_offset(skb);
+       ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
+       if (ip6 == NULL)
+               return -EINVAL;
+       sip->sin6_addr = ip6->saddr;
+
+       nexthdr = ip6->nexthdr;
+       offset += sizeof(_ipv6h);
+       offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
+       if (offset < 0)
+               return -EINVAL;
+
+       proto = nexthdr;
+       switch (proto) {
+       case IPPROTO_TCP:
+               th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
+               if (th != NULL)
+                       sip->sin6_port = th->source;
+               break;
+       case IPPROTO_UDP:
+               uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
+               if (uh != NULL)
+                       sip->sin6_port = uh->source;
+               break;
+       case IPPROTO_DCCP:
+               dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
+               if (dh != NULL)
+                       sip->sin6_port = dh->dccph_sport;
+               break;
+       }
+       return proto;
+}
+
 /**
  * smack_socket_sock_rcv_skb - Smack packet delivery access check
  * @sk: socket
@@ -2889,43 +3180,52 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        struct netlbl_lsm_secattr secattr;
        struct socket_smack *ssp = sk->sk_security;
-       char *csp;
-       int rc;
+       struct smack_known *skp;
+       struct sockaddr sadd;
+       int rc = 0;
        struct smk_audit_info ad;
 #ifdef CONFIG_AUDIT
        struct lsm_network_audit net;
 #endif
-       if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
-               return 0;
-
-       /*
-        * Translate what netlabel gave us.
-        */
-       netlbl_secattr_init(&secattr);
+       switch (sk->sk_family) {
+       case PF_INET:
+               /*
+                * Translate what netlabel gave us.
+                */
+               netlbl_secattr_init(&secattr);
 
-       rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
-       if (rc == 0)
-               csp = smack_from_secattr(&secattr, ssp);
-       else
-               csp = smack_net_ambient;
+               rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
+               if (rc == 0)
+                       skp = smack_from_secattr(&secattr, ssp);
+               else
+                       skp = smack_net_ambient;
 
-       netlbl_secattr_destroy(&secattr);
+               netlbl_secattr_destroy(&secattr);
 
 #ifdef CONFIG_AUDIT
-       smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
-       ad.a.u.net->family = sk->sk_family;
-       ad.a.u.net->netif = skb->skb_iif;
-       ipv4_skb_to_auditdata(skb, &ad.a, NULL);
+               smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
+               ad.a.u.net->family = sk->sk_family;
+               ad.a.u.net->netif = skb->skb_iif;
+               ipv4_skb_to_auditdata(skb, &ad.a, NULL);
 #endif
-       /*
-        * Receiving a packet requires that the other end
-        * be able to write here. Read access is not required.
-        * This is the simplist possible security model
-        * for networking.
-        */
-       rc = smk_access(csp, ssp->smk_in, MAY_WRITE, &ad);
-       if (rc != 0)
-               netlbl_skbuff_err(skb, rc, 0);
+               /*
+                * Receiving a packet requires that the other end
+                * be able to write here. Read access is not required.
+                * This is the simplist possible security model
+                * for networking.
+                */
+               rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+               if (rc != 0)
+                       netlbl_skbuff_err(skb, rc, 0);
+               break;
+       case PF_INET6:
+               rc = smk_skb_to_addr_ipv6(skb, &sadd);
+               if (rc == IPPROTO_UDP || rc == IPPROTO_TCP)
+                       rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING);
+               else
+                       rc = 0;
+               break;
+       }
        return rc;
 }
 
@@ -2979,7 +3279,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
 {
        struct netlbl_lsm_secattr secattr;
        struct socket_smack *ssp = NULL;
-       char *sp;
+       struct smack_known *skp;
        int family = PF_UNSPEC;
        u32 s = 0;      /* 0 is the invalid secid */
        int rc;
@@ -2995,7 +3295,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
 
        if (family == PF_UNIX) {
                ssp = sock->sk->sk_security;
-               s = smack_to_secid(ssp->smk_out);
+               s = ssp->smk_out->smk_secid;
        } else if (family == PF_INET || family == PF_INET6) {
                /*
                 * Translate what netlabel gave us.
@@ -3005,8 +3305,8 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
                netlbl_secattr_init(&secattr);
                rc = netlbl_skbuff_getattr(skb, family, &secattr);
                if (rc == 0) {
-                       sp = smack_from_secattr(&secattr, ssp);
-                       s = smack_to_secid(sp);
+                       skp = smack_from_secattr(&secattr, ssp);
+                       s = skp->smk_secid;
                }
                netlbl_secattr_destroy(&secattr);
        }
@@ -3027,13 +3327,15 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
 static void smack_sock_graft(struct sock *sk, struct socket *parent)
 {
        struct socket_smack *ssp;
+       struct smack_known *skp = smk_of_current();
 
        if (sk == NULL ||
            (sk->sk_family != PF_INET && sk->sk_family != PF_INET6))
                return;
 
        ssp = sk->sk_security;
-       ssp->smk_in = ssp->smk_out = smk_of_current();
+       ssp->smk_in = skp->smk_known;
+       ssp->smk_out = skp;
        /* cssp->smk_packet is already set in smack_inet_csk_clone() */
 }
 
@@ -3055,7 +3357,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        struct netlbl_lsm_secattr secattr;
        struct sockaddr_in addr;
        struct iphdr *hdr;
-       char *sp;
        char *hsp;
        int rc;
        struct smk_audit_info ad;
@@ -3063,16 +3364,24 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        struct lsm_network_audit net;
 #endif
 
-       /* handle mapped IPv4 packets arriving via IPv6 sockets */
-       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
-               family = PF_INET;
+       if (family == PF_INET6) {
+               /*
+                * Handle mapped IPv4 packets arriving
+                * via IPv6 sockets. Don't set up netlabel
+                * processing on IPv6.
+                */
+               if (skb->protocol == htons(ETH_P_IP))
+                       family = PF_INET;
+               else
+                       return 0;
+       }
 
        netlbl_secattr_init(&secattr);
        rc = netlbl_skbuff_getattr(skb, family, &secattr);
        if (rc == 0)
-               sp = smack_from_secattr(&secattr, ssp);
+               skp = smack_from_secattr(&secattr, ssp);
        else
-               sp = smack_known_huh.smk_known;
+               skp = &smack_known_huh;
        netlbl_secattr_destroy(&secattr);
 
 #ifdef CONFIG_AUDIT
@@ -3085,7 +3394,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
         * Receiving a packet requires that the other end be able to write
         * here. Read access is not required.
         */
-       rc = smk_access(sp, ssp->smk_in, MAY_WRITE, &ad);
+       rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
        if (rc != 0)
                return rc;
 
@@ -3093,7 +3402,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
         * Save the peer's label in the request_sock so we can later setup
         * smk_packet in the child socket so that SO_PEERCRED can report it.
         */
-       req->peer_secid = smack_to_secid(sp);
+       req->peer_secid = skp->smk_secid;
 
        /*
         * We need to decide if we want to label the incoming connection here
@@ -3106,10 +3415,9 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
        hsp = smack_host_label(&addr);
        rcu_read_unlock();
 
-       if (hsp == NULL) {
-               skp = smk_find_entry(sp);
+       if (hsp == NULL)
                rc = netlbl_req_setattr(req, &skp->smk_netlabel);
-       else
+       else
                netlbl_req_delattr(req);
 
        return rc;
@@ -3126,10 +3434,12 @@ static void smack_inet_csk_clone(struct sock *sk,
                                 const struct request_sock *req)
 {
        struct socket_smack *ssp = sk->sk_security;
+       struct smack_known *skp;
 
-       if (req->peer_secid != 0)
-               ssp->smk_packet = smack_from_secid(req->peer_secid);
-       else
+       if (req->peer_secid != 0) {
+               skp = smack_from_secid(req->peer_secid);
+               ssp->smk_packet = skp->smk_known;
+       } else
                ssp->smk_packet = NULL;
 }
 
@@ -3155,7 +3465,9 @@ static void smack_inet_csk_clone(struct sock *sk,
 static int smack_key_alloc(struct key *key, const struct cred *cred,
                           unsigned long flags)
 {
-       key->security = smk_of_task(cred->security);
+       struct smack_known *skp = smk_of_task(cred->security);
+
+       key->security = skp->smk_known;
        return 0;
 }
 
@@ -3184,7 +3496,7 @@ static int smack_key_permission(key_ref_t key_ref,
 {
        struct key *keyp;
        struct smk_audit_info ad;
-       char *tsp = smk_of_task(cred->security);
+       struct smack_known *tkp = smk_of_task(cred->security);
 
        keyp = key_ref_to_ptr(key_ref);
        if (keyp == NULL)
@@ -3198,15 +3510,14 @@ static int smack_key_permission(key_ref_t key_ref,
        /*
         * This should not occur
         */
-       if (tsp == NULL)
+       if (tkp == NULL)
                return -EACCES;
 #ifdef CONFIG_AUDIT
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY);
        ad.a.u.key_struct.key = keyp->serial;
        ad.a.u.key_struct.key_desc = keyp->description;
 #endif
-       return smk_access(tsp, keyp->security,
-                                MAY_READWRITE, &ad);
+       return smk_access(tkp, keyp->security, MAY_READWRITE, &ad);
 }
 #endif /* CONFIG_KEYS */
 
@@ -3288,7 +3599,7 @@ static int smack_audit_rule_known(struct audit_krule *krule)
 static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
                                  struct audit_context *actx)
 {
-       char *smack;
+       struct smack_known *skp;
        char *rule = vrule;
 
        if (!rule) {
@@ -3300,7 +3611,7 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
        if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
                return 0;
 
-       smack = smack_from_secid(secid);
+       skp = smack_from_secid(secid);
 
        /*
         * No need to do string comparisons. If a match occurs,
@@ -3308,9 +3619,9 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
         * label.
         */
        if (op == Audit_equal)
-               return (rule == smack);
+               return (rule == skp->smk_known);
        if (op == Audit_not_equal)
-               return (rule != smack);
+               return (rule != skp->smk_known);
 
        return 0;
 }
@@ -3338,11 +3649,11 @@ static void smack_audit_rule_free(void *vrule)
  */
 static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 {
-       char *sp = smack_from_secid(secid);
+       struct smack_known *skp = smack_from_secid(secid);
 
        if (secdata)
-               *secdata = sp;
-       *seclen = strlen(sp);
+               *secdata = skp->smk_known;
+       *seclen = strlen(skp->smk_known);
        return 0;
 }
 
@@ -3498,6 +3809,7 @@ struct security_operations smack_ops = {
        .unix_may_send =                smack_unix_may_send,
 
        .socket_post_create =           smack_socket_post_create,
+       .socket_bind =                  smack_socket_bind,
        .socket_connect =               smack_socket_connect,
        .socket_sendmsg =               smack_socket_sendmsg,
        .socket_sock_rcv_skb =          smack_socket_sock_rcv_skb,
@@ -3577,8 +3889,8 @@ static __init int smack_init(void)
        if (!security_module_enable(&smack_ops))
                return 0;
 
-       tsp = new_task_smack(smack_known_floor.smk_known,
-                               smack_known_floor.smk_known, GFP_KERNEL);
+       tsp = new_task_smack(&smack_known_floor, &smack_known_floor,
+                               GFP_KERNEL);
        if (tsp == NULL)
                return -ENOMEM;
 
index 53a08b85bda4837936339f7158474994af8a7ba6..ab167037b2ddcc99b9dc733b69f1243ee65843fb 100644 (file)
@@ -66,7 +66,7 @@ static DEFINE_MUTEX(smk_netlbladdr_lock);
  * If it isn't somehow marked, use this.
  * It can be reset via smackfs/ambient
  */
-char *smack_net_ambient;
+struct smack_known *smack_net_ambient;
 
 /*
  * This is the level in a CIPSO header that indicates a
@@ -112,7 +112,7 @@ struct smack_master_list {
 LIST_HEAD(smack_rule_list);
 
 struct smack_parsed_rule {
-       char                    *smk_subject;
+       struct smack_known      *smk_subject;
        char                    *smk_object;
        int                     smk_access1;
        int                     smk_access2;
@@ -163,9 +163,11 @@ static inline void smack_catset_bit(unsigned int cat, char *catsetp)
  */
 static void smk_netlabel_audit_set(struct netlbl_audit *nap)
 {
+       struct smack_known *skp = smk_of_current();
+
        nap->loginuid = audit_get_loginuid(current);
        nap->sessionid = audit_get_sessionid(current);
-       nap->secid = smack_to_secid(smk_of_current());
+       nap->secid = skp->smk_secid;
 }
 
 /*
@@ -306,7 +308,7 @@ static int smk_fill_rule(const char *subject, const char *object,
        struct smack_known *skp;
 
        if (import) {
-               rule->smk_subject = smk_import(subject, len);
+               rule->smk_subject = smk_import_entry(subject, len);
                if (rule->smk_subject == NULL)
                        return -1;
 
@@ -321,7 +323,7 @@ static int smk_fill_rule(const char *subject, const char *object,
                kfree(cp);
                if (skp == NULL)
                        return -1;
-               rule->smk_subject = skp->smk_known;
+               rule->smk_subject = skp;
 
                cp = smk_parse_smack(object, len);
                if (cp == NULL)
@@ -445,7 +447,6 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
                                        struct list_head *rule_list,
                                        struct mutex *rule_lock, int format)
 {
-       struct smack_known *skp;
        struct smack_parsed_rule *rule;
        char *data;
        int datalen;
@@ -505,12 +506,10 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
                        goto out_free_rule;
        }
 
-
        if (rule_list == NULL) {
                load = 1;
-               skp = smk_find_entry(rule->smk_subject);
-               rule_list = &skp->smk_rules;
-               rule_lock = &skp->smk_rules_lock;
+               rule_list = &rule->smk_subject->smk_rules;
+               rule_lock = &rule->smk_subject->smk_rules_lock;
        }
 
        rc = smk_set_access(rule, rule_list, rule_lock, load);
@@ -579,13 +578,14 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
         * because you should expect to be able to write
         * anything you read back.
         */
-       if (strlen(srp->smk_subject) >= max || strlen(srp->smk_object) >= max)
+       if (strlen(srp->smk_subject->smk_known) >= max ||
+           strlen(srp->smk_object) >= max)
                return;
 
        if (srp->smk_access == 0)
                return;
 
-       seq_printf(s, "%s %s", srp->smk_subject, srp->smk_object);
+       seq_printf(s, "%s %s", srp->smk_subject->smk_known, srp->smk_object);
 
        seq_putc(s, ' ');
 
@@ -738,9 +738,9 @@ static void smk_unlbl_ambient(char *oldambient)
                               __func__, __LINE__, rc);
        }
        if (smack_net_ambient == NULL)
-               smack_net_ambient = smack_known_floor.smk_known;
+               smack_net_ambient = &smack_known_floor;
 
-       rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET,
+       rc = netlbl_cfg_unlbl_map_add(smack_net_ambient->smk_known, PF_INET,
                                      NULL, NULL, &nai);
        if (rc != 0)
                printk(KERN_WARNING "%s:%d add rc = %d\n",
@@ -881,7 +881,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
        if (format == SMK_FIXED24_FMT)
                rule += SMK_LABELLEN;
        else
-               rule += strlen(skp->smk_known);
+               rule += strlen(skp->smk_known) + 1;
 
        ret = sscanf(rule, "%d", &maplevel);
        if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL)
@@ -1535,11 +1535,12 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
         */
        mutex_lock(&smack_ambient_lock);
 
-       asize = strlen(smack_net_ambient) + 1;
+       asize = strlen(smack_net_ambient->smk_known) + 1;
 
        if (cn >= asize)
                rc = simple_read_from_buffer(buf, cn, ppos,
-                                            smack_net_ambient, asize);
+                                            smack_net_ambient->smk_known,
+                                            asize);
        else
                rc = -EINVAL;
 
@@ -1560,8 +1561,8 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
 static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 {
+       struct smack_known *skp;
        char *oldambient;
-       char *smack = NULL;
        char *data;
        int rc = count;
 
@@ -1577,16 +1578,16 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
                goto out;
        }
 
-       smack = smk_import(data, count);
-       if (smack == NULL) {
+       skp = smk_import_entry(data, count);
+       if (skp == NULL) {
                rc = -EINVAL;
                goto out;
        }
 
        mutex_lock(&smack_ambient_lock);
 
-       oldambient = smack_net_ambient;
-       smack_net_ambient = smack;
+       oldambient = smack_net_ambient->smk_known;
+       smack_net_ambient = skp;
        smk_unlbl_ambient(oldambient);
 
        mutex_unlock(&smack_ambient_lock);
@@ -1645,7 +1646,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 {
        char *data;
-       char *sp = smk_of_task(current->cred->security);
+       struct smack_known *skp = smk_of_task(current->cred->security);
        int rc = count;
 
        if (!smack_privileged(CAP_MAC_ADMIN))
@@ -1656,7 +1657,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
         * explicitly for clarity. The smk_access() implementation
         * would use smk_access(smack_onlycap, MAY_WRITE)
         */
-       if (smack_onlycap != NULL && smack_onlycap != sp)
+       if (smack_onlycap != NULL && smack_onlycap != skp->smk_known)
                return -EPERM;
 
        data = kzalloc(count, GFP_KERNEL);
@@ -1866,8 +1867,8 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
        if (res)
                return -EINVAL;
 
-       res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access1,
-                         NULL);
+       res = smk_access(rule.smk_subject, rule.smk_object,
+                               rule.smk_access1, NULL);
        data[0] = res == 0 ? '1' : '0';
        data[1] = '\0';
 
index aa5d8034890b5f6d3fc7ede653862e17bf46b9db..1ca8dc2ccb89f21cb0d102d2d4cd4cc0c74e4bf0 100644 (file)
@@ -1076,8 +1076,6 @@ static int aaci_remove(struct amba_device *dev)
 {
        struct snd_card *card = amba_get_drvdata(dev);
 
-       amba_set_drvdata(dev, NULL);
-
        if (card) {
                struct aaci *aaci = card->private_data;
                writel(0, aaci->base + AACI_MAINCR);
index ec54be4efff09c48ec1ff7a5b09318a831ac563e..ce431e6e07cfc7df27e8320d6da1b13516310df9 100644 (file)
@@ -230,7 +230,6 @@ static int pxa2xx_ac97_remove(struct platform_device *dev)
 
        if (card) {
                snd_card_free(card);
-               platform_set_drvdata(dev, NULL);
                pxa2xx_ac97_hw_remove(dev);
        }
 
index b413ed05e74deae78fbd97809c99f0fd68f1ee46..c0c2f57a0d6f332b6143c3eaa6850921c1dde485 100644 (file)
@@ -157,6 +157,15 @@ config SND_DYNAMIC_MINORS
 
          If you are unsure about this, say N here.
 
+config SND_MAX_CARDS
+       int "Max number of sound cards"
+       range 4 256
+       default 32
+       depends on SND_DYNAMIC_MINORS
+       help
+         Specify the max number of sound cards that can be assigned
+         on a single machine.
+
 config SND_SUPPORT_OLD_API
        bool "Support old ALSA API"
        default y
index 6ef06400dfc83884f2feaf6ddd26529498bae8c3..6b9087115da24806e8aba244127ac8ec3a4e93f8 100644 (file)
@@ -46,7 +46,8 @@ static LIST_HEAD(shutdown_files);
 
 static const struct file_operations snd_shutdown_f_ops;
 
-static unsigned int snd_cards_lock;    /* locked for registering/using */
+/* locked for registering/using */
+static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS);
 struct snd_card *snd_cards[SNDRV_CARDS];
 EXPORT_SYMBOL(snd_cards);
 
@@ -167,29 +168,35 @@ int snd_card_create(int idx, const char *xid,
        err = 0;
        mutex_lock(&snd_card_mutex);
        if (idx < 0) {
-               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
                        /* idx == -1 == 0xffff means: take any free slot */
-                       if (~snd_cards_lock & idx & 1<<idx2) {
+                       if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
+                               continue;
+                       if (!test_bit(idx2, snd_cards_lock)) {
                                if (module_slot_match(module, idx2)) {
                                        idx = idx2;
                                        break;
                                }
                        }
+               }
        }
        if (idx < 0) {
-               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
                        /* idx == -1 == 0xffff means: take any free slot */
-                       if (~snd_cards_lock & idx & 1<<idx2) {
+                       if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
+                               continue;
+                       if (!test_bit(idx2, snd_cards_lock)) {
                                if (!slots[idx2] || !*slots[idx2]) {
                                        idx = idx2;
                                        break;
                                }
                        }
+               }
        }
        if (idx < 0)
                err = -ENODEV;
        else if (idx < snd_ecards_limit) {
-               if (snd_cards_lock & (1 << idx))
+               if (test_bit(idx, snd_cards_lock))
                        err = -EBUSY;   /* invalid */
        } else if (idx >= SNDRV_CARDS)
                err = -ENODEV;
@@ -199,7 +206,7 @@ int snd_card_create(int idx, const char *xid,
                         idx, snd_ecards_limit - 1, err);
                goto __error;
        }
-       snd_cards_lock |= 1 << idx;             /* lock it */
+       set_bit(idx, snd_cards_lock);           /* lock it */
        if (idx >= snd_ecards_limit)
                snd_ecards_limit = idx + 1; /* increase the limit */
        mutex_unlock(&snd_card_mutex);
@@ -249,7 +256,7 @@ int snd_card_locked(int card)
        int locked;
 
        mutex_lock(&snd_card_mutex);
-       locked = snd_cards_lock & (1 << card);
+       locked = test_bit(card, snd_cards_lock);
        mutex_unlock(&snd_card_mutex);
        return locked;
 }
@@ -361,7 +368,7 @@ int snd_card_disconnect(struct snd_card *card)
        /* phase 1: disable fops (user space) operations for ALSA API */
        mutex_lock(&snd_card_mutex);
        snd_cards[card->number] = NULL;
-       snd_cards_lock &= ~(1 << card->number);
+       clear_bit(card->number, snd_cards_lock);
        mutex_unlock(&snd_card_mutex);
        
        /* phase 2: replace file->f_op with special dummy operations */
@@ -549,7 +556,6 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
                                    const char *nid)
 {
        int len, loops;
-       bool with_suffix;
        bool is_default = false;
        char *id;
        
@@ -565,26 +571,23 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
                is_default = true;
        }
 
-       with_suffix = false;
+       len = strlen(id);
        for (loops = 0; loops < SNDRV_CARDS; loops++) {
+               char *spos;
+               char sfxstr[5]; /* "_012" */
+               int sfxlen;
+
                if (card_id_ok(card, id))
                        return; /* OK */
 
-               len = strlen(id);
-               if (!with_suffix) {
-                       /* add the "_X" suffix */
-                       char *spos = id + len;
-                       if (len >  sizeof(card->id) - 3)
-                               spos = id + sizeof(card->id) - 3;
-                       strcpy(spos, "_1");
-                       with_suffix = true;
-               } else {
-                       /* modify the existing suffix */
-                       if (id[len - 1] != '9')
-                               id[len - 1]++;
-                       else
-                               id[len - 1] = 'A';
-               }
+               /* Add _XYZ suffix */
+               sprintf(sfxstr, "_%X", loops + 1);
+               sfxlen = strlen(sfxstr);
+               if (len + sfxlen >= sizeof(card->id))
+                       spos = id + sizeof(card->id) - sfxlen - 1;
+               else
+                       spos = id + len;
+               strcpy(spos, sfxstr);
        }
        /* fallback to the default id */
        if (!is_default) {
index 41b3dfe68698985e2d5f7e85a4e8411cb6a6371e..82bb029d4414155e60ae2a01ddd4707d926b83ae 100644 (file)
@@ -568,7 +568,8 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
  *
  * Sets the given PCM operators to the pcm instance.
  */
-void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops)
+void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
+                    const struct snd_pcm_ops *ops)
 {
        struct snd_pcm_str *stream = &pcm->streams[direction];
        struct snd_pcm_substream *substream;
index f92818155958d2a166d3a90f1f2ed2670e9217d2..a68d4c6d702c80cd461def1c84c4a91a254b21a4 100644 (file)
@@ -1589,29 +1589,16 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
 }
 
 
-/* WARNING: Don't forget to fput back the file */
-static struct file *snd_pcm_file_fd(int fd, int *fput_needed)
+static bool is_pcm_file(struct file *file)
 {
-       struct file *file;
-       struct inode *inode;
+       struct inode *inode = file_inode(file);
        unsigned int minor;
 
-       file = fget_light(fd, fput_needed);
-       if (!file)
-               return NULL;
-       inode = file_inode(file);
-       if (!S_ISCHR(inode->i_mode) ||
-           imajor(inode) != snd_major) {
-               fput_light(file, *fput_needed);
-               return NULL;
-       }
+       if (!S_ISCHR(inode->i_mode) || imajor(inode) != snd_major)
+               return false;
        minor = iminor(inode);
-       if (!snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) &&
-           !snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE)) {
-               fput_light(file, *fput_needed);
-               return NULL;
-       }
-       return file;
+       return snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) ||
+               snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE);
 }
 
 /*
@@ -1620,16 +1607,18 @@ static struct file *snd_pcm_file_fd(int fd, int *fput_needed)
 static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
 {
        int res = 0;
-       struct file *file;
        struct snd_pcm_file *pcm_file;
        struct snd_pcm_substream *substream1;
        struct snd_pcm_group *group;
-       int fput_needed;
+       struct fd f = fdget(fd);
 
-       file = snd_pcm_file_fd(fd, &fput_needed);
-       if (!file)
+       if (!f.file)
                return -EBADFD;
-       pcm_file = file->private_data;
+       if (!is_pcm_file(f.file)) {
+               res = -EBADFD;
+               goto _badf;
+       }
+       pcm_file = f.file->private_data;
        substream1 = pcm_file->substream;
        group = kmalloc(sizeof(*group), GFP_KERNEL);
        if (!group) {
@@ -1663,8 +1652,9 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
        up_write(&snd_pcm_link_rwsem);
  _nolock:
        snd_card_unref(substream1->pcm->card);
-       fput_light(file, fput_needed);
        kfree(group);
+ _badf:
+       fdput(f);
        return res;
 }
 
index 02f90b4f8b86a28e4c8faf14dde8e5d749e815af..842a97d5fc3a1ec104fcd691597e07095c3fa76d 100644 (file)
@@ -310,20 +310,10 @@ static int master_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static int master_put(struct snd_kcontrol *kcontrol,
-                     struct snd_ctl_elem_value *ucontrol)
+static int sync_slaves(struct link_master *master, int old_val, int new_val)
 {
-       struct link_master *master = snd_kcontrol_chip(kcontrol);
        struct link_slave *slave;
        struct snd_ctl_elem_value *uval;
-       int err, old_val;
-
-       err = master_init(master);
-       if (err < 0)
-               return err;
-       old_val = master->val;
-       if (ucontrol->value.integer.value[0] == old_val)
-               return 0;
 
        uval = kmalloc(sizeof(*uval), GFP_KERNEL);
        if (!uval)
@@ -332,11 +322,33 @@ static int master_put(struct snd_kcontrol *kcontrol,
                master->val = old_val;
                uval->id = slave->slave.id;
                slave_get_val(slave, uval);
-               master->val = ucontrol->value.integer.value[0];
+               master->val = new_val;
                slave_put_val(slave, uval);
        }
        kfree(uval);
-       if (master->hook && !err)
+       return 0;
+}
+
+static int master_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct link_master *master = snd_kcontrol_chip(kcontrol);
+       int err, new_val, old_val;
+       bool first_init;
+
+       err = master_init(master);
+       if (err < 0)
+               return err;
+       first_init = err;
+       old_val = master->val;
+       new_val = ucontrol->value.integer.value[0];
+       if (new_val == old_val)
+               return 0;
+
+       err = sync_slaves(master, old_val, new_val);
+       if (err < 0)
+               return err;
+       if (master->hook && !first_init)
                master->hook(master->hook_private_data, master->val);
        return 1;
 }
@@ -442,20 +454,33 @@ int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
 EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook);
 
 /**
- * snd_ctl_sync_vmaster_hook - Sync the vmaster hook
+ * snd_ctl_sync_vmaster - Sync the vmaster slaves and hook
  * @kcontrol: vmaster kctl element
+ * @hook_only: sync only the hook
  *
- * Call the hook function to synchronize with the current value of the given
- * vmaster element.  NOP when NULL is passed to @kcontrol or the hook doesn't
- * exist.
+ * Forcibly call the put callback of each slave and call the hook function
+ * to synchronize with the current value of the given vmaster element.
+ * NOP when NULL is passed to @kcontrol.
  */
-void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kcontrol)
+void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only)
 {
        struct link_master *master;
+       bool first_init = false;
+
        if (!kcontrol)
                return;
        master = snd_kcontrol_chip(kcontrol);
-       if (master->hook)
+       if (!hook_only) {
+               int err = master_init(master);
+               if (err < 0)
+                       return;
+               first_init = err;
+               err = sync_slaves(master, master->val, master->val);
+               if (err < 0)
+                       return;
+       }
+
+       if (master->hook && !first_init)
                master->hook(master->hook_private_data, master->val);
 }
-EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster_hook);
+EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);
index 6f78de9c6fb68bbcedcbbbe473d1eb6c837d24a6..f7589923effa08f25094b87423e559414e7f8aaf 100644 (file)
@@ -1183,7 +1183,6 @@ static int loopback_probe(struct platform_device *devptr)
 static int loopback_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index fd798f753609c81a64e6391132d73543cfbf1761..11048cc744d0ef01034ce0a9aceb517ff202b5a5 100644 (file)
@@ -1129,7 +1129,6 @@ static int snd_dummy_probe(struct platform_device *devptr)
 static int snd_dummy_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 8125a7e95ee4dd0bf93dbd07291abb17dbcd1347..95ea4a153ea43afb916de2ad86ffd2990650d355 100644 (file)
@@ -1325,7 +1325,6 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
 static int snd_ml403_ac97cr_remove(struct platform_device *pfdev)
 {
        snd_card_free(platform_get_drvdata(pfdev));
-       platform_set_drvdata(pfdev, NULL);
        return 0;
 }
 
index da1a29bfc85d7a21c91f8efb6f29edaae6fa0677..90a3a7b38a2a01eee908c7975f1dedce783a2948 100644 (file)
@@ -129,7 +129,6 @@ static int snd_mpu401_probe(struct platform_device *devptr)
 static int snd_mpu401_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 9f1815b99a15235ec2923e39ed040998ee7a3448..e5ec7eb27dec5f873c36b6c6f5e3e79a44fdddfe 100644 (file)
@@ -749,7 +749,6 @@ static int snd_mtpav_probe(struct platform_device *dev)
 static int snd_mtpav_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 7a5fdb9b0afcd000acc649042a38f182cc280f4e..1c19cd7ad26e76af7c71b6615ae291aeed42faf7 100644 (file)
@@ -189,7 +189,6 @@ static int pcsp_remove(struct platform_device *dev)
        struct snd_pcsp *chip = platform_get_drvdata(dev);
        alsa_card_pcsp_exit(chip);
        pcspkr_input_remove(chip->input_dev);
-       platform_set_drvdata(dev, NULL);
        return 0;
 }
 
index 7425dd8c1f095072d3163d98ccd5378594627886..e0bf5e77b43ae757d1f607b5c86a3636a4e371df 100644 (file)
@@ -985,7 +985,6 @@ static int snd_serial_probe(struct platform_device *devptr)
 static int snd_serial_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index cc4be88d73184a6e538a4eb961c3f47c182abdd0..ace3879e8d9649fb95a8d65a4c3481e0ce0e49a4 100644 (file)
@@ -132,7 +132,6 @@ static int snd_virmidi_probe(struct platform_device *devptr)
 static int snd_virmidi_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index c39961c11401a32777eac568b6b1e273d9ab5e7b..83596891cde4f1d6b1cb9fb7115d4646265bf85e 100644 (file)
@@ -205,7 +205,7 @@ static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh)
 
        if (size < 1)
                return 0;
-       if (snd_BUG_ON(size > SIZE_MAX_STATUS))
+       if (snd_BUG_ON(size >= SIZE_MAX_STATUS))
                return -EINVAL;
 
        for (i = 1; i <= size; i++) {
index b680c5ef01d694468f3b2736f357e49a09d50bf3..f6103d68c4b1660bf9d61ba8d0c053086eec923b 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
-#include <linux/spinlock.h>
 #include "packets-buffer.h"
 
 /**
index 844a555c3b1eb4ab002eb1c33b64f4703f6a3a44..b252c21b6d13b32d1fbc16a4d9894b6995d2dbf0 100644 (file)
@@ -405,8 +405,10 @@ static int scs_probe(struct device *unit_dev)
        scs->output_idle = true;
 
        scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL);
-       if (!scs->buffer)
+       if (!scs->buffer) {
+               err = -ENOMEM;
                goto err_card;
+       }
 
        scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE;
        scs->hss_handler.address_callback = handle_hss;
index cef813d23641afcd39b56a57c5fc8058cb99bfb0..ed726d1569e8d3e9dffd49ee2af31fc79b7b7bc8 100644 (file)
@@ -571,7 +571,7 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
        struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
        int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
        const char **input_names;
-       int  num_names, idx;
+       unsigned int num_names, idx;
 
        num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
        if (!num_names)
index c214ecf45400a1c7de02aacaf0d68b6495ae719e..e3f455bd85cd55c12ac8d561ef0793ba96ab8c4f 100644 (file)
@@ -135,7 +135,6 @@ out:        snd_card_free(card);
 static int snd_ad1848_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index d26545543732dab8b0805a97dbbcb9f40ba22b28..35659218710f93f1d738b327f4f43c650b8043cc 100644 (file)
@@ -101,7 +101,6 @@ out:        snd_card_free(card);
 static int snd_adlib_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index a7369fe19a6f045fdf5098ed93660f07997489c2..f84f073fc1e82db9738788f2d930d75993c98c2d 100644 (file)
@@ -418,7 +418,6 @@ static int snd_cmi8328_remove(struct device *pdev, unsigned int dev)
        snd_cmi8328_cfg_write(cmi->port, CFG2, 0);
        snd_cmi8328_cfg_write(cmi->port, CFG3, 0);
        snd_card_free(card);
-       dev_set_drvdata(pdev, NULL);
        return 0;
 }
 
index c707c52268ab44aed2d1165079e889c6470de344..270b9659ef7f703790a65531fc0205ddfead3c3a 100644 (file)
@@ -651,7 +651,6 @@ static int snd_cmi8330_isa_remove(struct device *devptr,
                                  unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index aa7a5d86e480412b1bb2da2411847e5d574d0880..ba9a74eff3e0dda98644dbe13df9cdb505e3043f 100644 (file)
@@ -151,7 +151,6 @@ out:        snd_card_free(card);
 static int snd_cs4231_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index 252e9fb37db34bc862627255e129f1f36f50ed86..69614acb20520678ea0c58c5dbfb5a4a74563772 100644 (file)
@@ -504,7 +504,6 @@ static int snd_cs423x_isa_remove(struct device *pdev,
                                 unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(pdev));
-       dev_set_drvdata(pdev, NULL);
        return 0;
 }
 
@@ -600,7 +599,6 @@ static int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
 static void snd_cs423x_pnp_remove(struct pnp_dev *pdev)
 {
        snd_card_free(pnp_get_drvdata(pdev));
-       pnp_set_drvdata(pdev, NULL);
 }
 
 #ifdef CONFIG_PM
index 102874a703d4cc8c53e98db88728215ef60cbec6..cdcfb57f1f0a94226d2f131d1005117c33766627 100644 (file)
@@ -213,7 +213,6 @@ out:
 static int snd_es1688_isa_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index 24380efe31a11099417f3422838f5854249cf286..12978b864c3ab52b8cc1388d24d15ead0fd4f690 100644 (file)
@@ -2235,7 +2235,6 @@ static int snd_es18xx_isa_remove(struct device *devptr,
                                 unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
@@ -2305,7 +2304,6 @@ static int snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
 static void snd_audiodrive_pnp_remove(struct pnp_dev *pdev)
 {
        snd_card_free(pnp_get_drvdata(pdev));
-       pnp_set_drvdata(pdev, NULL);
 }
 
 #ifdef CONFIG_PM
index 672184e3221a6e2765accc287c8e7b47596ff235..81244e7cea5be0d32d00cf14fe2a461432cd1082 100644 (file)
@@ -623,7 +623,6 @@ error:
 static int snd_galaxy_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index 16bca4e96c08a01d5af759c95626b7bcbcc53065..1adc1b924f39f4e3d3dc7a4d4414568a3cb10b7c 100644 (file)
@@ -215,7 +215,6 @@ out:        snd_card_free(card);
 static int snd_gusclassic_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index 0b9c2426b49f05608a3e0c099a9efdad20157cdf..38e1e3260c2453be6c07d0dfecdb48d5869bba78 100644 (file)
@@ -344,7 +344,6 @@ out:        snd_card_free(card);
 static int snd_gusextreme_remove(struct device *dev, unsigned int n)
 {
        snd_card_free(dev_get_drvdata(dev));
-       dev_set_drvdata(dev, NULL);
        return 0;
 }
 
index c309a5d0e7e12e0eba6a3fc8a4d1414aebf5408c..652d5d834620daa453caf9390b618e1fcc46afa6 100644 (file)
@@ -357,7 +357,6 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
 static int snd_gusmax_remove(struct device *devptr, unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 78bc5744e89a0cb66a34628916632186c8dd3029..9942691cc0ca9c101bfd830b134bc4e97bddb727 100644 (file)
@@ -849,7 +849,6 @@ static int snd_interwave_isa_probe(struct device *pdev,
 static int snd_interwave_isa_remove(struct device *devptr, unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index ddabb406b14cbacfe660678fe72326fab49bc15c..81aeb934261a26d2f2fca18060f21517b4650b32 100644 (file)
@@ -1064,7 +1064,6 @@ cfg_error:
 static int snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
 {
        snd_msnd_unload(dev_get_drvdata(pdev));
-       dev_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 075777a6cf0b3d165ff27d537eb48a9573d6b1f4..cc01c419b7e91931a1b61d0170d101256d9446fe 100644 (file)
@@ -757,7 +757,6 @@ static int snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
 static void snd_opl3sa2_pnp_remove(struct pnp_dev *pdev)
 {
        snd_card_free(pnp_get_drvdata(pdev));
-       pnp_set_drvdata(pdev, NULL);
 }
 
 #ifdef CONFIG_PM
@@ -900,7 +899,6 @@ static int snd_opl3sa2_isa_remove(struct device *devptr,
                                  unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index c3da1df9371df1c4c5cce4c6c00001906d270395..619753d96ca5e1cfbc51d4fd146cba5e9b520cfe 100644 (file)
@@ -1495,7 +1495,6 @@ static int snd_miro_isa_remove(struct device *devptr,
                               unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index b41ed8661b237abd41676cf2bed810686028e046..103b33373fd4d8e83233c7e08d2478b64302c840 100644 (file)
@@ -1035,7 +1035,6 @@ static int snd_opti9xx_isa_remove(struct device *devptr,
                                  unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 4961da4e627c24878c5cf0537cf70ffd90c8b221..356a6308392f29a19fabd4e670cafdac35cc3486 100644 (file)
@@ -345,7 +345,6 @@ static int snd_jazz16_remove(struct device *devptr, unsigned int dev)
 {
        struct snd_card *card = dev_get_drvdata(devptr);
 
-       dev_set_drvdata(devptr, NULL);
        snd_card_free(card);
        return 0;
 }
index 50dbec454f9872df065c54667d77e6ac1753f635..a4130993955f39d0781983c7f12060ba518c0770 100644 (file)
@@ -566,7 +566,6 @@ static int snd_sb16_isa_probe(struct device *pdev, unsigned int dev)
 static int snd_sb16_isa_remove(struct device *pdev, unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(pdev));
-       dev_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 237d964ff8a6bcd49a955ff266f19494d6fa3cec..a806ae90a9449246cd9b8a43ae6924f7439def21 100644 (file)
@@ -208,7 +208,6 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
 static int snd_sb8_remove(struct device *pdev, unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(pdev));
-       dev_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 5376ebff845ec4a091dfc38349b7d6c337633bad..09d481b3ba7fae52346ccdb273403e32c76e4862 100644 (file)
@@ -698,7 +698,6 @@ static int snd_sc6000_remove(struct device *devptr, unsigned int dev)
        release_region(port[dev], 0x10);
        release_region(mss_port[dev], 4);
 
-       dev_set_drvdata(devptr, NULL);
        snd_card_free(card);
        return 0;
 }
index 42a009720b29c2e89201e923b6160c4f3ed52136..57b338973ede0c99ff9b2b291761bc2d1dfa62c3 100644 (file)
@@ -1200,7 +1200,6 @@ _release_card:
 static int snd_sscape_remove(struct device *devptr, unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index fe5dd982bd2384a6e14fa837292f4f381b092352..82dd76939fa040b639f32cb33d072fecafd22239 100644 (file)
@@ -581,7 +581,6 @@ static int snd_wavefront_isa_remove(struct device *devptr,
                                    unsigned int dev)
 {
        snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
        return 0;
 }
 
index 2a44cc10645924820972e8a1cf90e00ac5881ab7..12be1fb512dd277a8df2f104ba11f91365c0033d 100644 (file)
@@ -178,7 +178,6 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 
 err_out_free:
-       pci_set_drvdata(pdev, NULL);
        kfree(hw_config);
        return 1;
 }
@@ -187,7 +186,6 @@ static void remove_one(struct pci_dev *pdev)
 {
        struct address_info *hw_config = pci_get_drvdata(pdev);
        sb_dsp_unload(hw_config, 0);
-       pci_set_drvdata(pdev, NULL);
        kfree(hw_config);
 }
 
index 0e66ba48d453fd9e81e431623320d8e86f3ad758..67f56a2cee6aec83bd4710f645a82cdca9e39847 100644 (file)
@@ -902,8 +902,6 @@ snd_harmony_free(struct snd_harmony *h)
        if (h->iobase)
                iounmap(h->iobase);
 
-       parisc_set_drvdata(h->dev, NULL);
-
        kfree(h);
        return 0;
 }
@@ -1016,7 +1014,6 @@ static int
 snd_harmony_remove(struct parisc_device *padev)
 {
        snd_card_free(parisc_get_drvdata(padev));
-       parisc_set_drvdata(padev, NULL);
        return 0;
 }
 
index d37c683cfd7a62125857ce9c5ca848a101afcefb..445ca481d8d30116bc075e3ac2cee881f1149863 100644 (file)
@@ -1296,7 +1296,7 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx,
                                    struct snd_ac97 *ac97)
 {
        int err;
-       char name[44];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        unsigned char lo_max, hi_max;
 
        if (! snd_ac97_valid_reg(ac97, reg))
index ad8a31173939d80a6738656579a2a88bd793ac86..d2b9d617aee52e1343a61e134e1c82f97db2c272 100644 (file)
@@ -1046,7 +1046,6 @@ static void
 snd_ad1889_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = {
index 53754f5edeb13062ddfc1cfb28e5d0e8179c1cb3..3dfa12b670ebfaf0a9ce5c04fed7710eea28b211 100644 (file)
@@ -2298,7 +2298,6 @@ static int snd_ali_probe(struct pci_dev *pci,
 static void snd_ali_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver ali5451_driver = {
index 864c4310366b4da41ad891ce829d0e2fc0a10300..591efb6eef05687a93ce4cd3b77a8a9134b6aa33 100644 (file)
@@ -282,7 +282,6 @@ static void snd_als300_remove(struct pci_dev *pci)
 {
        snd_als300_dbgcallenter();
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
        snd_als300_dbgcallleave();
 }
 
index 61efda2a4d949f56d4ace3b82daf1fe37dc4660b..ffc821b0139e9a3566ca56856667f443ba954d35 100644 (file)
@@ -984,7 +984,6 @@ out:
 static void snd_card_als4000_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index fbc17203613c05f874e765ae30df13f12add9324..185d54a5cb1af5765f2c2ae8f09af36f28f55de2 100644 (file)
@@ -1278,7 +1278,7 @@ struct hpi_control {
        u16 dst_node_type;
        u16 dst_node_index;
        u16 band;
-       char name[44]; /* copied to snd_ctl_elem_id.name[44]; */
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* copied to snd_ctl_elem_id.name[44]; */
 };
 
 static const char * const asihpi_tuner_band_names[] = {
index ef5019fe51930a7cedda5bc32949633d950dd878..7f0272032fbb2b25e8c8104523b41a7a5dc82f04 100644 (file)
@@ -445,7 +445,6 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
        if (pa->p_buffer)
                vfree(pa->p_buffer);
 
-       pci_set_drvdata(pci_dev, NULL);
        if (1)
                dev_info(&pci_dev->dev,
                         "remove %04x:%04x,%04x:%04x,%04x, HPI index %d\n",
index 6e78c6789858394b16c7c4543d4c30874602c978..fe4c61bdb8bac5764556bce3da8301653042d2c3 100644 (file)
@@ -1714,7 +1714,6 @@ static int snd_atiixp_probe(struct pci_dev *pci,
 static void snd_atiixp_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver atiixp_driver = {
index d0bec7ba3b0d8f3eb610807525e071ed53c4e220..cf29b9a1d65d71dbcc0608b1db89bef5273a199b 100644 (file)
@@ -1334,7 +1334,6 @@ static int snd_atiixp_probe(struct pci_dev *pci,
 static void snd_atiixp_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver atiixp_modem_driver = {
index b157e1fadd8fb3b014575cefe8e3f317bc3747f3..7059dd69e5e611598530edf8ba6b6beba7a16050 100644 (file)
@@ -371,7 +371,6 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 static void snd_vortex_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 // pci_driver definition
index 08e9a4702cbc4cafcd34a9d52c2219da0c6ca441..2925220d3fcf84afdd27c0636b5b1939cd087f3f 100644 (file)
@@ -392,7 +392,6 @@ static int snd_aw2_probe(struct pci_dev *pci,
 static void snd_aw2_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 /* open callback */
index 1204a0fa336889c0bc92600496520e2b07961b20..c8e1216115936015a73e67df84e2c83ecc0d1975 100644 (file)
@@ -2725,7 +2725,6 @@ snd_azf3328_remove(struct pci_dev *pci)
 {
        snd_azf3328_dbgcallenter();
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
        snd_azf3328_dbgcallleave();
 }
 
index 9febe5509748ed5a1cdc2556d441ff770f31f8ea..18802039497afd3dfcafdd53dd1d0d62e503c4cc 100644 (file)
@@ -953,7 +953,6 @@ _error:
 static void snd_bt87x_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 /* default entries for all Bt87x cards - it's not exported */
index 1610a5705970790973d0eecdd6b34d36c1d4506b..f4db5587e86ee9b3f509d1541b9ae85c0a64cbab 100644 (file)
@@ -1896,7 +1896,6 @@ static int snd_ca0106_probe(struct pci_dev *pci,
 static void snd_ca0106_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index c617435db6e6532a1caad658a4cb7773bc252d2a..2755ec5bcc258d695d534f3ca99d895218c49215 100644 (file)
@@ -3317,7 +3317,6 @@ static int snd_cmipci_probe(struct pci_dev *pci,
 static void snd_cmipci_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 
index 6a86950699415527261c4d938bbe7cfaca328010..1dc793e742d79845b3e92d6da1ac204f971a6ef8 100644 (file)
@@ -1312,7 +1312,7 @@ static int snd_cs4281_free(struct cs4281 *chip)
        /* Sound System Power Management - Turn Everything OFF */
        snd_cs4281_pokeBA0(chip, BA0_SSPM, 0);
        /* PCI interface - D3 state */
-       pci_set_power_state(chip->pci, 3);
+       pci_set_power_state(chip->pci, PCI_D3hot);
 
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
@@ -1971,7 +1971,6 @@ static int snd_cs4281_probe(struct pci_dev *pci,
 static void snd_cs4281_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 /*
index 6b0d8b50a305d4a632f6702a7a445c2febdc3733..b03498325d661d091ca18d84614fdebd1fb22032 100644 (file)
@@ -158,7 +158,6 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
 static void snd_card_cs46xx_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver cs46xx_driver = {
index dace827b45d1390401b2f8ae7a0a1fa78cfc0cb8..c6b82c85e044b9eec35e212f2dc487452651430e 100644 (file)
@@ -91,7 +91,6 @@ static int snd_cs5530_dev_free(struct snd_device *device)
 static void snd_cs5530_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg)
index 7e4b13e2d12aa84d89e7532f23a9b5053f8c1b2c..902bebd3b3fb6d660a9d5f00ddca921c149a7009 100644 (file)
@@ -391,7 +391,6 @@ static void snd_cs5535audio_remove(struct pci_dev *pci)
 {
        olpc_quirks_cleanup();
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver cs5535audio_driver = {
index d01ffcb2b2f5f823033869f24faf1a12b7cc70df..d464ad2fc7b71632afd81df4ef0e3ea4dda265f2 100644 (file)
@@ -122,7 +122,6 @@ error:
 static void ct_card_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index 760cbff532105f3bf56485082a43f0e6177fbad9..05cfe551ce425b6d4049755688d6d76883e768c8 100644 (file)
@@ -2323,7 +2323,6 @@ static void snd_echo_remove(struct pci_dev *pci)
        chip = pci_get_drvdata(pci);
        if (chip)
                snd_card_free(chip->card);
-       pci_set_drvdata(pci, NULL);
 }
 
 
index 8c5010f7889cbd57192cfaa03d77972f7522aded..9e1bd0c39a8cf27230bd50196a525d1c2c3f525d 100644 (file)
@@ -202,7 +202,6 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
 static void snd_card_emu10k1_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 
index cdff11d48ebd5b4316584552ca7191e4ee7aee97..56ad9d6f200df7daa7de21fea6d7d59ef502c881 100644 (file)
@@ -1623,7 +1623,6 @@ static int snd_emu10k1x_probe(struct pci_dev *pci,
 static void snd_emu10k1x_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 // PCI IDs
index db2dc835171d2a6bf9ee8d4468ca6e54911b06c2..ca8929b9a5d65ce3b89421cd03f83e432203ef89 100644 (file)
@@ -1939,7 +1939,7 @@ static int snd_ensoniq_free(struct ensoniq *ensoniq)
 #endif
        if (ensoniq->irq >= 0)
                synchronize_irq(ensoniq->irq);
-       pci_set_power_state(ensoniq->pci, 3);
+       pci_set_power_state(ensoniq->pci, PCI_D3hot);
       __hw_end:
 #ifdef CHIP1370
        if (ensoniq->dma_bug.area)
@@ -2497,7 +2497,6 @@ static int snd_audiopci_probe(struct pci_dev *pci,
 static void snd_audiopci_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver ens137x_driver = {
index 8423403954abfae68b01ab7a96e93f0e025d1628..9213fb38921c6b7687bfaaa262c6c3b3de0a09d3 100644 (file)
@@ -1881,7 +1881,6 @@ static int snd_es1938_probe(struct pci_dev *pci,
 static void snd_es1938_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver es1938_driver = {
index a1f32b5ae0d1b4131a7ba7b9a8d2366bfd959e3d..5e2ec9687731119d80ebc5994b2bdb8fcec06c0d 100644 (file)
@@ -564,6 +564,7 @@ struct es1968 {
 #ifdef CONFIG_SND_ES1968_RADIO
        struct v4l2_device v4l2_dev;
        struct snd_tea575x tea;
+       unsigned int tea575x_tuner;
 #endif
 };
 
@@ -2557,37 +2558,47 @@ static int snd_es1968_input_register(struct es1968 *chip)
                                bits 1=unmask write to given bit */
 #define IO_DIR         8      /* direction register offset from GPIO_DATA
                                bits 0/1=read/write direction */
-/* mask bits for GPIO lines */
-#define STR_DATA       0x0040 /* GPIO6 */
-#define STR_CLK                0x0080 /* GPIO7 */
-#define STR_WREN       0x0100 /* GPIO8 */
-#define STR_MOST       0x0200 /* GPIO9 */
+
+/* GPIO to TEA575x maps */
+struct snd_es1968_tea575x_gpio {
+       u8 data, clk, wren, most;
+       char *name;
+};
+
+static struct snd_es1968_tea575x_gpio snd_es1968_tea575x_gpios[] = {
+       { .data = 6, .clk = 7, .wren = 8, .most = 9, .name = "SF64-PCE2" },
+       { .data = 7, .clk = 8, .wren = 6, .most = 10, .name = "M56VAP" },
+};
+
+#define get_tea575x_gpio(chip) \
+       (&snd_es1968_tea575x_gpios[(chip)->tea575x_tuner])
+
 
 static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
 {
        struct es1968 *chip = tea->private_data;
-       unsigned long io = chip->io_port + GPIO_DATA;
+       struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
        u16 val = 0;
 
-       val |= (pins & TEA575X_DATA) ? STR_DATA : 0;
-       val |= (pins & TEA575X_CLK)  ? STR_CLK  : 0;
-       val |= (pins & TEA575X_WREN) ? STR_WREN : 0;
+       val |= (pins & TEA575X_DATA) ? (1 << gpio.data) : 0;
+       val |= (pins & TEA575X_CLK)  ? (1 << gpio.clk)  : 0;
+       val |= (pins & TEA575X_WREN) ? (1 << gpio.wren) : 0;
 
-       outw(val, io);
+       outw(val, chip->io_port + GPIO_DATA);
 }
 
 static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea)
 {
        struct es1968 *chip = tea->private_data;
-       unsigned long io = chip->io_port + GPIO_DATA;
-       u16 val = inw(io);
-       u8 ret;
+       struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
+       u16 val = inw(chip->io_port + GPIO_DATA);
+       u8 ret = 0;
 
-       ret = 0;
-       if (val & STR_DATA)
+       if (val & (1 << gpio.data))
                ret |= TEA575X_DATA;
-       if (val & STR_MOST)
+       if (val & (1 << gpio.most))
                ret |= TEA575X_MOST;
+
        return ret;
 }
 
@@ -2596,13 +2607,18 @@ static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool outpu
        struct es1968 *chip = tea->private_data;
        unsigned long io = chip->io_port + GPIO_DATA;
        u16 odir = inw(io + IO_DIR);
+       struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip);
 
        if (output) {
-               outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
-               outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR);
+               outw(~((1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren)),
+                       io + IO_MASK);
+               outw(odir | (1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren),
+                       io + IO_DIR);
        } else {
-               outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK);
-               outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR);
+               outw(~((1 << gpio.clk) | (1 << gpio.wren) | (1 << gpio.data) | (1 << gpio.most)),
+                       io + IO_MASK);
+               outw((odir & ~((1 << gpio.data) | (1 << gpio.most)))
+                       | (1 << gpio.clk) | (1 << gpio.wren), io + IO_DIR);
        }
 }
 
@@ -2772,6 +2788,9 @@ static int snd_es1968_create(struct snd_card *card,
        snd_card_set_dev(card, &pci->dev);
 
 #ifdef CONFIG_SND_ES1968_RADIO
+       /* don't play with GPIOs on laptops */
+       if (chip->pci->subsystem_vendor != 0x125d)
+               goto no_radio;
        err = v4l2_device_register(&pci->dev, &chip->v4l2_dev);
        if (err < 0) {
                snd_es1968_free(chip);
@@ -2781,10 +2800,18 @@ static int snd_es1968_create(struct snd_card *card,
        chip->tea.private_data = chip;
        chip->tea.radio_nr = radio_nr;
        chip->tea.ops = &snd_es1968_tea_ops;
-       strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card));
        sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci));
-       if (!snd_tea575x_init(&chip->tea, THIS_MODULE))
-               printk(KERN_INFO "es1968: detected TEA575x radio\n");
+       for (i = 0; i < ARRAY_SIZE(snd_es1968_tea575x_gpios); i++) {
+               chip->tea575x_tuner = i;
+               if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) {
+                       snd_printk(KERN_INFO "es1968: detected TEA575x radio type %s\n",
+                                  get_tea575x_gpio(chip)->name);
+                       strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name,
+                               sizeof(chip->tea.card));
+                       break;
+               }
+       }
+no_radio:
 #endif
 
        *chip_ret = chip;
@@ -2909,7 +2936,6 @@ static int snd_es1968_probe(struct pci_dev *pci,
 static void snd_es1968_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver es1968_driver = {
index 4f07fda5adf2cc534d2e52a4c2577ea666c2bd39..706c5b67b708e441dbd6d768c5698effd8d9e570 100644 (file)
@@ -1370,7 +1370,6 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
 static void snd_card_fm801_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index 80a7d44bcf81f38780776fa5abb0eb2f8f35087b..0c5371abecd256ab9467a02378266fa902267c2c 100644 (file)
@@ -140,7 +140,6 @@ config SND_HDA_CODEC_VIA
 
 config SND_HDA_CODEC_HDMI
        bool "Build HDMI/DisplayPort HD-audio codec support"
-       select SND_DYNAMIC_MINORS
        default y
        help
          Say Y here to include HDMI and DisplayPort HD-audio codec
index 55108b5fb2919c597177d9dc5f28b56cb34d28a2..35090b3acbaca242f63064de691c30647110c6c1 100644 (file)
@@ -185,20 +185,19 @@ EXPORT_SYMBOL_HDA(snd_hda_get_jack_type);
  * Compose a 32bit command word to be sent to the HD-audio controller
  */
 static inline unsigned int
-make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int flags,
               unsigned int verb, unsigned int parm)
 {
        u32 val;
 
-       if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) ||
+       if ((codec->addr & ~0xf) || (nid & ~0x7f) ||
            (verb & ~0xfff) || (parm & ~0xffff)) {
-               printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n",
-                      codec->addr, direct, nid, verb, parm);
+               printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x\n",
+                      codec->addr, nid, verb, parm);
                return ~0;
        }
 
        val = (u32)codec->addr << 28;
-       val |= (u32)direct << 27;
        val |= (u32)nid << 20;
        val |= verb << 8;
        val |= parm;
@@ -209,7 +208,7 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
  * Send and receive a verb
  */
 static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
-                          unsigned int *res)
+                          int flags, unsigned int *res)
 {
        struct hda_bus *bus = codec->bus;
        int err;
@@ -222,6 +221,8 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
  again:
        snd_hda_power_up(codec);
        mutex_lock(&bus->cmd_mutex);
+       if (flags & HDA_RW_NO_RESPONSE_FALLBACK)
+               bus->no_response_fallback = 1;
        for (;;) {
                trace_hda_send_cmd(codec, cmd);
                err = bus->ops.command(bus, cmd);
@@ -234,6 +235,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
                *res = bus->ops.get_response(bus, codec->addr);
                trace_hda_get_response(codec, *res);
        }
+       bus->no_response_fallback = 0;
        mutex_unlock(&bus->cmd_mutex);
        snd_hda_power_down(codec);
        if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) {
@@ -255,7 +257,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
  * snd_hda_codec_read - send a command and get the response
  * @codec: the HDA codec
  * @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
  * @verb: the verb to send
  * @parm: the parameter for the verb
  *
@@ -264,12 +266,12 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
  * Returns the obtained response value, or -1 for an error.
  */
 unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
-                               int direct,
+                               int flags,
                                unsigned int verb, unsigned int parm)
 {
-       unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm);
+       unsigned cmd = make_codec_cmd(codec, nid, flags, verb, parm);
        unsigned int res;
-       if (codec_exec_verb(codec, cmd, &res))
+       if (codec_exec_verb(codec, cmd, flags, &res))
                return -1;
        return res;
 }
@@ -279,7 +281,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read);
  * snd_hda_codec_write - send a single command without waiting for response
  * @codec: the HDA codec
  * @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
  * @verb: the verb to send
  * @parm: the parameter for the verb
  *
@@ -287,12 +289,12 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read);
  *
  * Returns 0 if successful, or a negative error code.
  */
-int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
-                        unsigned int verb, unsigned int parm)
+int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
+                       unsigned int verb, unsigned int parm)
 {
-       unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm);
+       unsigned int cmd = make_codec_cmd(codec, nid, flags, verb, parm);
        unsigned int res;
-       return codec_exec_verb(codec, cmd,
+       return codec_exec_verb(codec, cmd, flags,
                               codec->bus->sync_write ? &res : NULL);
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write);
@@ -3582,7 +3584,7 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
  * snd_hda_codec_write_cache - send a single command with caching
  * @codec: the HDA codec
  * @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
  * @verb: the verb to send
  * @parm: the parameter for the verb
  *
@@ -3591,7 +3593,7 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
  * Returns 0 if successful, or a negative error code.
  */
 int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
-                             int direct, unsigned int verb, unsigned int parm)
+                             int flags, unsigned int verb, unsigned int parm)
 {
        int err;
        struct hda_cache_head *c;
@@ -3600,7 +3602,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
 
        cache_only = codec->cached_write;
        if (!cache_only) {
-               err = snd_hda_codec_write(codec, nid, direct, verb, parm);
+               err = snd_hda_codec_write(codec, nid, flags, verb, parm);
                if (err < 0)
                        return err;
        }
@@ -3624,7 +3626,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
  * snd_hda_codec_update_cache - check cache and write the cmd only when needed
  * @codec: the HDA codec
  * @nid: NID to send the command
- * @direct: direct flag
+ * @flags: optional bit flags
  * @verb: the verb to send
  * @parm: the parameter for the verb
  *
@@ -3635,7 +3637,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
  * Returns 0 if successful, or a negative error code.
  */
 int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
-                              int direct, unsigned int verb, unsigned int parm)
+                              int flags, unsigned int verb, unsigned int parm)
 {
        struct hda_cache_head *c;
        u32 key;
@@ -3651,7 +3653,7 @@ int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
                return 0;
        }
        mutex_unlock(&codec->bus->cmd_mutex);
-       return snd_hda_codec_write_cache(codec, nid, direct, verb, parm);
+       return snd_hda_codec_write_cache(codec, nid, flags, verb, parm);
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache);
 
@@ -3806,11 +3808,13 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
        hda_nid_t fg = codec->afg ? codec->afg : codec->mfg;
        int count;
        unsigned int state;
+       int flags = 0;
 
        /* this delay seems necessary to avoid click noise at power-down */
        if (power_state == AC_PWRST_D3) {
                /* transition time less than 10ms for power down */
                msleep(codec->epss ? 10 : 100);
+               flags = HDA_RW_NO_RESPONSE_FALLBACK;
        }
 
        /* repeat power states setting at most 10 times*/
@@ -3819,7 +3823,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
                        codec->patch_ops.set_power_state(codec, fg,
                                                         power_state);
                else {
-                       snd_hda_codec_read(codec, fg, 0,
+                       snd_hda_codec_read(codec, fg, flags,
                                           AC_VERB_SET_POWER_STATE,
                                           power_state);
                        snd_hda_codec_set_power_to_all(codec, fg, power_state);
@@ -4461,12 +4465,13 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {
 
 /*
  * get the empty PCM device number to assign
- *
- * note the max device number is limited by HDA_MAX_PCMS, currently 10
  */
-static int get_empty_pcm_device(struct hda_bus *bus, int type)
+static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
 {
        /* audio device indices; not linear to keep compatibility */
+       /* assigned to static slots up to dev#10; if more needed, assign
+        * the later slot dynamically (when CONFIG_SND_DYNAMIC_MINORS=y)
+        */
        static int audio_idx[HDA_PCM_NTYPES][5] = {
                [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 },
                [HDA_PCM_TYPE_SPDIF] = { 1, -1 },
@@ -4480,18 +4485,28 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
                return -EINVAL;
        }
 
-       for (i = 0; audio_idx[type][i] >= 0 ; i++)
+       for (i = 0; audio_idx[type][i] >= 0; i++) {
+#ifndef CONFIG_SND_DYNAMIC_MINORS
+               if (audio_idx[type][i] >= 8)
+                       break;
+#endif
                if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits))
                        return audio_idx[type][i];
+       }
 
+#ifdef CONFIG_SND_DYNAMIC_MINORS
        /* non-fixed slots starting from 10 */
        for (i = 10; i < 32; i++) {
                if (!test_and_set_bit(i, bus->pcm_dev_bits))
                        return i;
        }
+#endif
 
        snd_printk(KERN_WARNING "Too many %s devices\n",
                snd_hda_pcm_type_name[type]);
+#ifndef CONFIG_SND_DYNAMIC_MINORS
+       snd_printk(KERN_WARNING "Consider building the kernel with CONFIG_SND_DYNAMIC_MINORS=y\n");
+#endif
        return -EAGAIN;
 }
 
index c93f9021f45212d523e8928db45bcef6f65c4576..701c2e069b10ad218886f5853caa1c5c3e31409c 100644 (file)
@@ -679,6 +679,7 @@ struct hda_bus {
        unsigned int response_reset:1;  /* controller was reset */
        unsigned int in_reset:1;        /* during reset operation */
        unsigned int power_keep_link_on:1; /* don't power off HDA link */
+       unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
 
        int primary_dig_out_type;       /* primary digital out PCM type */
 };
@@ -930,6 +931,8 @@ enum {
        HDA_INPUT, HDA_OUTPUT
 };
 
+/* snd_hda_codec_read/write optional flags */
+#define HDA_RW_NO_RESPONSE_FALLBACK    (1 << 0)
 
 /*
  * constructors
@@ -945,9 +948,9 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec);
  * low level functions
  */
 unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
-                               int direct,
+                               int flags,
                                unsigned int verb, unsigned int parm);
-int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
+int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
                        unsigned int verb, unsigned int parm);
 #define snd_hda_param_read(codec, nid, param) \
        snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param)
@@ -986,11 +989,11 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
 
 /* cached write */
 int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
-                             int direct, unsigned int verb, unsigned int parm);
+                             int flags, unsigned int verb, unsigned int parm);
 void snd_hda_sequence_write_cache(struct hda_codec *codec,
                                  const struct hda_verb *seq);
 int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
-                             int direct, unsigned int verb, unsigned int parm);
+                             int flags, unsigned int verb, unsigned int parm);
 void snd_hda_codec_resume_cache(struct hda_codec *codec);
 /* both for cmd & amp caches */
 void snd_hda_codec_flush_cache(struct hda_codec *codec);
index 4b1524a861f38e2aee10d8bd39bf3352d82ed0b8..8e77cbbad871dd4ff10263824d016487b1479813 100644 (file)
@@ -133,6 +133,9 @@ static void parse_user_hints(struct hda_codec *codec)
        val = snd_hda_get_bool_hint(codec, "line_in_auto_switch");
        if (val >= 0)
                spec->line_in_auto_switch = !!val;
+       val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp");
+       if (val >= 0)
+               spec->auto_mute_via_amp = !!val;
        val = snd_hda_get_bool_hint(codec, "need_dac_fix");
        if (val >= 0)
                spec->need_dac_fix = !!val;
@@ -808,6 +811,9 @@ static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
  * Helper functions for creating mixer ctl elements
  */
 
+static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol);
+
 enum {
        HDA_CTL_WIDGET_VOL,
        HDA_CTL_WIDGET_MUTE,
@@ -815,7 +821,15 @@ enum {
 };
 static const struct snd_kcontrol_new control_templates[] = {
        HDA_CODEC_VOLUME(NULL, 0, 0, 0),
-       HDA_CODEC_MUTE(NULL, 0, 0, 0),
+       /* only the put callback is replaced for handling the special mute */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = hda_gen_mixer_mute_put, /* replaced */
+               .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
+       },
        HDA_BIND_MUTE(NULL, 0, 0, 0),
 };
 
@@ -840,7 +854,7 @@ static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
                                const char *pfx, const char *dir,
                                const char *sfx, int cidx, unsigned long val)
 {
-       char name[32];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
        if (!add_control(spec, type, name, cidx, val))
                return -ENOMEM;
@@ -922,6 +936,23 @@ static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
        return add_sw_ctl(codec, pfx, cidx, chs, path);
 }
 
+/* playback mute control with the software mute bit check */
+static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (spec->auto_mute_via_amp) {
+               hda_nid_t nid = get_amp_nid(kcontrol);
+               bool enabled = !((spec->mute_bits >> nid) & 1);
+               ucontrol->value.integer.value[0] &= enabled;
+               ucontrol->value.integer.value[1] &= enabled;
+       }
+
+       return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+}
+
 /* any ctl assigned to the path with the given index? */
 static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
 {
@@ -1900,7 +1931,7 @@ static int create_extra_outs(struct hda_codec *codec, int num_pins,
 
        for (i = 0; i < num_pins; i++) {
                const char *name;
-               char tmp[44];
+               char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
                int err, idx = 0;
 
                if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker"))
@@ -2453,7 +2484,7 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
                }
                if (get_out_jack_num_items(codec, pin) > 1) {
                        struct snd_kcontrol_new *knew;
-                       char name[44];
+                       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
                        get_jack_mode_name(codec, pin, name, sizeof(name));
                        knew = snd_hda_gen_add_kctl(spec, name,
                                                    &out_jack_mode_enum);
@@ -2585,7 +2616,7 @@ static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
 {
        struct hda_gen_spec *spec = codec->spec;
        struct snd_kcontrol_new *knew;
-       char name[44];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        unsigned int defcfg;
 
        if (pin == spec->hp_mic_pin)
@@ -3285,7 +3316,7 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
                              bool inv_dmic)
 {
        struct hda_gen_spec *spec = codec->spec;
-       char tmpname[44];
+       char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
        const char *sfx = is_switch ? "Switch" : "Volume";
        unsigned int chs = inv_dmic ? 1 : 3;
@@ -3547,7 +3578,7 @@ static int parse_mic_boost(struct hda_codec *codec)
                struct nid_path *path;
                unsigned int val;
                int idx;
-               char boost_label[44];
+               char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
 
                idx = imux->items[i].index;
                if (idx >= imux->num_items)
@@ -3719,6 +3750,16 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
                unsigned int val, oldval;
                if (!nid)
                        break;
+
+               if (spec->auto_mute_via_amp) {
+                       if (mute)
+                               spec->mute_bits |= (1ULL << nid);
+                       else
+                               spec->mute_bits &= ~(1ULL << nid);
+                       set_pin_eapd(codec, nid, !mute);
+                       continue;
+               }
+
                oldval = snd_hda_codec_get_pin_target(codec, nid);
                if (oldval & PIN_IN)
                        continue; /* no mute for inputs */
@@ -3786,6 +3827,10 @@ static void call_update_outputs(struct hda_codec *codec)
                spec->automute_hook(codec);
        else
                snd_hda_gen_update_outputs(codec);
+
+       /* sync the whole vmaster slaves to reflect the new auto-mute status */
+       if (spec->auto_mute_via_amp && !codec->bus->shutdown)
+               snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
 }
 
 /* standard HP-automute helper */
index 76200314ee9566e89cf97fa6ff2821d91de37cea..e199a852388b4506148b0cfcbcca7ee380406a52 100644 (file)
@@ -209,6 +209,7 @@ struct hda_gen_spec {
        unsigned int master_mute:1;     /* master mute over all */
        unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
        unsigned int line_in_auto_switch:1; /* allow line-in auto switch */
+       unsigned int auto_mute_via_amp:1; /* auto-mute via amp instead of pinctl */
 
        /* parser behavior flags; set before snd_hda_gen_parse_auto_config() */
        unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */
@@ -237,6 +238,9 @@ struct hda_gen_spec {
        unsigned int have_aamix_ctl:1;
        unsigned int hp_mic_jack_modes:1;
 
+       /* additional mute flags (only effective with auto_mute_via_amp=1) */
+       u64 mute_bits;
+
        /* badness tables for output path evaluations */
        const struct badness_table *main_out_badness;
        const struct badness_table *extra_out_badness;
index de18722c487346858783fa5d5e9f9fd574b70b39..f39de9055097979f93efa3a05a630b8ffa945107 100644 (file)
@@ -942,6 +942,9 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
                }
        }
 
+       if (!bus->no_response_fallback)
+               return -1;
+
        if (!chip->polling_mode && chip->poll_count < 2) {
                snd_printdd(SFX "%s: azx_get_response timeout, "
                           "polling the codec once: last cmd=0x%08x\n",
@@ -1117,37 +1120,52 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
                                 struct snd_dma_buffer *dmab);
 #endif
 
-/* reset codec link */
-static int azx_reset(struct azx *chip, int full_reset)
+/* enter link reset */
+static void azx_enter_link_reset(struct azx *chip)
 {
        unsigned long timeout;
 
-       if (!full_reset)
-               goto __skip;
-
-       /* clear STATESTS */
-       azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
-
        /* reset controller */
        azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET);
 
        timeout = jiffies + msecs_to_jiffies(100);
-       while (azx_readb(chip, GCTL) &&
+       while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) &&
                        time_before(jiffies, timeout))
                usleep_range(500, 1000);
+}
 
-       /* delay for >= 100us for codec PLL to settle per spec
-        * Rev 0.9 section 5.5.1
-        */
-       usleep_range(500, 1000);
+/* exit link reset */
+static void azx_exit_link_reset(struct azx *chip)
+{
+       unsigned long timeout;
 
-       /* Bring controller out of reset */
        azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET);
 
        timeout = jiffies + msecs_to_jiffies(100);
        while (!azx_readb(chip, GCTL) &&
                        time_before(jiffies, timeout))
                usleep_range(500, 1000);
+}
+
+/* reset codec link */
+static int azx_reset(struct azx *chip, int full_reset)
+{
+       if (!full_reset)
+               goto __skip;
+
+       /* clear STATESTS */
+       azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+
+       /* reset controller */
+       azx_enter_link_reset(chip);
+
+       /* delay for >= 100us for codec PLL to settle per spec
+        * Rev 0.9 section 5.5.1
+        */
+       usleep_range(500, 1000);
+
+       /* Bring controller out of reset */
+       azx_exit_link_reset(chip);
 
        /* Brent Chartrand said to wait >= 540us for codecs to initialize */
        usleep_range(1000, 1200);
@@ -2891,6 +2909,7 @@ static int azx_suspend(struct device *dev)
        if (chip->initialized)
                snd_hda_suspend(chip->bus);
        azx_stop_chip(chip);
+       azx_enter_link_reset(chip);
        if (chip->irq >= 0) {
                free_irq(chip->irq, chip);
                chip->irq = -1;
@@ -2943,6 +2962,7 @@ static int azx_runtime_suspend(struct device *dev)
        struct azx *chip = card->private_data;
 
        azx_stop_chip(chip);
+       azx_enter_link_reset(chip);
        azx_clear_irq_pending(chip);
        return 0;
 }
@@ -3764,7 +3784,6 @@ static int azx_probe(struct pci_dev *pci,
 
 out_free:
        snd_card_free(card);
-       pci_set_drvdata(pci, NULL);
        return err;
 }
 
@@ -3834,7 +3853,6 @@ static void azx_remove(struct pci_dev *pci)
 
        if (card)
                snd_card_free(card);
-       pci_set_drvdata(pci, NULL);
 }
 
 /* PCI IDs */
@@ -3878,6 +3896,9 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* Oaktrail */
        { PCI_DEVICE(0x8086, 0x080a),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+       /* BayTrail */
+       { PCI_DEVICE(0x8086, 0x0f04),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* ICH */
        { PCI_DEVICE(0x8086, 0x2668),
          .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
index 9e0a95288f46fcca24fa0944fc99cd134e0d7c2e..3fd2973183e2dda266a78c00a96bc5517b5bb29f 100644 (file)
@@ -398,7 +398,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
                         const char *base_name)
 {
        unsigned int def_conf, conn;
-       char name[44];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int idx, err;
        bool phantom_jack;
 
index e0bf7534fa1f410c28986e5cb0d0be4ee03e1442..2e7493ef8ee0643b1ee51b759198c233d23af6a5 100644 (file)
@@ -562,6 +562,14 @@ static inline unsigned int get_wcaps_channels(u32 wcaps)
        return chans;
 }
 
+static inline void snd_hda_override_wcaps(struct hda_codec *codec,
+                                         hda_nid_t nid, u32 val)
+{
+       if (nid >= codec->start_nid &&
+           nid < codec->start_nid + codec->num_nodes)
+               codec->wcaps[nid - codec->start_nid] = val;
+}
+
 u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction);
 int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
                              unsigned int caps);
@@ -667,7 +675,7 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid,
        if (state & AC_PWRST_ERROR)
                return true;
        state = (state >> 4) & 0x0f;
-       return (state != target_state);
+       return (state == target_state);
 }
 
 unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
index 0fee8fae590a35b1f6535fc88763a1739c3dda2d..9760f001916d8c72add740db2314793a3e027318 100644 (file)
@@ -504,6 +504,8 @@ static void print_conn_list(struct snd_info_buffer *buffer,
                            int conn_len)
 {
        int c, curr = -1;
+       const hda_nid_t *list;
+       int cache_len;
 
        if (conn_len > 1 &&
            wid_type != AC_WID_AUD_MIX &&
@@ -521,6 +523,19 @@ static void print_conn_list(struct snd_info_buffer *buffer,
                }
                snd_iprintf(buffer, "\n");
        }
+
+       /* Get Cache connections info */
+       cache_len = snd_hda_get_conn_list(codec, nid, &list);
+       if (cache_len != conn_len
+                       || memcmp(list, conn, conn_len)) {
+               snd_iprintf(buffer, "  In-driver Connection: %d\n", cache_len);
+               if (cache_len > 0) {
+                       snd_iprintf(buffer, "    ");
+                       for (c = 0; c < cache_len; c++)
+                               snd_iprintf(buffer, " 0x%02x", list[c]);
+                       snd_iprintf(buffer, "\n");
+               }
+       }
 }
 
 static void print_gpio(struct snd_info_buffer *buffer,
index 90ff7a3f72dff8de71a4b1fa0a338d00e8579006..6e9876f27d959a64e14443ceab5efaed9f11d44b 100644 (file)
@@ -139,7 +139,7 @@ enum {
 #define DSP_SPEAKER_OUT_LATENCY         7
 
 struct ct_effect {
-       char name[44];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        hda_nid_t nid;
        int mid; /*effect module ID*/
        int reqs[EFFECT_VALS_MAX_COUNT]; /*effect module request*/
@@ -270,7 +270,7 @@ enum {
 };
 
 struct ct_tuning_ctl {
-       char name[44];
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        hda_nid_t parent_nid;
        hda_nid_t nid;
        int mid; /*effect module ID*/
@@ -3103,7 +3103,7 @@ static int add_tuning_control(struct hda_codec *codec,
                                hda_nid_t pnid, hda_nid_t nid,
                                const char *name, int dir)
 {
-       char namestr[44];
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int type = dir ? HDA_INPUT : HDA_OUTPUT;
        struct snd_kcontrol_new knew =
                HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type);
@@ -3935,7 +3935,7 @@ static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
                         const char *pfx, int dir)
 {
-       char namestr[44];
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
        int type = dir ? HDA_INPUT : HDA_OUTPUT;
        struct snd_kcontrol_new knew =
                CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type);
index b314d3e6d7fae5d0a576ccbe14eb45c54dfde2f9..de00ce166470d5c73ac646c452f8a3ccd86e717a 100644 (file)
@@ -2947,7 +2947,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
-       SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
        {}
@@ -3318,6 +3317,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
index e12f7a030c58efae2c5a93829ec6bfce1fb17ac7..540bdef2f9040dc8276cee974429065c5121e63f 100644 (file)
@@ -1018,13 +1018,18 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
                hdmi_non_intrinsic_event(codec, res);
 }
 
-static void haswell_verify_pin_D0(struct hda_codec *codec, hda_nid_t nid)
+static void haswell_verify_pin_D0(struct hda_codec *codec,
+               hda_nid_t cvt_nid, hda_nid_t nid)
 {
        int pwr, lamp, ramp;
 
-       pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
-       pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
-       if (pwr != AC_PWRST_D0) {
+       /* For Haswell, the converter 1/2 may keep in D3 state after bootup,
+        * thus pins could only choose converter 0 for use. Make sure the
+        * converters are in correct power state */
+       if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0))
+               snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+       if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) {
                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
                                    AC_PWRST_D0);
                msleep(40);
@@ -1068,7 +1073,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
        int new_pinctl = 0;
 
        if (codec->vendor_id == 0x80862807)
-               haswell_verify_pin_D0(codec, pin_nid);
+               haswell_verify_pin_D0(codec, cvt_nid, pin_nid);
 
        if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
                pinctl = snd_hda_codec_read(codec, pin_nid, 0,
@@ -1101,26 +1106,15 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
        return 0;
 }
 
-/*
- * HDA PCM callbacks
- */
-static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
-                        struct hda_codec *codec,
-                        struct snd_pcm_substream *substream)
+static int hdmi_choose_cvt(struct hda_codec *codec,
+                       int pin_idx, int *cvt_id, int *mux_id)
 {
        struct hdmi_spec *spec = codec->spec;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int pin_idx, cvt_idx, mux_idx = 0;
        struct hdmi_spec_per_pin *per_pin;
-       struct hdmi_eld *eld;
        struct hdmi_spec_per_cvt *per_cvt = NULL;
+       int cvt_idx, mux_idx = 0;
 
-       /* Validate hinfo */
-       pin_idx = hinfo_to_pin_index(spec, hinfo);
-       if (snd_BUG_ON(pin_idx < 0))
-               return -EINVAL;
        per_pin = get_pin(spec, pin_idx);
-       eld = &per_pin->sink_eld;
 
        /* Dynamically assign converter to stream */
        for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
@@ -1138,17 +1132,89 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
                        continue;
                break;
        }
+
        /* No free converters */
        if (cvt_idx == spec->num_cvts)
                return -ENODEV;
 
+       if (cvt_id)
+               *cvt_id = cvt_idx;
+       if (mux_id)
+               *mux_id = mux_idx;
+
+       return 0;
+}
+
+static void haswell_config_cvts(struct hda_codec *codec,
+                       int pin_id, int mux_id)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin;
+       int pin_idx, mux_idx;
+       int curr;
+       int err;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               per_pin = get_pin(spec, pin_idx);
+
+               if (pin_idx == pin_id)
+                       continue;
+
+               curr = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+                                         AC_VERB_GET_CONNECT_SEL, 0);
+
+               /* Choose another unused converter */
+               if (curr == mux_id) {
+                       err = hdmi_choose_cvt(codec, pin_idx, NULL, &mux_idx);
+                       if (err < 0)
+                               return;
+                       snd_printdd("HDMI: choose converter %d for pin %d\n", mux_idx, pin_idx);
+                       snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           mux_idx);
+               }
+       }
+}
+
+/*
+ * HDA PCM callbacks
+ */
+static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
+                        struct hda_codec *codec,
+                        struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int pin_idx, cvt_idx, mux_idx = 0;
+       struct hdmi_spec_per_pin *per_pin;
+       struct hdmi_eld *eld;
+       struct hdmi_spec_per_cvt *per_cvt = NULL;
+       int err;
+
+       /* Validate hinfo */
+       pin_idx = hinfo_to_pin_index(spec, hinfo);
+       if (snd_BUG_ON(pin_idx < 0))
+               return -EINVAL;
+       per_pin = get_pin(spec, pin_idx);
+       eld = &per_pin->sink_eld;
+
+       err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx);
+       if (err < 0)
+               return err;
+
+       per_cvt = get_cvt(spec, cvt_idx);
        /* Claim converter */
        per_cvt->assigned = 1;
        hinfo->nid = per_cvt->cvt_nid;
 
-       snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+       snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
                            AC_VERB_SET_CONNECT_SEL,
                            mux_idx);
+
+       /* configure unused pins to choose other converters */
+       if (codec->vendor_id == 0x80862807)
+               haswell_config_cvts(codec, pin_idx, mux_idx);
+
        snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
 
        /* Initially set the converter's capabilities */
@@ -1798,12 +1864,33 @@ static void generic_hdmi_free(struct hda_codec *codec)
        kfree(spec);
 }
 
+#ifdef CONFIG_PM
+static int generic_hdmi_resume(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx;
+
+       generic_hdmi_init(codec);
+       snd_hda_codec_resume_amp(codec);
+       snd_hda_codec_resume_cache(codec);
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+               hdmi_present_sense(per_pin, 1);
+       }
+       return 0;
+}
+#endif
+
 static const struct hda_codec_ops generic_hdmi_patch_ops = {
        .init                   = generic_hdmi_init,
        .free                   = generic_hdmi_free,
        .build_pcms             = generic_hdmi_build_pcms,
        .build_controls         = generic_hdmi_build_controls,
        .unsol_event            = hdmi_unsol_event,
+#ifdef CONFIG_PM
+       .resume                 = generic_hdmi_resume,
+#endif
 };
 
 
@@ -1821,7 +1908,6 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
 
        /* override pins connection list */
        snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid);
-       nconns = max(spec->num_cvts, 4);
        snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
 }
 
index 403010c9e82ea610125c82811e7f1f4ea3d27aac..14ac9b0e740c2a40e816b36ee7bbdf04601135eb 100644 (file)
@@ -115,6 +115,7 @@ struct alc_spec {
 
        int init_amp;
        int codec_variant;      /* flag for other variants */
+       bool has_alc5505_dsp;
 
        /* for PLL fix */
        hda_nid_t pll_nid;
@@ -2580,7 +2581,96 @@ static void alc269_shutup(struct hda_codec *codec)
        }
 }
 
+static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
+                            unsigned int val)
+{
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val & 0xffff); /* LSB */
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val >> 16); /* MSB */
+}
+
+static int alc5505_coef_get(struct hda_codec *codec, unsigned int index_reg)
+{
+       unsigned int val;
+
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
+       val = snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
+               & 0xffff;
+       val |= snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
+               << 16;
+       return val;
+}
+
+static void alc5505_dsp_halt(struct hda_codec *codec)
+{
+       unsigned int val;
+
+       alc5505_coef_set(codec, 0x3000, 0x000c); /* DSP CPU stop */
+       alc5505_coef_set(codec, 0x880c, 0x0008); /* DDR enter self refresh */
+       alc5505_coef_set(codec, 0x61c0, 0x11110080); /* Clock control for PLL and CPU */
+       alc5505_coef_set(codec, 0x6230, 0xfc0d4011); /* Disable Input OP */
+       alc5505_coef_set(codec, 0x61b4, 0x040a2b03); /* Stop PLL2 */
+       alc5505_coef_set(codec, 0x61b0, 0x00005b17); /* Stop PLL1 */
+       alc5505_coef_set(codec, 0x61b8, 0x04133303); /* Stop PLL3 */
+       val = alc5505_coef_get(codec, 0x6220);
+       alc5505_coef_set(codec, 0x6220, (val | 0x3000)); /* switch Ringbuffer clock to DBUS clock */
+}
+
+static void alc5505_dsp_back_from_halt(struct hda_codec *codec)
+{
+       alc5505_coef_set(codec, 0x61b8, 0x04133302);
+       alc5505_coef_set(codec, 0x61b0, 0x00005b16);
+       alc5505_coef_set(codec, 0x61b4, 0x040a2b02);
+       alc5505_coef_set(codec, 0x6230, 0xf80d4011);
+       alc5505_coef_set(codec, 0x6220, 0x2002010f);
+       alc5505_coef_set(codec, 0x880c, 0x00000004);
+}
+
+static void alc5505_dsp_init(struct hda_codec *codec)
+{
+       unsigned int val;
+
+       alc5505_dsp_halt(codec);
+       alc5505_dsp_back_from_halt(codec);
+       alc5505_coef_set(codec, 0x61b0, 0x5b14); /* PLL1 control */
+       alc5505_coef_set(codec, 0x61b0, 0x5b16);
+       alc5505_coef_set(codec, 0x61b4, 0x04132b00); /* PLL2 control */
+       alc5505_coef_set(codec, 0x61b4, 0x04132b02);
+       alc5505_coef_set(codec, 0x61b8, 0x041f3300); /* PLL3 control*/
+       alc5505_coef_set(codec, 0x61b8, 0x041f3302);
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_CODEC_RESET, 0); /* Function reset */
+       alc5505_coef_set(codec, 0x61b8, 0x041b3302);
+       alc5505_coef_set(codec, 0x61b8, 0x04173302);
+       alc5505_coef_set(codec, 0x61b8, 0x04163302);
+       alc5505_coef_set(codec, 0x8800, 0x348b328b); /* DRAM control */
+       alc5505_coef_set(codec, 0x8808, 0x00020022); /* DRAM control */
+       alc5505_coef_set(codec, 0x8818, 0x00000400); /* DRAM control */
+
+       val = alc5505_coef_get(codec, 0x6200) >> 16; /* Read revision ID */
+       if (val <= 3)
+               alc5505_coef_set(codec, 0x6220, 0x2002010f); /* I/O PAD Configuration */
+       else
+               alc5505_coef_set(codec, 0x6220, 0x6002018f);
+
+       alc5505_coef_set(codec, 0x61ac, 0x055525f0); /**/
+       alc5505_coef_set(codec, 0x61c0, 0x12230080); /* Clock control */
+       alc5505_coef_set(codec, 0x61b4, 0x040e2b02); /* PLL2 control */
+       alc5505_coef_set(codec, 0x61bc, 0x010234f8); /* OSC Control */
+       alc5505_coef_set(codec, 0x880c, 0x00000004); /* DRAM Function control */
+       alc5505_coef_set(codec, 0x880c, 0x00000003);
+       alc5505_coef_set(codec, 0x880c, 0x00000010);
+}
+
 #ifdef CONFIG_PM
+static int alc269_suspend(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->has_alc5505_dsp)
+               alc5505_dsp_halt(codec);
+       return alc_suspend(codec);
+}
+
 static int alc269_resume(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -2603,7 +2693,10 @@ static int alc269_resume(struct hda_codec *codec)
 
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
+       alc_inv_dmic_sync(codec, true);
        hda_call_check_power_status(codec, 0x01);
+       if (spec->has_alc5505_dsp)
+               alc5505_dsp_back_from_halt(codec);
        return 0;
 }
 #endif /* CONFIG_PM */
@@ -3225,6 +3318,7 @@ enum {
        ALC271_FIXUP_HP_GATE_MIC_JACK,
        ALC269_FIXUP_ACER_AC700,
        ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
+       ALC269VB_FIXUP_ORDISSIMO_EVE2,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -3467,6 +3561,15 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_limit_int_mic_boost,
        },
+       [ALC269VB_FIXUP_ORDISSIMO_EVE2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x99a3092f }, /* int-mic */
+                       { 0x18, 0x03a11d20 }, /* mic */
+                       { 0x19, 0x411111f0 }, /* Unused bogus pin */
+                       { }
+               },
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -3482,6 +3585,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x05c9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05ca, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05cb, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05de, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05e0, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05e9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -3495,9 +3600,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05f8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05f9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05fb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
        SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -3539,6 +3649,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
+       SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
 
 #if 0
        /* Below is a quirk table taken from the old code.
@@ -3718,6 +3829,11 @@ static int patch_alc269(struct hda_codec *codec)
                break;
        }
 
+       if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) {
+               spec->has_alc5505_dsp = true;
+               spec->init_hook = alc5505_dsp_init;
+       }
+
        /* automatic parse from the BIOS config */
        err = alc269_parse_auto_config(codec);
        if (err < 0)
@@ -3728,6 +3844,7 @@ static int patch_alc269(struct hda_codec *codec)
 
        codec->patch_ops = alc_patch_ops;
 #ifdef CONFIG_PM
+       codec->patch_ops.suspend = alc269_suspend;
        codec->patch_ops.resume = alc269_resume;
 #endif
        spec->shutup = alc269_shutup;
index 1d9d6427e0bf7cd3f09bc3a83fb1e0b08ad64848..e2f83591161bbf3e7bf5f70ef732b8cd57b38587 100644 (file)
@@ -2233,6 +2233,10 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
                          "HP Folio", STAC_92HD83XXX_HP_MIC_LED),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x1900,
                          "HP", STAC_92HD83XXX_HP_MIC_LED),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2000,
+                         "HP", STAC_92HD83XXX_HP_MIC_LED),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2100,
+                         "HP", STAC_92HD83XXX_HP_MIC_LED),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
                          "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
@@ -3707,14 +3711,6 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer,
 #endif
 
 #ifdef CONFIG_PM
-static int stac_resume(struct hda_codec *codec)
-{
-       codec->patch_ops.init(codec);
-       snd_hda_codec_resume_amp(codec);
-       snd_hda_codec_resume_cache(codec);
-       return 0;
-}
-
 static int stac_suspend(struct hda_codec *codec)
 {
        stac_shutup(codec);
@@ -3743,7 +3739,6 @@ static void stac_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 }
 #else
 #define stac_suspend           NULL
-#define stac_resume            NULL
 #define stac_set_power_state   NULL
 #endif /* CONFIG_PM */
 
@@ -3755,7 +3750,6 @@ static const struct hda_codec_ops stac_patch_ops = {
        .unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
        .suspend = stac_suspend,
-       .resume = stac_resume,
 #endif
        .reboot_notify = stac_shutup,
 };
index e5245544eb52bbecaaf0ff3e60b6f4f25d80d3c3..e2481baddc70ff6ff265ee0ed118377869847db6 100644 (file)
@@ -480,14 +480,9 @@ static int via_suspend(struct hda_codec *codec)
        struct via_spec *spec = codec->spec;
        vt1708_stop_hp_work(codec);
 
-       if (spec->codec_type == VT1802) {
-               /* Fix pop noise on headphones */
-               int i;
-               for (i = 0; i < spec->gen.autocfg.hp_outs; i++)
-                       snd_hda_codec_write(codec, spec->gen.autocfg.hp_pins[i],
-                                           0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           0x00);
-       }
+       /* Fix pop noise on headphones */
+       if (spec->codec_type == VT1802)
+               snd_hda_shutup_pins(codec);
 
        return 0;
 }
@@ -746,6 +741,8 @@ static int patch_vt1708(struct hda_codec *codec)
        /* don't support the input jack switching due to lack of unsol event */
        /* (it may work with polling, though, but it needs testing) */
        spec->gen.suppress_auto_mic = 1;
+       /* Some machines show the broken speaker mute */
+       spec->gen.auto_mute_via_amp = 1;
 
        /* Add HP and CD pin config connect bit re-config action */
        vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
@@ -910,6 +907,8 @@ static const struct hda_verb vt1708S_init_verbs[] = {
 static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
                               int offset, int num_steps, int step_size)
 {
+       snd_hda_override_wcaps(codec, pin,
+                              get_wcaps(codec, pin) | AC_WCAP_IN_AMP);
        snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
                                  (offset << AC_AMPCAP_OFFSET_SHIFT) |
                                  (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
index 806407a3973e41784749f21c841628ad262c73f7..28ec872e54c01350369bf47f143db9c2d5da8b8d 100644 (file)
@@ -2807,7 +2807,6 @@ static void snd_ice1712_remove(struct pci_dev *pci)
        if (ice->card_info && ice->card_info->chip_exit)
                ice->card_info->chip_exit(ice);
        snd_card_free(card);
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver ice1712_driver = {
index ce70e7f113e0545f90e70edfd363271b9455dc58..50047177829172f97c0c6b9302854bdd8b0aca93 100644 (file)
@@ -2800,7 +2800,6 @@ static void snd_vt1724_remove(struct pci_dev *pci)
        if (ice->card_info && ice->card_info->chip_exit)
                ice->card_info->chip_exit(ice);
        snd_card_free(card);
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index b8fe40531b9c52f905a45a0505dd1e9f09d107d4..59c8aaebb91ea4106bf315139603af307f13b25f 100644 (file)
@@ -3364,7 +3364,6 @@ static int snd_intel8x0_probe(struct pci_dev *pci,
 static void snd_intel8x0_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver intel8x0_driver = {
index fea09e8ea608d0078fa84e8fa81e73e40a33802c..3573c11936656d8f1b003573d559494618c7a694 100644 (file)
@@ -1328,7 +1328,6 @@ static int snd_intel8x0m_probe(struct pci_dev *pci,
 static void snd_intel8x0m_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver intel8x0m_driver = {
index 43b4228d9afe41812a25d4d9ea81e2b028016410..9cf9829555d422a250cff10dd956b23e09dca996 100644 (file)
@@ -2473,7 +2473,6 @@ snd_korg1212_probe(struct pci_dev *pci,
 static void snd_korg1212_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver korg1212_driver = {
index 322b638e8ec48056c7e433f2067e4aff80bd0014..7307d97186cb45c66f7584f9857c559533038f72 100644 (file)
@@ -759,7 +759,6 @@ out_free:
 static void lola_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 /* PCI IDs */
index 298bc9b7299116b23a83e572c69cfb3224124351..3230e57f246c32c362aeab200200e78100a7f919 100644 (file)
@@ -1139,7 +1139,6 @@ out_free:
 static void snd_lx6464es_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 
index c76ac14112108a9a07eef1bd3c844f48b92228eb..d5417360f51fb8be6a43be6ddef9bd6c2e7ac2e3 100644 (file)
@@ -2775,7 +2775,6 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 static void snd_m3_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver m3_driver = {
index 934dec98e2ced022e3818a60d5d7ab65f3d4ba19..1e0f6ee193f0a926279e3d3d25a4ea995b78bfdd 100644 (file)
@@ -1377,7 +1377,6 @@ static int snd_mixart_probe(struct pci_dev *pci,
 static void snd_mixart_remove(struct pci_dev *pci)
 {
        snd_mixart_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver mixart_driver = {
index 6febedb05936f3f441f55fdb297a42d57f8b7137..fe79fff4c6dc303fd3a5babde6320446979a3f14 100644 (file)
@@ -1746,7 +1746,6 @@ static int snd_nm256_probe(struct pci_dev *pci,
 static void snd_nm256_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 
index 9562dc63ba607c70db84443a961b57fad9e20927..b0cb48adddc790c3f87e7a52cdb0431430e13ce2 100644 (file)
@@ -722,7 +722,6 @@ EXPORT_SYMBOL(oxygen_pci_probe);
 void oxygen_pci_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 EXPORT_SYMBOL(oxygen_pci_remove);
 
index b97384ad946dae84ec724f4c91d2b46a226b50df..d379b284955b23dea2cded6e8efe7e0ba17ccda2 100644 (file)
@@ -1691,7 +1691,6 @@ static int pcxhr_probe(struct pci_dev *pci,
 static void pcxhr_remove(struct pci_dev *pci)
 {
        pcxhr_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver pcxhr_driver = {
index 63c1c80415541c8a7207ded0c1cab82e8fb952a2..56cc891e395e54a17edf0a80b377370b317c628c 100644 (file)
@@ -2066,7 +2066,6 @@ static void snd_riptide_joystick_remove(struct pci_dev *pci)
        if (gameport) {
                release_region(gameport->io, 8);
                gameport_unregister_port(gameport);
-               pci_set_drvdata(pci, NULL);
        }
 }
 #endif
@@ -2179,7 +2178,6 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 static void snd_card_riptide_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver driver = {
index 0ecd4100713ecf2eb6b61bdc845f8000fc4b070e..cc26346ae66bf82d6fc4680b56ed4f136ff832ab 100644 (file)
@@ -1981,7 +1981,6 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 static void snd_rme32_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver rme32_driver = {
index 5fb88ac82aa93f6f4f0d0021ba0775ebf952e1ac..2a8ad9d1a2aea290cf433c0fccb4218ab78cf5ff 100644 (file)
@@ -2390,7 +2390,6 @@ snd_rme96_probe(struct pci_dev *pci,
 static void snd_rme96_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver rme96_driver = {
index 94084cdb130c44823d04dbb8b617572e43f7987f..4f255dfee4504454702bfdec305b1b72820a26ac 100644 (file)
@@ -5412,7 +5412,6 @@ static int snd_hdsp_probe(struct pci_dev *pci,
 static void snd_hdsp_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver hdsp_driver = {
index 9ea05e956474fe0847ea6734348626f02c627a63..bd501931ee2341f1a6f913dc1b21a967268de704 100644 (file)
@@ -400,8 +400,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 
 #define HDSPM_wc_freq0 (1<<5)  /* input freq detected via autosync  */
 #define HDSPM_wc_freq1 (1<<6)  /* 001=32, 010==44.1, 011=48, */
-#define HDSPM_wc_freq2 (1<<7)  /* 100=64, 101=88.2, 110=96, */
-/* missing Bit   for               111=128, 1000=176.4, 1001=192 */
+#define HDSPM_wc_freq2 (1<<7)  /* 100=64, 101=88.2, 110=96, 111=128 */
+#define HDSPM_wc_freq3 0x800   /* 1000=176.4, 1001=192 */
 
 #define HDSPM_SyncRef0 0x10000  /* Sync Reference */
 #define HDSPM_SyncRef1 0x20000
@@ -412,13 +412,17 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 
 #define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync)
 
-#define HDSPM_wcFreqMask  (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_wcFreqMask  (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\
+                           HDSPM_wc_freq3)
 #define HDSPM_wcFreq32    (HDSPM_wc_freq0)
 #define HDSPM_wcFreq44_1  (HDSPM_wc_freq1)
 #define HDSPM_wcFreq48    (HDSPM_wc_freq0|HDSPM_wc_freq1)
 #define HDSPM_wcFreq64    (HDSPM_wc_freq2)
 #define HDSPM_wcFreq88_2  (HDSPM_wc_freq0|HDSPM_wc_freq2)
 #define HDSPM_wcFreq96    (HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_wcFreq128   (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_wcFreq176_4 (HDSPM_wc_freq3)
+#define HDSPM_wcFreq192   (HDSPM_wc_freq0|HDSPM_wc_freq3)
 
 #define HDSPM_status1_F_0 0x0400000
 #define HDSPM_status1_F_1 0x0800000
@@ -1087,6 +1091,26 @@ static int hdspm_round_frequency(int rate)
                return 48000;
 }
 
+/* QS and DS rates normally can not be detected
+ * automatically by the card. Only exception is MADI
+ * in 96k frame mode.
+ *
+ * So if we read SS values (32 .. 48k), check for
+ * user-provided DS/QS bits in the control register
+ * and multiply the base frequency accordingly.
+ */
+static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
+{
+       if (rate <= 48000) {
+               if (hdspm->control_register & HDSPM_QuadSpeed)
+                       return rate * 4;
+               else if (hdspm->control_register &
+                               HDSPM_DoubleSpeed)
+                       return rate * 2;
+       };
+       return rate;
+}
+
 static int hdspm_tco_sync_check(struct hdspm *hdspm);
 static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
 
@@ -1181,6 +1205,15 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
                        case HDSPM_wcFreq96:
                                rate = 96000;
                                break;
+                       case HDSPM_wcFreq128:
+                               rate = 128000;
+                               break;
+                       case HDSPM_wcFreq176_4:
+                               rate = 176400;
+                               break;
+                       case HDSPM_wcFreq192:
+                               rate = 192000;
+                               break;
                        default:
                                rate = 0;
                                break;
@@ -1192,7 +1225,7 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
                 */
                if (rate != 0 &&
                (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
-                       return rate;
+                       return hdspm_rate_multiplier(hdspm, rate);
 
                /* maybe a madi input (which is taken if sel sync is madi) */
                if (status & HDSPM_madiLock) {
@@ -1255,21 +1288,8 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
                        }
                }
 
-               /* QS and DS rates normally can not be detected
-                * automatically by the card. Only exception is MADI
-                * in 96k frame mode.
-                *
-                * So if we read SS values (32 .. 48k), check for
-                * user-provided DS/QS bits in the control register
-                * and multiply the base frequency accordingly.
-                */
-               if (rate <= 48000) {
-                       if (hdspm->control_register & HDSPM_QuadSpeed)
-                               rate *= 4;
-                       else if (hdspm->control_register &
-                                       HDSPM_DoubleSpeed)
-                               rate *= 2;
-               }
+               rate = hdspm_rate_multiplier(hdspm, rate);
+
                break;
        }
 
@@ -6737,7 +6757,6 @@ static int snd_hdspm_probe(struct pci_dev *pci,
 static void snd_hdspm_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver hdspm_driver = {
index 773a67fff4cdeb64469170912e82034919e5a841..b96d9e1adf6de027cb57899a6f31998d69988300 100644 (file)
@@ -2628,7 +2628,6 @@ static int snd_rme9652_probe(struct pci_dev *pci,
 static void snd_rme9652_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver rme9652_driver = {
index 748e82d4d25715b43e4b6790513941fe200f0191..e413b4e2c81952101294d993dba70aee9c1a14fb 100644 (file)
@@ -1482,7 +1482,6 @@ error_out:
 static void snd_sis7019_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver sis7019_driver = {
index a2e7686e7ae3300f78240db2755fc23899ecec30..2a46bf98af30f054a20109ada2a17115de05b127 100644 (file)
@@ -1528,7 +1528,6 @@ static int snd_sonic_probe(struct pci_dev *pci,
 static void snd_sonic_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver sonicvibes_driver = {
index 1aefd6204a63f26347f856881b3522d00e37e169..b3b588bc94c37720dd20026589b39ae342a9890d 100644 (file)
@@ -169,7 +169,6 @@ static int snd_trident_probe(struct pci_dev *pci,
 static void snd_trident_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver trident_driver = {
index d756a3562706c8182db03a358ec4edd9cc3a4437..3c511d0caf9ef25d4a985abfbd3e797b916209a8 100644 (file)
@@ -2646,7 +2646,6 @@ static int snd_via82xx_probe(struct pci_dev *pci,
 static void snd_via82xx_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver via82xx_driver = {
index 4f5fd80b7e5688ef008691f908e4b781b5d186dd..ca190283cbd7745f50d4ec4ffeaf74726ea3afc1 100644 (file)
@@ -1227,7 +1227,6 @@ static int snd_via82xx_probe(struct pci_dev *pci,
 static void snd_via82xx_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver via82xx_modem_driver = {
index e2f1ab37e1548661dae8f8cadce87764db7d52d6..ab8a9b1bfb8e21933290e86be80a4f8a6459313b 100644 (file)
@@ -254,7 +254,6 @@ static int snd_vx222_probe(struct pci_dev *pci,
 static void snd_vx222_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 #ifdef CONFIG_PM_SLEEP
index 01c49655a3c1014bb9dec01784971b6e8a4d250c..e8932b2e4a5dcce73f4a2417933d90cf618079cb 100644 (file)
@@ -347,7 +347,6 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
 static void snd_card_ymfpci_remove(struct pci_dev *pci)
 {
        snd_card_free(pci_get_drvdata(pci));
-       pci_set_drvdata(pci, NULL);
 }
 
 static struct pci_driver ymfpci_driver = {
index 22056c50fe39fde10184856c33e14d20bf1743a1..d591c154fc58fc4a9aeb3a5407e500b24d7e4996 100644 (file)
@@ -2258,7 +2258,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
        /* FIXME: temporarily disabled, otherwise we cannot fire up
         * the chip again unless reboot.  ACPI bug?
         */
-       pci_set_power_state(chip->pci, 3);
+       pci_set_power_state(chip->pci, PCI_D3hot);
 #endif
 
 #ifdef CONFIG_PM_SLEEP
index 09fc848d32ecd475951f09513e492e78a03d2a1c..8abb521b4814b413a9423edf48bf2d7e41c08e2e 100644 (file)
@@ -139,7 +139,6 @@ __error:
 static int snd_pmac_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index e59a73a9bc427602717633ea66953a73950d2d18..78a369785a9ecf3b3e8d1a72e6b536e6a8ddb89a 100644 (file)
@@ -598,7 +598,6 @@ static int snd_aica_remove(struct platform_device *devptr)
                return -ENODEV;
        snd_card_free(dreamcastcard->card);
        kfree(dreamcastcard);
-       platform_set_drvdata(devptr, NULL);
        return 0;
 }
 
index e68c4fc91a0304002537845b4a8b1182ab107258..7c9422c4fc0f99097c0b3b6197a1dc0ff8165099 100644 (file)
@@ -290,8 +290,6 @@ static int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device)
 static int snd_sh_dac_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
-       platform_set_drvdata(devptr, NULL);
-
        return 0;
 }
 
index 9e675c76436c7c63c90fda29521cfc0c1a5fa633..45eeaa9f7fec49f035cf8faa54fdfdb5a8ea9df5 100644 (file)
@@ -51,6 +51,7 @@ source "sound/soc/pxa/Kconfig"
 source "sound/soc/samsung/Kconfig"
 source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/spear/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
 source "sound/soc/ux500/Kconfig"
index 197b6ae54c8ddd3ce9de65453b50099f3393264e..bc0261476d7afc78767856683398ec1bd7bc463e 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_SND_SOC) += pxa/
 obj-$(CONFIG_SND_SOC)  += samsung/
 obj-$(CONFIG_SND_SOC)  += s6000/
 obj-$(CONFIG_SND_SOC)  += sh/
+obj-$(CONFIG_SND_SOC)  += spear/
 obj-$(CONFIG_SND_SOC)  += tegra/
 obj-$(CONFIG_SND_SOC)  += txx9/
 obj-$(CONFIG_SND_SOC)  += ux500/
index 2d6fbd0125b9a6b6411a256c6d3e950d6be34878..802717eccbd010d1a43f104e87004a28e56c3f30 100644 (file)
@@ -38,8 +38,6 @@
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 
-#include <linux/pinctrl/consumer.h>
-
 #include <linux/atmel-ssc.h>
 
 #include <sound/core.h>
@@ -203,15 +201,8 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
        struct device_node *codec_np, *cpu_np;
        struct clk *pllb;
        struct snd_soc_card *card = &snd_soc_at91sam9g20ek;
-       struct pinctrl *pinctrl;
        int ret;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               dev_err(&pdev->dev, "Failed to request pinctrl for mck\n");
-               return PTR_ERR(pinctrl);
-       }
-
        if (!np) {
                if (!(machine_is_at91sam9g20ek() ||
                        machine_is_at91sam9g20ek_2mmc()))
index 44b8dcecf57179c16dbb695da2e0cad1ebfa8937..d6f7694fcad4f78ae1cb300d8d9fe3a4ef3b11d1 100644 (file)
@@ -179,13 +179,12 @@ static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97)
 }
 
 /* AC97 controller operations */
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops ac97c_bus_ops = {
        .read           = au1xac97c_ac97_read,
        .write          = au1xac97c_ac97_write,
        .reset          = au1xac97c_ac97_cold_reset,
        .warm_reset     = au1xac97c_ac97_warm_reset,
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);       /* globals be gone! */
 
 static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
@@ -272,6 +271,10 @@ static int au1xac97c_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ctx);
 
+       ret = snd_soc_set_ac97_ops(&ac97c_bus_ops);
+       if (ret)
+               return ret;
+
        ret = snd_soc_register_component(&pdev->dev, &au1xac97c_component,
                                         &au1xac97c_dai_driver, 1);
        if (ret)
@@ -338,19 +341,7 @@ static struct platform_driver au1xac97c_driver = {
        .remove         = au1xac97c_drvremove,
 };
 
-static int __init au1xac97c_load(void)
-{
-       ac97c_workdata = NULL;
-       return platform_driver_register(&au1xac97c_driver);
-}
-
-static void __exit au1xac97c_unload(void)
-{
-       platform_driver_unregister(&au1xac97c_driver);
-}
-
-module_init(au1xac97c_load);
-module_exit(au1xac97c_unload);
+module_platform_driver(&au1xac97c_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver");
index 8f1862aa733311b35552079ace7a8fa314b4c3b6..a822ab822bb7ba40f5f1ead77a04a7caa7069233 100644 (file)
@@ -201,13 +201,12 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
 }
 
 /* AC97 controller operations */
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops psc_ac97_ops = {
        .read           = au1xpsc_ac97_read,
        .write          = au1xpsc_ac97_write,
        .reset          = au1xpsc_ac97_cold_reset,
        .warm_reset     = au1xpsc_ac97_warm_reset,
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params,
@@ -383,15 +382,9 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
        if (!iores)
                return -ENODEV;
 
-       if (!devm_request_mem_region(&pdev->dev, iores->start,
-                                    resource_size(iores),
-                                    pdev->name))
-               return -EBUSY;
-
-       wd->mmio = devm_ioremap(&pdev->dev, iores->start,
-                               resource_size(iores));
-       if (!wd->mmio)
-               return -EBUSY;
+       wd->mmio = devm_ioremap_resource(&pdev->dev, iores);
+       if (IS_ERR(wd->mmio))
+               return PTR_ERR(wd->mmio);
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!dmares)
@@ -423,6 +416,10 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wd);
 
+       ret = snd_soc_set_ac97_ops(&psc_ac97_ops);
+       if (ret)
+               return ret;
+
        ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component,
                                         &wd->dai_drv, 1);
        if (ret)
@@ -503,19 +500,7 @@ static struct platform_driver au1xpsc_ac97_driver = {
        .remove         = au1xpsc_ac97_drvremove,
 };
 
-static int __init au1xpsc_ac97_load(void)
-{
-       au1xpsc_ac97_workdata = NULL;
-       return platform_driver_register(&au1xpsc_ac97_driver);
-}
-
-static void __exit au1xpsc_ac97_unload(void)
-{
-       platform_driver_unregister(&au1xpsc_ac97_driver);
-}
-
-module_init(au1xpsc_ac97_load);
-module_exit(au1xpsc_ac97_unload);
+module_platform_driver(au1xpsc_ac97_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver");
index 16b88f5c26e26a974fb611da0ee27babfd5703eb..54f74f8cbb754a0e66aecc3953fff0c8ba63966c 100644 (file)
@@ -56,6 +56,23 @@ config SND_SOC_BFIN_EVAL_ADAV80X
          Note: This driver assumes that the ADAV80X digital record and playback
          interfaces are connected to the first SPORT port on the BF5XX board.
 
+config SND_BF5XX_SOC_AD1836
+       tristate "SoC AD1836 Audio support for BF5xx"
+       depends on SND_BF5XX_I2S
+       select SND_BF5XX_SOC_I2S
+       select SND_SOC_AD1836
+       help
+         Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
+
+config SND_BF5XX_SOC_AD193X
+       tristate "SoC AD193X Audio support for Blackfin"
+       depends on SND_BF5XX_I2S
+       select SND_BF5XX_SOC_I2S
+       select SND_SOC_AD193X
+       help
+         Say Y if you want to add support for AD193X codec on Blackfin.
+         This driver supports AD1936, AD1937, AD1938 and AD1939.
+
 config SND_BF5XX_SOC_AD73311
        tristate "SoC AD73311 Audio support for Blackfin"
        depends on SND_BF5XX_I2S
@@ -72,33 +89,6 @@ config SND_BFIN_AD73311_SE
          Enter the GPIO used to control AD73311's SE pin. Acceptable
          values are 0 to 7
 
-config SND_BF5XX_TDM
-       tristate "SoC I2S(TDM mode) Audio for the ADI BF5xx chip"
-       depends on (BLACKFIN && SND_SOC)
-       select SND_BF5XX_SOC_SPORT
-       help
-         Say Y or M if you want to add support for codecs attached to
-         the Blackfin SPORT (synchronous serial ports) interface in TDM
-         mode.
-         You will also need to select the audio interfaces to support below.
-
-config SND_BF5XX_SOC_AD1836
-       tristate "SoC AD1836 Audio support for BF5xx"
-       depends on SND_BF5XX_TDM
-       select SND_BF5XX_SOC_TDM
-       select SND_SOC_AD1836
-       help
-         Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
-
-config SND_BF5XX_SOC_AD193X
-       tristate "SoC AD193X Audio support for Blackfin"
-       depends on SND_BF5XX_TDM
-       select SND_BF5XX_SOC_TDM
-       select SND_SOC_AD193X
-       help
-         Say Y if you want to add support for AD193X codec on Blackfin.
-         This driver supports AD1936, AD1937, AD1938 and AD1939.
-
 config SND_BF5XX_AC97
        tristate "SoC AC97 Audio for the ADI BF5xx chip"
        depends on BLACKFIN
@@ -174,9 +164,6 @@ config SND_BF5XX_SOC_I2S
 config SND_BF6XX_SOC_I2S
        tristate
 
-config SND_BF5XX_SOC_TDM
-       tristate
-
 config SND_BF5XX_SOC_AC97
        tristate
 
index 6fea1f4cbee2d2f99c83bcdaa3d5153b824e1f2d..ad0a6e99bc5dcd2ce08fb7106f8c2e4fc1cf9da0 100644 (file)
@@ -1,23 +1,19 @@
 # Blackfin Platform Support
 snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
 snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
-snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o
 snd-soc-bf5xx-sport-objs := bf5xx-sport.o
 snd-soc-bf6xx-sport-objs := bf6xx-sport.o
 snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
 snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
 snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o
-snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o
 
 obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
 obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
-obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o
 obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
 obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o
 obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
 obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
 obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o
-obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o
 
 # Blackfin Machine Support
 snd-ad1836-objs := bf5xx-ad1836.o
index 7e2f36004a5acd605f9223e93d168143e11bcd25..53f84085bf1fbd7c1daadc093ebd60d7f5dc7251 100644 (file)
@@ -39,7 +39,6 @@
 
 #include <asm/dma.h>
 
-#include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 #include "bf5xx-sport.h"
 
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.h b/sound/soc/blackfin/bf5xx-ac97-pcm.h
deleted file mode 100644 (file)
index d324d58..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * linux/sound/arm/bf5xx-ac97-pcm.h -- ALSA PCM interface for the Blackfin
- *
- * Copyright 2007 Analog Device 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.
- */
-
-#ifndef _BF5XX_AC97_PCM_H
-#define _BF5XX_AC97_PCM_H
-
-struct bf5xx_pcm_dma_params {
-       char *name;                     /* stream identifier */
-};
-
-struct bf5xx_gpio {
-       u32 sys;
-       u32 rx;
-       u32 tx;
-       u32 clk;
-       u32 frm;
-};
-
-#endif
index 490217325975ab47f9c393fc66d01365e16410b1..efb1daecd0dd6136122aa8595c145630ff102b22 100644 (file)
@@ -198,13 +198,12 @@ static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
 #endif
 }
 
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops bf5xx_ac97_ops = {
        .read   = bf5xx_ac97_read,
        .write  = bf5xx_ac97_write,
        .warm_reset     = bf5xx_ac97_warm_reset,
        .reset  = bf5xx_ac97_cold_reset,
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 #ifdef CONFIG_PM
 static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
@@ -231,9 +230,9 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
                return 0;
 
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
-       ret = sport_set_multichannel(sport, 16, 0x3FF, 1);
+       ret = sport_set_multichannel(sport, 16, 0x3FF, 0x3FF, 1);
 #else
-       ret = sport_set_multichannel(sport, 16, 0x1F, 1);
+       ret = sport_set_multichannel(sport, 16, 0x1F, 0x1F, 1);
 #endif
        if (ret) {
                pr_err("SPORT is busy!\n");
@@ -293,13 +292,14 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        /* Request PB3 as reset pin */
-       if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) {
-               pr_err("Failed to request GPIO_%d for reset\n",
-                               CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-               ret =  -1;
+       ret = devm_gpio_request_one(&pdev->dev,
+                                   CONFIG_SND_BF5XX_RESET_GPIO_NUM,
+                                   GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET") {
+               dev_err(&pdev->dev,
+                       "Failed to request GPIO_%d for reset: %d\n",
+                       CONFIG_SND_BF5XX_RESET_GPIO_NUM, ret);
                goto gpio_err;
        }
-       gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
 #endif
 
        sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
@@ -311,9 +311,9 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
 
        /*SPORT works in TDM mode to simulate AC97 transfers*/
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
-       ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1);
+       ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 0x3FF, 1);
 #else
-       ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1);
+       ret = sport_set_multichannel(sport_handle, 16, 0x1F, 0x1F, 1);
 #endif
        if (ret) {
                pr_err("SPORT is busy!\n");
@@ -335,6 +335,12 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
+       ret = snd_soc_set_ac97_ops(&bf5xx_ac97_ops);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
+               goto sport_config_err;
+       }
+
        ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
                                         &bfin_ac97_dai, 1);
        if (ret) {
@@ -349,10 +355,7 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
 sport_config_err:
        sport_done(sport_handle);
 sport_err:
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
-       gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-gpio_err:
-#endif
+       snd_soc_set_ac97_ops(NULL);
 
        return ret;
 }
@@ -363,9 +366,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev)
 
        snd_soc_unregister_component(&pdev->dev);
        sport_done(sport_handle);
-#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
-       gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
+       snd_soc_set_ac97_ops(NULL);
 
        return 0;
 }
index d23f4b0ea54f3779f9e655ef7e7557c8e8671f26..8fcfc4ec3a51d5009b9a747a5d48daf513d791eb 100644 (file)
 
 #include "../codecs/ad1836.h"
 
-#include "bf5xx-tdm-pcm.h"
-#include "bf5xx-tdm.h"
-
 static struct snd_soc_card bf5xx_ad1836;
 
-static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
+static int bf5xx_ad1836_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
        int ret = 0;
@@ -49,13 +44,13 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
-static struct snd_soc_ops bf5xx_ad1836_ops = {
-       .hw_params = bf5xx_ad1836_hw_params,
-};
-
 #define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
                                SND_SOC_DAIFMT_CBM_CFM)
 
@@ -63,9 +58,9 @@ static struct snd_soc_dai_link bf5xx_ad1836_dai = {
        .name = "ad1836",
        .stream_name = "AD1836",
        .codec_dai_name = "ad1836-hifi",
-       .platform_name = "bfin-tdm-pcm-audio",
-       .ops = &bf5xx_ad1836_ops,
+       .platform_name = "bfin-i2s-pcm-audio",
        .dai_fmt = BF5XX_AD1836_DAIFMT,
+       .init = bf5xx_ad1836_init,
 };
 
 static struct snd_soc_card bf5xx_ad1836 = {
index 0e55e9f2a514df69473365a7222d93908ea1bdcd..603ad1f2b9b9bb75f00194b971befe720c9e3992 100644 (file)
 
 #include "../codecs/ad193x.h"
 
-#include "bf5xx-tdm-pcm.h"
-#include "bf5xx-tdm.h"
-
 static struct snd_soc_card bf5xx_ad193x;
 
-static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
+static int bf5xx_ad193x_link_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       unsigned int clk = 0;
-       unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
-       int ret = 0;
-
-       switch (params_rate(params)) {
-       case 48000:
-               clk = 24576000;
-               break;
-       }
+       int ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
-               SND_SOC_CLOCK_IN);
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
 
@@ -71,9 +57,7 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       /* set cpu DAI channel mapping */
-       ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
-               channel_map, ARRAY_SIZE(channel_map), channel_map);
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
        if (ret < 0)
                return ret;
 
@@ -83,30 +67,26 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 #define BF5XX_AD193X_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
                                SND_SOC_DAIFMT_CBM_CFM)
 
-static struct snd_soc_ops bf5xx_ad193x_ops = {
-       .hw_params = bf5xx_ad193x_hw_params,
-};
-
 static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
        {
                .name = "ad193x",
                .stream_name = "AD193X",
-               .cpu_dai_name = "bfin-tdm.0",
+               .cpu_dai_name = "bfin-i2s.0",
                .codec_dai_name ="ad193x-hifi",
-               .platform_name = "bfin-tdm-pcm-audio",
+               .platform_name = "bfin-i2s-pcm-audio",
                .codec_name = "spi0.5",
-               .ops = &bf5xx_ad193x_ops,
                .dai_fmt = BF5XX_AD193X_DAIFMT,
+               .init = bf5xx_ad193x_link_init,
        },
        {
                .name = "ad193x",
                .stream_name = "AD193X",
-               .cpu_dai_name = "bfin-tdm.1",
+               .cpu_dai_name = "bfin-i2s.1",
                .codec_dai_name ="ad193x-hifi",
-               .platform_name = "bfin-tdm-pcm-audio",
+               .platform_name = "bfin-i2s-pcm-audio",
                .codec_name = "spi0.5",
-               .ops = &bf5xx_ad193x_ops,
                .dai_fmt = BF5XX_AD193X_DAIFMT,
+               .init = bf5xx_ad193x_link_init,
        },
 };
 
index b30f88bbd70332ab09fe9a116e21a6278e6c74d5..3450e8f9080ddd4600b47ffc2487ae68dbe96326 100644 (file)
@@ -48,7 +48,6 @@
 
 #include "../codecs/ad1980.h"
 
-#include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 
 static struct snd_soc_card bf5xx_board;
index 61cc91d4a028f8916d9c48adf0d14df2406368e2..786bbdd96e7c4b9d6144128ebe63497a23a66e3b 100644 (file)
@@ -45,7 +45,6 @@
 
 #include "../codecs/ad73311.h"
 #include "bf5xx-sport.h"
-#include "bf5xx-i2s-pcm.h"
 
 #if CONFIG_SND_BF5XX_SPORT_NUM == 0
 #define bfin_write_SPORT_TCR1  bfin_write_SPORT0_TCR1
index 262c1de364d87a06ee43125203e18d54f26a968f..9cb4a80df98eee2efa78b9b3a05a99baf64cc8b1 100644 (file)
@@ -39,8 +39,8 @@
 
 #include <asm/dma.h>
 
-#include "bf5xx-i2s-pcm.h"
 #include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
 
 static void bf5xx_dma_irq(void *data)
 {
@@ -50,7 +50,6 @@ static void bf5xx_dma_irq(void *data)
 
 static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_INTERLEAVED |
-                                  SNDRV_PCM_INFO_MMAP |
                                   SNDRV_PCM_INFO_MMAP_VALID |
                                   SNDRV_PCM_INFO_BLOCK_TRANSFER,
        .formats                = SNDRV_PCM_FMTBIT_S16_LE |
@@ -67,10 +66,16 @@ static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
 static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
-       size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
-       snd_pcm_lib_malloc_pages(substream, size);
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       unsigned int buffer_size = params_buffer_bytes(params);
+       struct bf5xx_i2s_pcm_data *dma_data;
 
-       return 0;
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       if (dma_data->tdm_mode)
+               buffer_size = buffer_size / params_channels(params) * 8;
+
+       return snd_pcm_lib_malloc_pages(substream, buffer_size);
 }
 
 static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
@@ -82,9 +87,16 @@ static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
 
 static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct sport_device *sport = runtime->private_data;
        int period_bytes = frames_to_bytes(runtime, runtime->period_size);
+       struct bf5xx_i2s_pcm_data *dma_data;
+
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       if (dma_data->tdm_mode)
+               period_bytes = period_bytes / runtime->channels * 8;
 
        pr_debug("%s enter\n", __func__);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -131,10 +143,15 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 
 static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct sport_device *sport = runtime->private_data;
        unsigned int diff;
        snd_pcm_uframes_t frames;
+       struct bf5xx_i2s_pcm_data *dma_data;
+
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
        pr_debug("%s enter\n", __func__);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                diff = sport_curr_offset_tx(sport);
@@ -151,6 +168,8 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
                diff = 0;
 
        frames = bytes_to_frames(substream->runtime, diff);
+       if (dma_data->tdm_mode)
+               frames = frames * runtime->channels / 8;
 
        return frames;
 }
@@ -162,11 +181,18 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
        struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_dma_buffer *buf = &substream->dma_buffer;
+       struct bf5xx_i2s_pcm_data *dma_data;
        int ret;
 
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
        pr_debug("%s enter\n", __func__);
 
        snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
+       if (dma_data->tdm_mode)
+               runtime->hw.buffer_bytes_max /= 4;
+       else
+               runtime->hw.info |= SNDRV_PCM_INFO_MMAP;
 
        ret = snd_pcm_hw_constraint_integer(runtime,
                        SNDRV_PCM_HW_PARAM_PERIODS);
@@ -202,6 +228,88 @@ static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
        return 0 ;
 }
 
+static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
+       snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int sample_size = runtime->sample_bits / 8;
+       struct bf5xx_i2s_pcm_data *dma_data;
+       unsigned int i;
+       void *src, *dst;
+
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       if (dma_data->tdm_mode) {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       src = buf;
+                       dst = runtime->dma_area;
+                       dst += pos * sample_size * 8;
+
+                       while (count--) {
+                               for (i = 0; i < runtime->channels; i++) {
+                                       memcpy(dst + dma_data->map[i] *
+                                               sample_size, src, sample_size);
+                                       src += sample_size;
+                               }
+                               dst += 8 * sample_size;
+                       }
+               } else {
+                       src = runtime->dma_area;
+                       src += pos * sample_size * 8;
+                       dst = buf;
+
+                       while (count--) {
+                               for (i = 0; i < runtime->channels; i++) {
+                                       memcpy(dst, src + dma_data->map[i] *
+                                               sample_size, sample_size);
+                                       dst += sample_size;
+                               }
+                               src += 8 * sample_size;
+                       }
+               }
+       } else {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       src = buf;
+                       dst = runtime->dma_area;
+                       dst += frames_to_bytes(runtime, pos);
+               } else {
+                       src = runtime->dma_area;
+                       src += frames_to_bytes(runtime, pos);
+                       dst = buf;
+               }
+
+               memcpy(dst, src, frames_to_bytes(runtime, count));
+       }
+
+       return 0;
+}
+
+static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
+       int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int sample_size = runtime->sample_bits / 8;
+       void *buf = runtime->dma_area;
+       struct bf5xx_i2s_pcm_data *dma_data;
+       unsigned int offset, size;
+
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       if (dma_data->tdm_mode) {
+               offset = pos * 8 * sample_size;
+               size = count * 8 * sample_size;
+       } else {
+               offset = frames_to_bytes(runtime, pos);
+               size = frames_to_bytes(runtime, count);
+       }
+
+       snd_pcm_format_set_silence(runtime->format, buf + offset, size);
+
+       return 0;
+}
+
 static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
        .open           = bf5xx_pcm_open,
        .ioctl          = snd_pcm_lib_ioctl,
@@ -211,57 +319,16 @@ static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
        .trigger        = bf5xx_pcm_trigger,
        .pointer        = bf5xx_pcm_pointer,
        .mmap           = bf5xx_pcm_mmap,
+       .copy           = bf5xx_pcm_copy,
+       .silence        = bf5xx_pcm_silence,
 };
 
-static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_coherent(pcm->card->dev, size,
-                       &buf->addr, GFP_KERNEL);
-       if (!buf->area) {
-               pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n");
-               return -ENOMEM;
-       }
-       buf->bytes = size;
-
-       pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
-               buf->area, buf->bytes);
-
-       return 0;
-}
-
-static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-               dma_free_coherent(NULL, buf->bytes, buf->area, 0);
-               buf->area = NULL;
-       }
-}
-
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 
 static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret = 0;
+       size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
 
        pr_debug("%s enter\n", __func__);
        if (!card->dev->dma_mask)
@@ -269,27 +336,13 @@ static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
- out:
-       return ret;
+       return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+                               SNDRV_DMA_TYPE_DEV, card->dev, size, size);
 }
 
 static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
        .ops            = &bf5xx_pcm_i2s_ops,
        .pcm_new        = bf5xx_pcm_i2s_new,
-       .pcm_free       = bf5xx_pcm_free_dma_buffers,
 };
 
 static int bfin_i2s_soc_platform_probe(struct platform_device *pdev)
index 0c2c5a68d4fff43bc2438749bceb7c5bc1b32148..1f0435249f888903cf5f18f1560e1fbca0f822e2 100644 (file)
@@ -1,26 +1,17 @@
 /*
- * linux/sound/arm/bf5xx-i2s-pcm.h -- ALSA PCM interface for the Blackfin
- *
- * Copyright 2007 Analog Device 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.
  */
 
-#ifndef _BF5XX_I2S_PCM_H
-#define _BF5XX_I2S_PCM_H
+#ifndef _BF5XX_TDM_PCM_H
+#define _BF5XX_TDM_PCM_H
 
-struct bf5xx_pcm_dma_params {
-       char *name;                     /* stream identifier */
-};
+#define BFIN_TDM_DAI_MAX_SLOTS 8
 
-struct bf5xx_gpio {
-       u32 sys;
-       u32 rx;
-       u32 tx;
-       u32 clk;
-       u32 frm;
+struct bf5xx_i2s_pcm_data {
+       unsigned int map[BFIN_TDM_DAI_MAX_SLOTS];
+       bool tdm_mode;
 };
 
 #endif
index dd0c2a4f83a3a7cc0f8955a0ad955bf98ab79727..9a174fc47d39b38b0bf3ddfbd18f8367136744c4 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/gpio.h>
 
 #include "bf5xx-sport.h"
+#include "bf5xx-i2s-pcm.h"
 
 struct bf5xx_i2s_port {
        u16 tcr1;
@@ -49,6 +50,13 @@ struct bf5xx_i2s_port {
        u16 tcr2;
        u16 rcr2;
        int configured;
+
+       unsigned int slots;
+       unsigned int tx_mask;
+       unsigned int rx_mask;
+
+       struct bf5xx_i2s_pcm_data tx_dma_data;
+       struct bf5xx_i2s_pcm_data rx_dma_data;
 };
 
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
@@ -74,7 +82,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                ret = -EINVAL;
                break;
        default:
-               printk(KERN_ERR "%s: Unknown DAI format type\n", __func__);
+               dev_err(cpu_dai->dev, "%s: Unknown DAI format type\n",
+                       __func__);
                ret = -EINVAL;
                break;
        }
@@ -88,7 +97,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                ret = -EINVAL;
                break;
        default:
-               printk(KERN_ERR "%s: Unknown DAI master type\n", __func__);
+               dev_err(cpu_dai->dev, "%s: Unknown DAI master type\n",
+                       __func__);
                ret = -EINVAL;
                break;
        }
@@ -141,14 +151,14 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
                ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
                                      bf5xx_i2s->rcr2, 0, 0);
                if (ret) {
-                       pr_err("SPORT is busy!\n");
+                       dev_err(dai->dev, "SPORT is busy!\n");
                        return -EBUSY;
                }
 
                ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
                                      bf5xx_i2s->tcr2, 0, 0);
                if (ret) {
-                       pr_err("SPORT is busy!\n");
+                       dev_err(dai->dev, "SPORT is busy!\n");
                        return -EBUSY;
                }
        }
@@ -162,18 +172,76 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
        struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
        struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 
-       pr_debug("%s enter\n", __func__);
+       dev_dbg(dai->dev, "%s enter\n", __func__);
        /* No active stream, SPORT is allowed to be configured again. */
        if (!dai->active)
                bf5xx_i2s->configured = 0;
 }
 
+static int bf5xx_i2s_set_channel_map(struct snd_soc_dai *dai,
+               unsigned int tx_num, unsigned int *tx_slot,
+               unsigned int rx_num, unsigned int *rx_slot)
+{
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+       unsigned int tx_mapped = 0, rx_mapped = 0;
+       unsigned int slot;
+       int i;
+
+       if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
+                       (rx_num > BFIN_TDM_DAI_MAX_SLOTS))
+               return -EINVAL;
+
+       for (i = 0; i < tx_num; i++) {
+               slot = tx_slot[i];
+               if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
+                               (!(tx_mapped & (1 << slot)))) {
+                       bf5xx_i2s->tx_dma_data.map[i] = slot;
+                       tx_mapped |= 1 << slot;
+               } else
+                       return -EINVAL;
+       }
+       for (i = 0; i < rx_num; i++) {
+               slot = rx_slot[i];
+               if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
+                               (!(rx_mapped & (1 << slot)))) {
+                       bf5xx_i2s->rx_dma_data.map[i] = slot;
+                       rx_mapped |= 1 << slot;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int bf5xx_i2s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+       unsigned int rx_mask, int slots, int width)
+{
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+
+       if (slots % 8 != 0 || slots > 8)
+               return -EINVAL;
+
+       if (width != 32)
+               return -EINVAL;
+
+       bf5xx_i2s->slots = slots;
+       bf5xx_i2s->tx_mask = tx_mask;
+       bf5xx_i2s->rx_mask = rx_mask;
+
+       bf5xx_i2s->tx_dma_data.tdm_mode = slots != 0;
+       bf5xx_i2s->rx_dma_data.tdm_mode = slots != 0;
+
+       return sport_set_multichannel(sport_handle, slots, tx_mask, rx_mask, 0);
+}
+
 #ifdef CONFIG_PM
 static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 {
        struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
 
-       pr_debug("%s : sport %d\n", __func__, dai->id);
+       dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
 
        if (dai->capture_active)
                sport_rx_stop(sport_handle);
@@ -188,23 +256,24 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
        struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
        int ret;
 
-       pr_debug("%s : sport %d\n", __func__, dai->id);
+       dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
 
        ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
                                      bf5xx_i2s->rcr2, 0, 0);
        if (ret) {
-               pr_err("SPORT is busy!\n");
+               dev_err(dai->dev, "SPORT is busy!\n");
                return -EBUSY;
        }
 
        ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
                                      bf5xx_i2s->tcr2, 0, 0);
        if (ret) {
-               pr_err("SPORT is busy!\n");
+               dev_err(dai->dev, "SPORT is busy!\n");
                return -EBUSY;
        }
 
-       return 0;
+       return sport_set_multichannel(sport_handle, bf5xx_i2s->slots,
+                       bf5xx_i2s->tx_mask, bf5xx_i2s->rx_mask, 0);
 }
 
 #else
@@ -212,6 +281,23 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 #define bf5xx_i2s_resume       NULL
 #endif
 
+static int bf5xx_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+       struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+       unsigned int i;
+
+       for (i = 0; i < BFIN_TDM_DAI_MAX_SLOTS; i++) {
+               bf5xx_i2s->tx_dma_data.map[i] = i;
+               bf5xx_i2s->rx_dma_data.map[i] = i;
+       }
+
+       dai->playback_dma_data = &bf5xx_i2s->tx_dma_data;
+       dai->capture_dma_data = &bf5xx_i2s->rx_dma_data;
+
+       return 0;
+}
+
 #define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
@@ -224,22 +310,25 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
         SNDRV_PCM_FMTBIT_S32_LE)
 
 static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
-       .shutdown       = bf5xx_i2s_shutdown,
-       .hw_params      = bf5xx_i2s_hw_params,
-       .set_fmt        = bf5xx_i2s_set_dai_fmt,
+       .shutdown        = bf5xx_i2s_shutdown,
+       .hw_params       = bf5xx_i2s_hw_params,
+       .set_fmt         = bf5xx_i2s_set_dai_fmt,
+       .set_tdm_slot    = bf5xx_i2s_set_tdm_slot,
+       .set_channel_map = bf5xx_i2s_set_channel_map,
 };
 
 static struct snd_soc_dai_driver bf5xx_i2s_dai = {
+       .probe = bf5xx_i2s_dai_probe,
        .suspend = bf5xx_i2s_suspend,
        .resume = bf5xx_i2s_resume,
        .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
+               .channels_min = 2,
+               .channels_max = 8,
                .rates = BF5XX_I2S_RATES,
                .formats = BF5XX_I2S_FORMATS,},
        .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
+               .channels_min = 2,
+               .channels_max = 8,
                .rates = BF5XX_I2S_RATES,
                .formats = BF5XX_I2S_FORMATS,},
        .ops = &bf5xx_i2s_dai_ops,
@@ -255,7 +344,7 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
        int ret;
 
        /* configure SPORT for I2S */
-       sport_handle = sport_init(pdev, 4, 2 * sizeof(u32),
+       sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
                sizeof(struct bf5xx_i2s_port));
        if (!sport_handle)
                return -ENODEV;
@@ -264,7 +353,7 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
        ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
                                         &bf5xx_i2s_dai, 1);
        if (ret) {
-               pr_err("Failed to register DAI: %d\n", ret);
+               dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
                sport_done(sport_handle);
                return ret;
        }
@@ -276,7 +365,7 @@ static int bf5xx_i2s_remove(struct platform_device *pdev)
 {
        struct sport_device *sport_handle = platform_get_drvdata(pdev);
 
-       pr_debug("%s enter\n", __func__);
+       dev_dbg(&pdev->dev, "%s enter\n", __func__);
 
        snd_soc_unregister_component(&pdev->dev);
        sport_done(sport_handle);
index 2fd9f2a06968b8122f83325eccc4cbe1d885e751..695351241db89cb1ab0f4ec0c1d114edbdb501e9 100644 (file)
 /* note: multichannel is in units of 8 channels,
  * tdm_count is # channels NOT / 8 ! */
 int sport_set_multichannel(struct sport_device *sport,
-               int tdm_count, u32 mask, int packed)
+               int tdm_count, u32 tx_mask, u32 rx_mask, int packed)
 {
-       pr_debug("%s tdm_count=%d mask:0x%08x packed=%d\n", __func__,
-                       tdm_count, mask, packed);
+       pr_debug("%s tdm_count=%d tx_mask:0x%08x rx_mask:0x%08x packed=%d\n",
+                       __func__, tdm_count, tx_mask, rx_mask, packed);
 
        if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
                return -EBUSY;
@@ -65,8 +65,8 @@ int sport_set_multichannel(struct sport_device *sport,
                sport->regs->mcmc2 = FRAME_DELAY | MCMEN | \
                                (packed ? (MCDTXPE|MCDRXPE) : 0);
 
-               sport->regs->mtcs0 = mask;
-               sport->regs->mrcs0 = mask;
+               sport->regs->mtcs0 = tx_mask;
+               sport->regs->mrcs0 = rx_mask;
                sport->regs->mtcs1 = 0;
                sport->regs->mrcs1 = 0;
                sport->regs->mtcs2 = 0;
index 5ab60bd613ea314cfc73b3219f07282b8945f8f2..9fc2192feb3bde2e0a5bc7b48e5498a43e7ac357 100644 (file)
@@ -128,7 +128,7 @@ void sport_done(struct sport_device *sport);
 /* note: multichannel is in units of 8 channels, tdm_count is number of channels
  *  NOT / 8 ! all channels are enabled by default */
 int sport_set_multichannel(struct sport_device *sport, int tdm_count,
-               u32 mask, int packed);
+               u32 tx_mask, u32 rx_mask, int packed);
 
 int sport_config_rx(struct sport_device *sport,
                unsigned int rcr1, unsigned int rcr2,
index 7dbeef1099b48de868d3fd724c93db45a64a0206..9c19ccc936e279bbf09583dce23e2ae9e3bd7b97 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/gpio.h>
 #include "../codecs/ssm2602.h"
 #include "bf5xx-sport.h"
-#include "bf5xx-i2s-pcm.h"
 
 static struct snd_soc_card bf5xx_ssm2602;
 
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
deleted file mode 100644 (file)
index 0e6b888..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * File:         sound/soc/blackfin/bf5xx-tdm-pcm.c
- * Author:       Barry Song <Barry.Song@analog.com>
- *
- * Created:      Tue June 06 2009
- * Description:  DMA driver for tdm codec
- *
- * Modified:
- *               Copyright 2009 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/gfp.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-
-#include "bf5xx-tdm-pcm.h"
-#include "bf5xx-tdm.h"
-#include "bf5xx-sport.h"
-
-#define PCM_BUFFER_MAX  0x8000
-#define FRAGMENT_SIZE_MIN  (4*1024)
-#define FRAGMENTS_MIN  2
-#define FRAGMENTS_MAX  32
-
-static void bf5xx_dma_irq(void *data)
-{
-       struct snd_pcm_substream *pcm = data;
-       snd_pcm_period_elapsed(pcm);
-}
-
-static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
-       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-               SNDRV_PCM_INFO_RESUME),
-       .formats =          SNDRV_PCM_FMTBIT_S32_LE,
-       .rates =            SNDRV_PCM_RATE_48000,
-       .channels_min =     2,
-       .channels_max =     8,
-       .buffer_bytes_max = PCM_BUFFER_MAX,
-       .period_bytes_min = FRAGMENT_SIZE_MIN,
-       .period_bytes_max = PCM_BUFFER_MAX/2,
-       .periods_min =      FRAGMENTS_MIN,
-       .periods_max =      FRAGMENTS_MAX,
-};
-
-static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
-       snd_pcm_lib_malloc_pages(substream, size * 4);
-
-       return 0;
-}
-
-static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       snd_pcm_lib_free_pages(substream);
-
-       return 0;
-}
-
-static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sport_device *sport = runtime->private_data;
-       int fragsize_bytes = frames_to_bytes(runtime, runtime->period_size);
-
-       fragsize_bytes /= runtime->channels;
-       /* inflate the fragsize to match the dma width of SPORT */
-       fragsize_bytes *= 8;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
-               sport_config_tx_dma(sport, runtime->dma_area,
-                       runtime->periods, fragsize_bytes);
-       } else {
-               sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
-               sport_config_rx_dma(sport, runtime->dma_area,
-                       runtime->periods, fragsize_bytes);
-       }
-
-       return 0;
-}
-
-static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sport_device *sport = runtime->private_data;
-       int ret = 0;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       sport_tx_start(sport);
-               else
-                       sport_rx_start(sport);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       sport_tx_stop(sport);
-               else
-                       sport_rx_stop(sport);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sport_device *sport = runtime->private_data;
-       unsigned int diff;
-       snd_pcm_uframes_t frames;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               diff = sport_curr_offset_tx(sport);
-               frames = diff / (8*4); /* 32 bytes per frame */
-       } else {
-               diff = sport_curr_offset_rx(sport);
-               frames = diff / (8*4);
-       }
-       return frames;
-}
-
-static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-
-       int ret = 0;
-
-       snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
-
-       ret = snd_pcm_hw_constraint_integer(runtime,
-               SNDRV_PCM_HW_PARAM_PERIODS);
-       if (ret < 0)
-               goto out;
-
-       if (sport_handle != NULL) {
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       sport_handle->tx_buf = buf->area;
-               else
-                       sport_handle->rx_buf = buf->area;
-
-               runtime->private_data = sport_handle;
-       } else {
-               pr_err("sport_handle is NULL\n");
-               ret = -ENODEV;
-       }
-out:
-       return ret;
-}
-
-static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
-       snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct sport_device *sport = runtime->private_data;
-       struct bf5xx_tdm_port *tdm_port = sport->private_data;
-       unsigned int *src;
-       unsigned int *dst;
-       int i;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               src = buf;
-               dst = (unsigned int *)substream->runtime->dma_area;
-
-               dst += pos * 8;
-               while (count--) {
-                       for (i = 0; i < substream->runtime->channels; i++)
-                               *(dst + tdm_port->tx_map[i]) = *src++;
-                       dst += 8;
-               }
-       } else {
-               src = (unsigned int *)substream->runtime->dma_area;
-               dst = buf;
-
-               src += pos * 8;
-               while (count--) {
-                       for (i = 0; i < substream->runtime->channels; i++)
-                               *dst++ = *(src + tdm_port->rx_map[i]);
-                       src += 8;
-               }
-       }
-
-       return 0;
-}
-
-static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
-       int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
-{
-       unsigned char *buf = substream->runtime->dma_area;
-       buf += pos * 8 * 4;
-       memset(buf, '\0', count * 8 * 4);
-
-       return 0;
-}
-
-
-struct snd_pcm_ops bf5xx_pcm_tdm_ops = {
-       .open           = bf5xx_pcm_open,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = bf5xx_pcm_hw_params,
-       .hw_free        = bf5xx_pcm_hw_free,
-       .prepare        = bf5xx_pcm_prepare,
-       .trigger        = bf5xx_pcm_trigger,
-       .pointer        = bf5xx_pcm_pointer,
-       .copy           = bf5xx_pcm_copy,
-       .silence        = bf5xx_pcm_silence,
-};
-
-static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_coherent(pcm->card->dev, size * 4,
-               &buf->addr, GFP_KERNEL);
-       if (!buf->area) {
-               pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n");
-               return -ENOMEM;
-       }
-       buf->bytes = size;
-
-       return 0;
-}
-
-static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-               dma_free_coherent(NULL, buf->bytes, buf->area, 0);
-               buf->area = NULL;
-       }
-}
-
-static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
-
-static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret = 0;
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &bf5xx_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
-out:
-       return ret;
-}
-
-static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
-       .ops        = &bf5xx_pcm_tdm_ops,
-       .pcm_new        = bf5xx_pcm_tdm_new,
-       .pcm_free       = bf5xx_pcm_free_dma_buffers,
-};
-
-static int bf5xx_soc_platform_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
-}
-
-static int bf5xx_soc_platform_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver bfin_tdm_driver = {
-       .driver = {
-                       .name = "bfin-tdm-pcm-audio",
-                       .owner = THIS_MODULE,
-       },
-
-       .probe = bf5xx_soc_platform_probe,
-       .remove = bf5xx_soc_platform_remove,
-};
-
-module_platform_driver(bfin_tdm_driver);
-
-MODULE_AUTHOR("Barry Song");
-MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.h b/sound/soc/blackfin/bf5xx-tdm-pcm.h
deleted file mode 100644 (file)
index 7f8cc01..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * sound/soc/blackfin/bf5xx-tdm-pcm.h -- ALSA PCM interface for the Blackfin
- *
- * Copyright 2009 Analog Device 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.
- */
-
-#ifndef _BF5XX_TDM_PCM_H
-#define _BF5XX_TDM_PCM_H
-
-struct bf5xx_pcm_dma_params {
-       char *name;                     /* stream identifier */
-};
-
-#endif
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
deleted file mode 100644 (file)
index 69e9a3e..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * File:         sound/soc/blackfin/bf5xx-tdm.c
- * Author:       Barry Song <Barry.Song@analog.com>
- *
- * Created:      Thurs June 04 2009
- * Description:  Blackfin I2S(TDM) CPU DAI driver
- *              Even though TDM mode can be as part of I2S DAI, but there
- *              are so much difference in configuration and data flow,
- *              it's very ugly to integrate I2S and TDM into a module
- *
- * Modified:
- *               Copyright 2009 Analog Devices Inc.
- *
- * Bugs:         Enter bugs at http://blackfin.uclinux.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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <asm/irq.h>
-#include <asm/portmux.h>
-#include <linux/mutex.h>
-#include <linux/gpio.h>
-
-#include "bf5xx-sport.h"
-#include "bf5xx-tdm.h"
-
-static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
-       unsigned int fmt)
-{
-       int ret = 0;
-
-       /* interface format:support TDM,slave mode */
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_DSP_A:
-               break;
-       default:
-               printk(KERN_ERR "%s: Unknown DAI format type\n", __func__);
-               ret = -EINVAL;
-               break;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               break;
-       case SND_SOC_DAIFMT_CBS_CFS:
-       case SND_SOC_DAIFMT_CBM_CFS:
-       case SND_SOC_DAIFMT_CBS_CFM:
-               ret = -EINVAL;
-               break;
-       default:
-               printk(KERN_ERR "%s: Unknown DAI master type\n", __func__);
-               ret = -EINVAL;
-               break;
-       }
-
-       return ret;
-}
-
-static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params,
-       struct snd_soc_dai *dai)
-{
-       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
-       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
-       int ret = 0;
-
-       bf5xx_tdm->tcr2 &= ~0x1f;
-       bf5xx_tdm->rcr2 &= ~0x1f;
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S32_LE:
-               bf5xx_tdm->tcr2 |= 31;
-               bf5xx_tdm->rcr2 |= 31;
-               sport_handle->wdsize = 4;
-               break;
-               /* at present, we only support 32bit transfer */
-       default:
-               pr_err("not supported PCM format yet\n");
-               return -EINVAL;
-               break;
-       }
-
-       if (!bf5xx_tdm->configured) {
-               /*
-                * TX and RX are not independent,they are enabled at the
-                * same time, even if only one side is running. So, we
-                * need to configure both of them at the time when the first
-                * stream is opened.
-                *
-                * CPU DAI:slave mode.
-                */
-               ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1,
-                       bf5xx_tdm->rcr2, 0, 0);
-               if (ret) {
-                       pr_err("SPORT is busy!\n");
-                       return -EBUSY;
-               }
-
-               ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1,
-                       bf5xx_tdm->tcr2, 0, 0);
-               if (ret) {
-                       pr_err("SPORT is busy!\n");
-                       return -EBUSY;
-               }
-
-               bf5xx_tdm->configured = 1;
-       }
-
-       return 0;
-}
-
-static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
-       struct snd_soc_dai *dai)
-{
-       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
-       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
-
-       /* No active stream, SPORT is allowed to be configured again. */
-       if (!dai->active)
-               bf5xx_tdm->configured = 0;
-}
-
-static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
-               unsigned int tx_num, unsigned int *tx_slot,
-               unsigned int rx_num, unsigned int *rx_slot)
-{
-       struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
-       struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
-       int i;
-       unsigned int slot;
-       unsigned int tx_mapped = 0, rx_mapped = 0;
-
-       if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
-                       (rx_num > BFIN_TDM_DAI_MAX_SLOTS))
-               return -EINVAL;
-
-       for (i = 0; i < tx_num; i++) {
-               slot = tx_slot[i];
-               if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
-                               (!(tx_mapped & (1 << slot)))) {
-                       bf5xx_tdm->tx_map[i] = slot;
-                       tx_mapped |= 1 << slot;
-               } else
-                       return -EINVAL;
-       }
-       for (i = 0; i < rx_num; i++) {
-               slot = rx_slot[i];
-               if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
-                               (!(rx_mapped & (1 << slot)))) {
-                       bf5xx_tdm->rx_map[i] = slot;
-                       rx_mapped |= 1 << slot;
-               } else
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
-{
-       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
-
-       if (dai->playback_active)
-               sport_tx_stop(sport);
-       if (dai->capture_active)
-               sport_rx_stop(sport);
-
-       /* isolate sync/clock pins from codec while sports resume */
-       peripheral_free_list(sport->pin_req);
-
-       return 0;
-}
-
-static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
-{
-       int ret;
-       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
-
-       ret = sport_set_multichannel(sport, 8, 0xFF, 1);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-       }
-
-       ret = sport_config_rx(sport, 0, 0x1F, 0, 0);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-       }
-
-       ret = sport_config_tx(sport, 0, 0x1F, 0, 0);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-       }
-
-       peripheral_request_list(sport->pin_req, "soc-audio");
-
-       return 0;
-}
-
-#else
-#define bf5xx_tdm_suspend      NULL
-#define bf5xx_tdm_resume       NULL
-#endif
-
-static const struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
-       .hw_params      = bf5xx_tdm_hw_params,
-       .set_fmt        = bf5xx_tdm_set_dai_fmt,
-       .shutdown       = bf5xx_tdm_shutdown,
-       .set_channel_map   = bf5xx_tdm_set_channel_map,
-};
-
-static struct snd_soc_dai_driver bf5xx_tdm_dai = {
-       .suspend = bf5xx_tdm_suspend,
-       .resume = bf5xx_tdm_resume,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 8,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S32_LE,},
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 8,
-               .rates = SNDRV_PCM_RATE_48000,
-               .formats = SNDRV_PCM_FMTBIT_S32_LE,},
-       .ops = &bf5xx_tdm_dai_ops,
-};
-
-static const struct snd_soc_component_driver bf5xx_tdm_component = {
-       .name           = "bf5xx-tdm",
-};
-
-static int bfin_tdm_probe(struct platform_device *pdev)
-{
-       struct sport_device *sport_handle;
-       int ret;
-
-       /* configure SPORT for TDM */
-       sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
-               sizeof(struct bf5xx_tdm_port));
-       if (!sport_handle)
-               return -ENODEV;
-
-       /* SPORT works in TDM mode */
-       ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-               goto sport_config_err;
-       }
-
-       ret = sport_config_rx(sport_handle, 0, 0x1F, 0, 0);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-               goto sport_config_err;
-       }
-
-       ret = sport_config_tx(sport_handle, 0, 0x1F, 0, 0);
-       if (ret) {
-               pr_err("SPORT is busy!\n");
-               ret = -EBUSY;
-               goto sport_config_err;
-       }
-
-       ret = snd_soc_register_component(&pdev->dev, &bf5xx_tdm_component,
-                                        &bf5xx_tdm_dai, 1);
-       if (ret) {
-               pr_err("Failed to register DAI: %d\n", ret);
-               goto sport_config_err;
-       }
-
-       return 0;
-
-sport_config_err:
-       sport_done(sport_handle);
-       return ret;
-}
-
-static int bfin_tdm_remove(struct platform_device *pdev)
-{
-       struct sport_device *sport_handle = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_component(&pdev->dev);
-       sport_done(sport_handle);
-
-       return 0;
-}
-
-static struct platform_driver bfin_tdm_driver = {
-       .probe  = bfin_tdm_probe,
-       .remove = bfin_tdm_remove,
-       .driver = {
-               .name   = "bfin-tdm",
-               .owner  = THIS_MODULE,
-       },
-};
-
-module_platform_driver(bfin_tdm_driver);
-
-/* Module information */
-MODULE_AUTHOR("Barry Song");
-MODULE_DESCRIPTION("TDM driver for ADI Blackfin");
-MODULE_LICENSE("GPL");
-
diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h
deleted file mode 100644 (file)
index e986a3e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * sound/soc/blackfin/bf5xx-tdm.h
- *
- * 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 _BF5XX_TDM_H
-#define _BF5XX_TDM_H
-
-#define BFIN_TDM_DAI_MAX_SLOTS 8
-struct bf5xx_tdm_port {
-       u16 tcr1;
-       u16 rcr1;
-       u16 tcr2;
-       u16 rcr2;
-       unsigned int tx_map[BFIN_TDM_DAI_MAX_SLOTS];
-       unsigned int rx_map[BFIN_TDM_DAI_MAX_SLOTS];
-       int configured;
-};
-
-#endif
index 88143db7e7537acd96eea026d91427a29983755d..2c20f01e1f7e8b8d8d6d623bba45288e2bedeb1a 100644 (file)
@@ -1,7 +1,7 @@
 config SND_EP93XX_SOC
        tristate "SoC Audio support for the Cirrus Logic EP93xx series"
        depends on ARCH_EP93XX && SND_SOC
-       select SND_SOC_DMAENGINE_PCM
+       select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M if you want to add support for codecs attached to
          the EP93xx I2S or AC97 interfaces.
index 7798fbd5e81dac21ca7c5c6bb54836786510bd79..ac73c607410a73d92ff84a817c22bf6a99c25d5f 100644 (file)
@@ -237,13 +237,12 @@ static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops ep93xx_ac97_ops = {
        .read           = ep93xx_ac97_read,
        .write          = ep93xx_ac97_write,
        .reset          = ep93xx_ac97_cold_reset,
        .warm_reset     = ep93xx_ac97_warm_reset,
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
                               int cmd, struct snd_soc_dai *dai)
@@ -314,22 +313,15 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
-                              struct snd_soc_dai *dai)
+static int ep93xx_ac97_dai_probe(struct snd_soc_dai *dai)
 {
-       struct ep93xx_dma_data *dma_data;
+       dai->playback_dma_data = &ep93xx_ac97_pcm_out;
+       dai->capture_dma_data = &ep93xx_ac97_pcm_in;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = &ep93xx_ac97_pcm_out;
-       else
-               dma_data = &ep93xx_ac97_pcm_in;
-
-       snd_soc_dai_set_dma_data(dai, substream, dma_data);
        return 0;
 }
 
 static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
-       .startup        = ep93xx_ac97_startup,
        .trigger        = ep93xx_ac97_trigger,
 };
 
@@ -337,6 +329,7 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = {
        .name           = "ep93xx-ac97",
        .id             = 0,
        .ac97_control   = 1,
+       .probe          = ep93xx_ac97_dai_probe,
        .playback       = {
                .stream_name    = "AC97 Playback",
                .channels_min   = 2,
@@ -395,6 +388,10 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
        ep93xx_ac97_info = info;
        platform_set_drvdata(pdev, info);
 
+       ret = snd_soc_set_ac97_ops(&ep93xx_ac97_ops);
+       if (ret)
+               goto fail;
+
        ret = snd_soc_register_component(&pdev->dev, &ep93xx_ac97_component,
                                         &ep93xx_ac97_dai, 1);
        if (ret)
@@ -403,9 +400,8 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
        return 0;
 
 fail:
-       platform_set_drvdata(pdev, NULL);
        ep93xx_ac97_info = NULL;
-       dev_set_drvdata(&pdev->dev, NULL);
+       snd_soc_set_ac97_ops(NULL);
        return ret;
 }
 
@@ -418,9 +414,9 @@ static int ep93xx_ac97_remove(struct platform_device *pdev)
        /* disable the AC97 controller */
        ep93xx_ac97_write_reg(info, AC97GCR, 0);
 
-       platform_set_drvdata(pdev, NULL);
        ep93xx_ac97_info = NULL;
-       dev_set_drvdata(&pdev->dev, NULL);
+
+       snd_soc_set_ac97_ops(NULL);
 
        return 0;
 }
index 5c1102e9e1598823b8eac35bfe72b3b203dcb5f7..17ad70bca9fe5828d4a8b3b5327dfc6b30bdb260 100644 (file)
@@ -60,11 +60,10 @@ struct ep93xx_i2s_info {
        struct clk                      *mclk;
        struct clk                      *sclk;
        struct clk                      *lrclk;
-       struct ep93xx_dma_data          *dma_data;
        void __iomem                    *regs;
 };
 
-struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
+static struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
        [SNDRV_PCM_STREAM_PLAYBACK] = {
                .name           = "i2s-pcm-out",
                .port           = EP93XX_DMA_I2S1,
@@ -139,15 +138,11 @@ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
        }
 }
 
-static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
-                             struct snd_soc_dai *dai)
+static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       dai->playback_dma_data = &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+       dai->capture_dma_data = &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_CAPTURE];
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream,
-                                &info->dma_data[substream->stream]);
        return 0;
 }
 
@@ -338,7 +333,6 @@ static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
 #endif
 
 static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
-       .startup        = ep93xx_i2s_startup,
        .shutdown       = ep93xx_i2s_shutdown,
        .hw_params      = ep93xx_i2s_hw_params,
        .set_sysclk     = ep93xx_i2s_set_sysclk,
@@ -349,6 +343,7 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
 
 static struct snd_soc_dai_driver ep93xx_i2s_dai = {
        .symmetric_rates= 1,
+       .probe          = ep93xx_i2s_dai_probe,
        .suspend        = ep93xx_i2s_suspend,
        .resume         = ep93xx_i2s_resume,
        .playback       = {
@@ -407,7 +402,6 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
        }
 
        dev_set_drvdata(&pdev->dev, info);
-       info->dma_data = ep93xx_i2s_dma_data;
 
        err = snd_soc_register_component(&pdev->dev, &ep93xx_i2s_component,
                                         &ep93xx_i2s_dai, 1);
index 48803269037847ef7ad272fc07d61dc6d6590d0f..0e9f56e0d4b2e7e6031cb30ecd007c7da04ba693 100644 (file)
 
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/device.h>
-#include <linux/slab.h>
+#include <linux/platform_device.h>
 #include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
 
-#include <sound/core.h>
 #include <sound/pcm.h>
-#include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
 
 #include <linux/platform_data/dma-ep93xx.h>
-#include <mach/hardware.h>
-#include <mach/ep93xx-regs.h>
 
 static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
        .info                   = (SNDRV_PCM_INFO_MMAP          |
@@ -63,134 +57,24 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
        return false;
 }
 
-static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
-
-       return snd_dmaengine_pcm_open_request_chan(substream,
-                       ep93xx_pcm_dma_filter,
-                       snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
-}
-
-static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
-{
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-       return 0;
-}
-
-static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       snd_pcm_set_runtime_buffer(substream, NULL);
-       return 0;
-}
-
-static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
-                          struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                                    runtime->dma_area,
-                                    runtime->dma_addr,
-                                    runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops ep93xx_pcm_ops = {
-       .open           = ep93xx_pcm_open,
-       .close          = snd_dmaengine_pcm_close_release_chan,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = ep93xx_pcm_hw_params,
-       .hw_free        = ep93xx_pcm_hw_free,
-       .trigger        = snd_dmaengine_pcm_trigger,
-       .pointer        = snd_dmaengine_pcm_pointer_no_residue,
-       .mmap           = ep93xx_pcm_mmap,
-};
-
-static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = ep93xx_pcm_hardware.buffer_bytes_max;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                                          &buf->addr, GFP_KERNEL);
-       buf->bytes = size;
-
-       return (buf->area == NULL) ? -ENOMEM : 0;
-}
-
-static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {                
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-               
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
-                                     buf->addr);
-               buf->area = NULL;
-       }
-}
-
-static u64 ep93xx_pcm_dmamask = DMA_BIT_MASK(32);
-
-static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret = 0;
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &ep93xx_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
-                                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       return ret;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
-                                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_platform_driver ep93xx_soc_platform = {
-       .ops            = &ep93xx_pcm_ops,
-       .pcm_new        = &ep93xx_pcm_new,
-       .pcm_free       = &ep93xx_pcm_free_dma_buffers,
+static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = {
+       .pcm_hardware = &ep93xx_pcm_hardware,
+       .compat_filter_fn = ep93xx_pcm_dma_filter,
+       .prealloc_buffer_size = 131072,
 };
 
 static int ep93xx_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform);
+       return snd_dmaengine_pcm_register(&pdev->dev,
+               &ep93xx_dmaengine_pcm_config,
+               SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
+               SND_DMAENGINE_PCM_FLAG_NO_DT |
+               SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 
 static int ep93xx_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&pdev->dev);
+       snd_dmaengine_pcm_unregister(&pdev->dev);
        return 0;
 }
 
index 60159c07448da792e62e8e68f61e7d48d7ec04a4..8af04343cc1ac9eab35fe951fd079fd1954da462 100644 (file)
  * before DAC & PGA in DAPM power-off sequence.
  */
 #define PM860X_DAPM_OUTPUT(wname, wevent)      \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
-       .shift = 0, .invert = 0, .kcontrol_news = NULL, \
-       .num_kcontrols = 0, .event = wevent, \
-       .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
+       SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, 0, 0, NULL, 0, wevent, \
+                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD)
 
 struct pm860x_det {
        struct snd_soc_jack     *hp_jack;
@@ -1444,7 +1442,7 @@ static int pm860x_codec_probe(struct platform_device *pdev)
                res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
                if (!res) {
                        dev_err(&pdev->dev, "Failed to get IRQ resources\n");
-                       goto out;
+                       return -EINVAL;
                }
                pm860x->irq[i] = res->start + chip->irq_base;
                strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
@@ -1454,19 +1452,14 @@ static int pm860x_codec_probe(struct platform_device *pdev)
                                     pm860x_dai, ARRAY_SIZE(pm860x_dai));
        if (ret) {
                dev_err(&pdev->dev, "Failed to register codec\n");
-               goto out;
+               return -EINVAL;
        }
        return ret;
-
-out:
-       platform_set_drvdata(pdev, NULL);
-       return -EINVAL;
 }
 
 static int pm860x_codec_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 2f45f00e31b024bf758a25087f4f0f8f82708030..badb6fbacaa66222bea9cef708c1379783746c7f 100644 (file)
@@ -19,7 +19,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AD1980 if SND_SOC_AC97_BUS
        select SND_SOC_AD73311
        select SND_SOC_ADAU1373 if I2C
-       select SND_SOC_ADAV80X
+       select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
        select SND_SOC_ADS117X
        select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
@@ -40,7 +40,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_DA7213 if I2C
        select SND_SOC_DA732X if I2C
        select SND_SOC_DA9055 if I2C
-       select SND_SOC_DFBMCS320
+       select SND_SOC_BT_SCO
        select SND_SOC_ISABELLE if I2C
        select SND_SOC_JZ4740_CODEC
        select SND_SOC_LM4857 if I2C
@@ -53,13 +53,15 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_MAX9877 if I2C
        select SND_SOC_MC13783 if MFD_MC13XXX
        select SND_SOC_ML26124 if I2C
-       select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI
+       select SND_SOC_HDMI_CODEC
        select SND_SOC_PCM3008
        select SND_SOC_RT5631 if I2C
+       select SND_SOC_RT5640 if I2C
        select SND_SOC_SGTL5000 if I2C
        select SND_SOC_SI476X if MFD_SI476X_CORE
        select SND_SOC_SN95031 if INTEL_SCU_IPC
        select SND_SOC_SPDIF
+       select SND_SOC_SSM2518 if I2C
        select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
        select SND_SOC_STA32X if I2C
        select SND_SOC_STA529 if I2C
@@ -263,7 +265,7 @@ config SND_SOC_DA732X
 config SND_SOC_DA9055
        tristate
 
-config SND_SOC_DFBMCS320
+config SND_SOC_BT_SCO
        tristate
 
 config SND_SOC_DMIC
@@ -287,7 +289,7 @@ config SND_SOC_MAX98095
 config SND_SOC_MAX9850
        tristate
 
-config SND_SOC_OMAP_HDMI_CODEC
+config SND_SOC_HDMI_CODEC
        tristate
 
 config SND_SOC_PCM3008
@@ -296,6 +298,9 @@ config SND_SOC_PCM3008
 config SND_SOC_RT5631
        tristate
 
+config SND_SOC_RT5640
+       tristate
+
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
        tristate
@@ -313,6 +318,9 @@ config SND_SOC_SN95031
 config SND_SOC_SPDIF
        tristate
 
+config SND_SOC_SSM2518
+       tristate
+
 config SND_SOC_SSM2602
        tristate
 
index b9e41c9a1f4cfa26d7681f0249d3d26e328f7466..70fd8066f546e9cfc39dcb024f1efa6e5ea6bf1f 100644 (file)
@@ -27,7 +27,7 @@ snd-soc-da7210-objs := da7210.o
 snd-soc-da7213-objs := da7213.o
 snd-soc-da732x-objs := da732x.o
 snd-soc-da9055-objs := da9055.o
-snd-soc-dfbmcs320-objs := dfbmcs320.o
+snd-soc-bt-sco-objs := bt-sco.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
@@ -41,17 +41,19 @@ snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
-snd-soc-omap-hdmi-codec-objs := omap-hdmi.o
+snd-soc-hdmi-codec-objs := hdmi.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-rt5631-objs := rt5631.o
+snd-soc-rt5640-objs := rt5640.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-alc5623-objs := alc5623.o
 snd-soc-alc5632-objs := alc5632.o
 snd-soc-sigmadsp-objs := sigmadsp.o
 snd-soc-si476x-objs := si476x.o
 snd-soc-sn95031-objs := sn95031.o
-snd-soc-spdif-tx-objs := spdif_transciever.o
+snd-soc-spdif-tx-objs := spdif_transmitter.o
 snd-soc-spdif-rx-objs := spdif_receiver.o
+snd-soc-ssm2518-objs := ssm2518.o
 snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-sta32x-objs := sta32x.o
 snd-soc-sta529-objs := sta529.o
@@ -154,7 +156,7 @@ obj-$(CONFIG_SND_SOC_DA7210)        += snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DA7213)   += snd-soc-da7213.o
 obj-$(CONFIG_SND_SOC_DA732X)   += snd-soc-da732x.o
 obj-$(CONFIG_SND_SOC_DA9055)   += snd-soc-da9055.o
-obj-$(CONFIG_SND_SOC_DFBMCS320)        += snd-soc-dfbmcs320.o
+obj-$(CONFIG_SND_SOC_BT_SCO)   += snd-soc-bt-sco.o
 obj-$(CONFIG_SND_SOC_DMIC)     += snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
@@ -168,14 +170,16 @@ obj-$(CONFIG_SND_SOC_MAX98095)    += snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
-obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o
+obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
+obj-$(CONFIG_SND_SOC_RT5640)   += snd-soc-rt5640.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
 obj-$(CONFIG_SND_SOC_SI476X)   += snd-soc-si476x.o
 obj-$(CONFIG_SND_SOC_SN95031)  +=snd-soc-sn95031.o
 obj-$(CONFIG_SND_SOC_SPDIF)    += snd-soc-spdif-rx.o snd-soc-spdif-tx.o
+obj-$(CONFIG_SND_SOC_SSM2518)  += snd-soc-ssm2518.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
index a153b168129bc493fae94cd58c88bd2bfe7a2cf8..b8ba0adacfce1229989f0114ce25eb9711f61d16 100644 (file)
@@ -1496,6 +1496,12 @@ static const char * const enum_ad_to_slot_map[] = {"AD_OUT1",
                                        "AD_OUT7",
                                        "AD_OUT8",
                                        "zeroes",
+                                       "zeroes",
+                                       "zeroes",
+                                       "zeroes",
+                                       "tristate",
+                                       "tristate",
+                                       "tristate",
                                        "tristate"};
 static SOC_ENUM_SINGLE_DECL(soc_enum_adslot0map,
                        AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_EVEN_SHIFT,
@@ -2230,7 +2236,7 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
                int slots, int slot_width)
 {
        struct snd_soc_codec *codec = dai->codec;
-       unsigned int val, mask, slots_active;
+       unsigned int val, mask, slot, slots_active;
 
        mask = BIT(AB8500_DIGIFCONF2_IF0WL0) |
                BIT(AB8500_DIGIFCONF2_IF0WL1);
@@ -2286,27 +2292,34 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
        snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val);
 
        /* Setup TDM DA according to active tx slots */
+
+       if (tx_mask & ~0xff)
+               return -EINVAL;
+
        mask = AB8500_DASLOTCONFX_SLTODAX_MASK;
+       tx_mask = tx_mask << AB8500_DA_DATA0_OFFSET;
        slots_active = hweight32(tx_mask);
+
        dev_dbg(dai->codec->dev, "%s: Slots, active, TX: %d\n", __func__,
                slots_active);
+
        switch (slots_active) {
        case 0:
                break;
        case 1:
-               /* Slot 9 -> DA_IN1 & DA_IN3 */
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 11);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 11);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11);
+               slot = find_first_bit((unsigned long *)&tx_mask, 32);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
                break;
        case 2:
-               /* Slot 9 -> DA_IN1 & DA_IN3, Slot 11 -> DA_IN2 & DA_IN4 */
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 9);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 9);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11);
-               snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11);
-
+               slot = find_first_bit((unsigned long *)&tx_mask, 32);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
+               slot = find_next_bit((unsigned long *)&tx_mask, 32, slot + 1);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
+               snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
                break;
        case 8:
                dev_dbg(dai->codec->dev,
@@ -2321,25 +2334,36 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
        }
 
        /* Setup TDM AD according to active RX-slots */
+
+       if (rx_mask & ~0xff)
+               return -EINVAL;
+
+       rx_mask = rx_mask << AB8500_AD_DATA0_OFFSET;
        slots_active = hweight32(rx_mask);
+
        dev_dbg(dai->codec->dev, "%s: Slots, active, RX: %d\n", __func__,
                slots_active);
+
        switch (slots_active) {
        case 0:
                break;
        case 1:
-               /* AD_OUT3 -> slot 0 & 1 */
-               snd_soc_update_bits(codec, AB8500_ADSLOTSEL1, AB8500_MASK_ALL,
-                               AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN |
-                               AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD);
+               slot = find_first_bit((unsigned long *)&rx_mask, 32);
+               snd_soc_update_bits(codec, AB8500_ADSLOTSEL(slot),
+                               AB8500_MASK_SLOT(slot),
+                               AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
                break;
        case 2:
-               /* AD_OUT3 -> slot 0, AD_OUT2 -> slot 1 */
+               slot = find_first_bit((unsigned long *)&rx_mask, 32);
                snd_soc_update_bits(codec,
-                               AB8500_ADSLOTSEL1,
-                               AB8500_MASK_ALL,
-                               AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN |
-                               AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD);
+                               AB8500_ADSLOTSEL(slot),
+                               AB8500_MASK_SLOT(slot),
+                               AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
+               slot = find_next_bit((unsigned long *)&rx_mask, 32, slot + 1);
+               snd_soc_update_bits(codec,
+                               AB8500_ADSLOTSEL(slot),
+                               AB8500_MASK_SLOT(slot),
+                               AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT2, slot));
                break;
        case 8:
                dev_dbg(dai->codec->dev,
@@ -2356,6 +2380,11 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
        return 0;
 }
 
+static const struct snd_soc_dai_ops ab8500_codec_ops = {
+       .set_fmt = ab8500_codec_set_dai_fmt,
+       .set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
+};
+
 static struct snd_soc_dai_driver ab8500_codec_dai[] = {
        {
                .name = "ab8500-codec-dai.0",
@@ -2367,12 +2396,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
                        .rates = AB8500_SUPPORTED_RATE,
                        .formats = AB8500_SUPPORTED_FMT,
                },
-               .ops = (struct snd_soc_dai_ops[]) {
-                       {
-                               .set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
-                               .set_fmt = ab8500_codec_set_dai_fmt,
-                       }
-               },
+               .ops = &ab8500_codec_ops,
                .symmetric_rates = 1
        },
        {
@@ -2385,12 +2409,7 @@ static struct snd_soc_dai_driver ab8500_codec_dai[] = {
                        .rates = AB8500_SUPPORTED_RATE,
                        .formats = AB8500_SUPPORTED_FMT,
                },
-               .ops = (struct snd_soc_dai_ops[]) {
-                       {
-                               .set_tdm_slot = ab8500_codec_set_dai_tdm_slot,
-                               .set_fmt = ab8500_codec_set_dai_fmt,
-                       }
-               },
+               .ops = &ab8500_codec_ops,
                .symmetric_rates = 1
        }
 };
index 306d0bc8455faeb202f4c13d87892355350fa0b3..e2e54425d25ef7f8b4e4d295ad824cb676586043 100644 (file)
 #define AB8500_SUPPORTED_RATE                  (SNDRV_PCM_RATE_48000)
 #define AB8500_SUPPORTED_FMT                   (SNDRV_PCM_FMTBIT_S16_LE)
 
+/* AB8500 interface slot offset definitions */
+
+#define AB8500_AD_DATA0_OFFSET 0
+#define AB8500_DA_DATA0_OFFSET 8
+#define AB8500_AD_DATA1_OFFSET 16
+#define AB8500_DA_DATA1_OFFSET 24
+
 /* AB8500 audio bank (0x0d) register definitions */
 
 #define AB8500_POWERUP                         0x00
@@ -73,6 +80,7 @@
 #define AB8500_ADSLOTSEL14                     0x2C
 #define AB8500_ADSLOTSEL15                     0x2D
 #define AB8500_ADSLOTSEL16                     0x2E
+#define AB8500_ADSLOTSEL(slot)                 (AB8500_ADSLOTSEL1 + (slot >> 1))
 #define AB8500_ADSLOTHIZCTRL1                  0x2F
 #define AB8500_ADSLOTHIZCTRL2                  0x30
 #define AB8500_ADSLOTHIZCTRL3                  0x31
 #define AB8500_CACHEREGNUM                     (AB8500_LAST_REG + 1)
 
 #define AB8500_MASK_ALL                                0xFF
+#define AB8500_MASK_SLOT(slot)                 ((slot & 1) ? 0xF0 : 0x0F)
 #define AB8500_MASK_NONE                       0x00
 
 /* AB8500_POWERUP */
 #define AB8500_DIGIFCONF4_IF1WL0               0
 
 /* AB8500_ADSLOTSELX */
-#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_ODD  0x00
-#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD  0x10
-#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD  0x20
-#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_ODD  0x30
-#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_ODD  0x40
-#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_ODD  0x50
-#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_ODD  0x60
-#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_ODD  0x70
-#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_ODD   0x80
-#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_ODD 0xF0
-#define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_EVEN 0x00
-#define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_EVEN 0x01
-#define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN 0x02
-#define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_EVEN 0x03
-#define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_EVEN 0x04
-#define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_EVEN 0x05
-#define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_EVEN 0x06
-#define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_EVEN 0x07
-#define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_EVEN  0x08
-#define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_EVEN        0x0F
+#define AB8500_AD_OUT1 0x0
+#define AB8500_AD_OUT2 0x1
+#define AB8500_AD_OUT3 0x2
+#define AB8500_AD_OUT4 0x3
+#define AB8500_AD_OUT5 0x4
+#define AB8500_AD_OUT6 0x5
+#define AB8500_AD_OUT7 0x6
+#define AB8500_AD_OUT8 0x7
+#define AB8500_ZEROES  0x8
+#define AB8500_TRISTATE        0xF
 #define AB8500_ADSLOTSELX_EVEN_SHIFT           0
 #define AB8500_ADSLOTSELX_ODD_SHIFT            4
+#define AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(out, slot)    \
+       ((out) << (((slot) & 1) ? \
+        AB8500_ADSLOTSELX_ODD_SHIFT : AB8500_ADSLOTSELX_EVEN_SHIFT))
 
 /* AB8500_ADSLOTHIZCTRL1 */
 /* AB8500_ADSLOTHIZCTRL2 */
index ef2ae32ffc669849bbfb791eb657ed4ff2501497..ec7351803c245b7ba209a582e0d82fc958effb24 100644 (file)
@@ -62,13 +62,13 @@ static struct snd_soc_dai_driver ac97_dai = {
 static unsigned int ac97_read(struct snd_soc_codec *codec,
        unsigned int reg)
 {
-       return soc_ac97_ops.read(codec->ac97, reg);
+       return soc_ac97_ops->read(codec->ac97, reg);
 }
 
 static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
        unsigned int val)
 {
-       soc_ac97_ops.write(codec->ac97, reg, val);
+       soc_ac97_ops->write(codec->ac97, reg, val);
        return 0;
 }
 
@@ -79,7 +79,8 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
        int ret;
 
        /* add codec as bus device for standard ac97 */
-       ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus);
+       ret = snd_ac97_bus(codec->card->snd_card, 0, soc_ac97_ops, NULL,
+                          &ac97_bus);
        if (ret < 0)
                return ret;
 
index f385342947d33317118d924fd5a88c44e3b9532c..89fcf7d6e7b8fdfb94bac498c935ad9bf3646fcc 100644 (file)
@@ -108,7 +108,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
        case AC97_EXTENDED_STATUS:
        case AC97_VENDOR_ID1:
        case AC97_VENDOR_ID2:
-               return soc_ac97_ops.read(codec->ac97, reg);
+               return soc_ac97_ops->read(codec->ac97, reg);
        default:
                reg = reg >> 1;
 
@@ -124,7 +124,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 {
        u16 *cache = codec->reg_cache;
 
-       soc_ac97_ops.write(codec->ac97, reg, val);
+       soc_ac97_ops->write(codec->ac97, reg, val);
        reg = reg >> 1;
        if (reg < ARRAY_SIZE(ad1980_reg))
                cache[reg] = val;
@@ -154,13 +154,13 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
        u16 retry_cnt = 0;
 
 retry:
-       if (try_warm && soc_ac97_ops.warm_reset) {
-               soc_ac97_ops.warm_reset(codec->ac97);
+       if (try_warm && soc_ac97_ops->warm_reset) {
+               soc_ac97_ops->warm_reset(codec->ac97);
                if (ac97_read(codec, AC97_RESET) == 0x0090)
                        return 1;
        }
 
-       soc_ac97_ops.reset(codec->ac97);
+       soc_ac97_ops->reset(codec->ac97);
        /* Set bit 16slot in register 74h, then every slot will has only 16
         * bits. This command is sent out in 20bit mode, in which case the
         * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/
@@ -186,7 +186,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
 
        printk(KERN_INFO "AD1980 SoC Audio Codec\n");
 
-       ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+       ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
                return ret;
index dafdbe87edeb56d82369db5f310658a25298ee17..d1124a5b34713c688d92846e25cca563ed9c20ff 100644 (file)
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include "sigmadsp.h"
 #include "adau1701.h"
 
-#define ADAU1701_DSPCTRL       0x1c
-#define ADAU1701_SEROCTL       0x1e
-#define ADAU1701_SERICTL       0x1f
+#define ADAU1701_DSPCTRL       0x081c
+#define ADAU1701_SEROCTL       0x081e
+#define ADAU1701_SERICTL       0x081f
 
-#define ADAU1701_AUXNPOW       0x22
+#define ADAU1701_AUXNPOW       0x0822
+#define ADAU1701_PINCONF_0     0x0820
+#define ADAU1701_PINCONF_1     0x0821
+#define ADAU1701_AUXNPOW       0x0822
 
-#define ADAU1701_OSCIPOW       0x26
-#define ADAU1701_DACSET                0x27
+#define ADAU1701_OSCIPOW       0x0826
+#define ADAU1701_DACSET                0x0827
 
-#define ADAU1701_NUM_REGS      0x28
+#define ADAU1701_MAX_REGISTER  0x0828
 
 #define ADAU1701_DSPCTRL_CR            (1 << 2)
 #define ADAU1701_DSPCTRL_DAM           (1 << 3)
 #define ADAU1701_OSCIPOW_OPD           0x04
 #define ADAU1701_DACSET_DACINIT                1
 
+#define ADAU1707_CLKDIV_UNSET          (-1UL)
+
 #define ADAU1701_FIRMWARE "adau1701.bin"
 
 struct adau1701 {
+       int gpio_nreset;
+       int gpio_pll_mode[2];
        unsigned int dai_fmt;
+       unsigned int pll_clkdiv;
+       unsigned int sysclk;
+       struct regmap *regmap;
+       u8 pin_config[12];
 };
 
 static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -119,10 +134,13 @@ static const struct snd_soc_dapm_route adau1701_dapm_routes[] = {
        { "ADC", NULL, "IN1" },
 };
 
-static unsigned int adau1701_register_size(struct snd_soc_codec *codec,
+static unsigned int adau1701_register_size(struct device *dev,
                unsigned int reg)
 {
        switch (reg) {
+       case ADAU1701_PINCONF_0:
+       case ADAU1701_PINCONF_1:
+               return 3;
        case ADAU1701_DSPCTRL:
        case ADAU1701_SEROCTL:
        case ADAU1701_AUXNPOW:
@@ -133,33 +151,42 @@ static unsigned int adau1701_register_size(struct snd_soc_codec *codec,
                return 1;
        }
 
-       dev_err(codec->dev, "Unsupported register address: %d\n", reg);
+       dev_err(dev, "Unsupported register address: %d\n", reg);
        return 0;
 }
 
-static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg,
-               unsigned int value)
+static bool adau1701_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ADAU1701_DACSET:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static int adau1701_reg_write(void *context, unsigned int reg,
+                             unsigned int value)
 {
+       struct i2c_client *client = context;
        unsigned int i;
        unsigned int size;
-       uint8_t buf[4];
+       uint8_t buf[5];
        int ret;
 
-       size = adau1701_register_size(codec, reg);
+       size = adau1701_register_size(&client->dev, reg);
        if (size == 0)
                return -EINVAL;
 
-       snd_soc_cache_write(codec, reg, value);
-
-       buf[0] = 0x08;
-       buf[1] = reg;
+       buf[0] = reg >> 8;
+       buf[1] = reg & 0xff;
 
        for (i = size + 1; i >= 2; --i) {
                buf[i] = value;
                value >>= 8;
        }
 
-       ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2);
+       ret = i2c_master_send(client, buf, size + 2);
        if (ret == size + 2)
                return 0;
        else if (ret < 0)
@@ -168,21 +195,107 @@ static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg,
                return -EIO;
 }
 
-static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg)
+static int adau1701_reg_read(void *context, unsigned int reg,
+                            unsigned int *value)
 {
-       unsigned int value;
-       unsigned int ret;
+       int ret;
+       unsigned int i;
+       unsigned int size;
+       uint8_t send_buf[2], recv_buf[3];
+       struct i2c_client *client = context;
+       struct i2c_msg msgs[2];
+
+       size = adau1701_register_size(&client->dev, reg);
+       if (size == 0)
+               return -EINVAL;
 
-       ret = snd_soc_cache_read(codec, reg, &value);
-       if (ret)
+       send_buf[0] = reg >> 8;
+       send_buf[1] = reg & 0xff;
+
+       msgs[0].addr = client->addr;
+       msgs[0].len = sizeof(send_buf);
+       msgs[0].buf = send_buf;
+       msgs[0].flags = 0;
+
+       msgs[1].addr = client->addr;
+       msgs[1].len = size;
+       msgs[1].buf = recv_buf;
+       msgs[1].flags = I2C_M_RD;
+
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret < 0)
                return ret;
+       else if (ret != ARRAY_SIZE(msgs))
+               return -EIO;
 
-       return value;
+       *value = 0;
+
+       for (i = 0; i < size; i++)
+               *value |= recv_buf[i] << (i * 8);
+
+       return 0;
 }
 
-static int adau1701_load_firmware(struct snd_soc_codec *codec)
+static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
 {
-       return process_sigma_firmware(codec->control_data, ADAU1701_FIRMWARE);
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *client = to_i2c_client(codec->dev);
+       int ret;
+
+       if (clkdiv != ADAU1707_CLKDIV_UNSET &&
+           gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
+           gpio_is_valid(adau1701->gpio_pll_mode[1])) {
+               switch (clkdiv) {
+               case 64:
+                       gpio_set_value(adau1701->gpio_pll_mode[0], 0);
+                       gpio_set_value(adau1701->gpio_pll_mode[1], 0);
+                       break;
+               case 256:
+                       gpio_set_value(adau1701->gpio_pll_mode[0], 0);
+                       gpio_set_value(adau1701->gpio_pll_mode[1], 1);
+                       break;
+               case 384:
+                       gpio_set_value(adau1701->gpio_pll_mode[0], 1);
+                       gpio_set_value(adau1701->gpio_pll_mode[1], 0);
+                       break;
+               case 0: /* fallback */
+               case 512:
+                       gpio_set_value(adau1701->gpio_pll_mode[0], 1);
+                       gpio_set_value(adau1701->gpio_pll_mode[1], 1);
+                       break;
+               }
+       }
+
+       adau1701->pll_clkdiv = clkdiv;
+
+       if (gpio_is_valid(adau1701->gpio_nreset)) {
+               gpio_set_value(adau1701->gpio_nreset, 0);
+               /* minimum reset time is 20ns */
+               udelay(1);
+               gpio_set_value(adau1701->gpio_nreset, 1);
+               /* power-up time may be as long as 85ms */
+               mdelay(85);
+       }
+
+       /*
+        * Postpone the firmware download to a point in time when we
+        * know the correct PLL setup
+        */
+       if (clkdiv != ADAU1707_CLKDIV_UNSET) {
+               ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
+               if (ret) {
+                       dev_warn(codec->dev, "Failed to load firmware\n");
+                       return ret;
+               }
+       }
+
+       regmap_write(adau1701->regmap, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
+       regmap_write(adau1701->regmap, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
+
+       regcache_mark_dirty(adau1701->regmap);
+       regcache_sync(adau1701->regmap);
+
+       return 0;
 }
 
 static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
@@ -221,7 +334,7 @@ static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
                mask |= ADAU1701_SEROCTL_MSB_DEALY_MASK;
        }
 
-       snd_soc_update_bits(codec, ADAU1701_SEROCTL, mask, val);
+       regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL, mask, val);
 
        return 0;
 }
@@ -249,7 +362,7 @@ static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
                return -EINVAL;
        }
 
-       snd_soc_update_bits(codec, ADAU1701_SERICTL,
+       regmap_update_bits(adau1701->regmap, ADAU1701_SERICTL,
                ADAU1701_SERICTL_MODE_MASK, val);
 
        return 0;
@@ -259,8 +372,22 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+       unsigned int clkdiv = adau1701->sysclk / params_rate(params);
        snd_pcm_format_t format;
        unsigned int val;
+       int ret;
+
+       /*
+        * If the mclk/lrclk ratio changes, the chip needs updated PLL
+        * mode GPIO settings, and a full reset cycle, including a new
+        * firmware upload.
+        */
+       if (clkdiv != adau1701->pll_clkdiv) {
+               ret = adau1701_reset(codec, clkdiv);
+               if (ret < 0)
+                       return ret;
+       }
 
        switch (params_rate(params)) {
        case 192000:
@@ -276,7 +403,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       snd_soc_update_bits(codec, ADAU1701_DSPCTRL,
+       regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,
                ADAU1701_DSPCTRL_SR_MASK, val);
 
        format = params_format(params);
@@ -352,8 +479,8 @@ static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
        adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
 
-       snd_soc_write(codec, ADAU1701_SERICTL, serictl);
-       snd_soc_update_bits(codec, ADAU1701_SEROCTL,
+       regmap_write(adau1701->regmap, ADAU1701_SERICTL, serictl);
+       regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL,
                ~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl);
 
        return 0;
@@ -363,6 +490,7 @@ static int adau1701_set_bias_level(struct snd_soc_codec *codec,
                enum snd_soc_bias_level level)
 {
        unsigned int mask = ADAU1701_AUXNPOW_VBPD | ADAU1701_AUXNPOW_VRPD;
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
 
        switch (level) {
        case SND_SOC_BIAS_ON:
@@ -371,11 +499,13 @@ static int adau1701_set_bias_level(struct snd_soc_codec *codec,
                break;
        case SND_SOC_BIAS_STANDBY:
                /* Enable VREF and VREF buffer */
-               snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, 0x00);
+               regmap_update_bits(adau1701->regmap,
+                                  ADAU1701_AUXNPOW, mask, 0x00);
                break;
        case SND_SOC_BIAS_OFF:
                /* Disable VREF and VREF buffer */
-               snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, mask);
+               regmap_update_bits(adau1701->regmap,
+                                  ADAU1701_AUXNPOW, mask, mask);
                break;
        }
 
@@ -387,6 +517,7 @@ static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        unsigned int mask = ADAU1701_DSPCTRL_DAM;
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
        unsigned int val;
 
        if (mute)
@@ -394,7 +525,7 @@ static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
        else
                val = mask;
 
-       snd_soc_update_bits(codec, ADAU1701_DSPCTRL, mask, val);
+       regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL, mask, val);
 
        return 0;
 }
@@ -403,6 +534,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
        int source, unsigned int freq, int dir)
 {
        unsigned int val;
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
 
        switch (clk_id) {
        case ADAU1701_CLK_SRC_OSC:
@@ -415,7 +547,9 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                return -EINVAL;
        }
 
-       snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val);
+       regmap_update_bits(adau1701->regmap, ADAU1701_OSCIPOW,
+                          ADAU1701_OSCIPOW_OPD, val);
+       adau1701->sysclk = freq;
 
        return 0;
 }
@@ -452,18 +586,45 @@ static struct snd_soc_dai_driver adau1701_dai = {
        .symmetric_rates = 1,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id adau1701_dt_ids[] = {
+       { .compatible = "adi,adau1701", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, adau1701_dt_ids);
+#endif
+
 static int adau1701_probe(struct snd_soc_codec *codec)
 {
-       int ret;
+       int i, ret;
+       unsigned int val;
+       struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+
+       /*
+        * Let the pll_clkdiv variable default to something that won't happen
+        * at runtime. That way, we can postpone the firmware download from
+        * adau1701_reset() to a point in time when we know the correct PLL
+        * mode parameters.
+        */
+       adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
+
+       /* initalize with pre-configured pll mode settings */
+       ret = adau1701_reset(codec, adau1701->pll_clkdiv);
+       if (ret < 0)
+               return ret;
+
+       /* set up pin config */
+       val = 0;
+       for (i = 0; i < 6; i++)
+               val |= adau1701->pin_config[i] << (i * 4);
 
-       codec->control_data = to_i2c_client(codec->dev);
+       regmap_write(adau1701->regmap, ADAU1701_PINCONF_0, val);
 
-       ret = adau1701_load_firmware(codec);
-       if (ret)
-               dev_warn(codec->dev, "Failed to load firmware\n");
+       val = 0;
+       for (i = 0; i < 6; i++)
+               val |= adau1701->pin_config[i + 6] << (i * 4);
 
-       snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT);
-       snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR);
+       regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val);
 
        return 0;
 }
@@ -473,9 +634,6 @@ static struct snd_soc_codec_driver adau1701_codec_drv = {
        .set_bias_level         = adau1701_set_bias_level,
        .idle_bias_off          = true,
 
-       .reg_cache_size         = ADAU1701_NUM_REGS,
-       .reg_word_size          = sizeof(u16),
-
        .controls               = adau1701_controls,
        .num_controls           = ARRAY_SIZE(adau1701_controls),
        .dapm_widgets           = adau1701_dapm_widgets,
@@ -483,22 +641,86 @@ static struct snd_soc_codec_driver adau1701_codec_drv = {
        .dapm_routes            = adau1701_dapm_routes,
        .num_dapm_routes        = ARRAY_SIZE(adau1701_dapm_routes),
 
-       .write                  = adau1701_write,
-       .read                   = adau1701_read,
-
        .set_sysclk             = adau1701_set_sysclk,
 };
 
+static const struct regmap_config adau1701_regmap = {
+       .reg_bits               = 16,
+       .val_bits               = 32,
+       .max_register           = ADAU1701_MAX_REGISTER,
+       .cache_type             = REGCACHE_RBTREE,
+       .volatile_reg           = adau1701_volatile_reg,
+       .reg_write              = adau1701_reg_write,
+       .reg_read               = adau1701_reg_read,
+};
+
 static int adau1701_i2c_probe(struct i2c_client *client,
                              const struct i2c_device_id *id)
 {
        struct adau1701 *adau1701;
+       struct device *dev = &client->dev;
+       int gpio_nreset = -EINVAL;
+       int gpio_pll_mode[2] = { -EINVAL, -EINVAL };
        int ret;
 
-       adau1701 = devm_kzalloc(&client->dev, sizeof(*adau1701), GFP_KERNEL);
+       adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL);
        if (!adau1701)
                return -ENOMEM;
 
+       adau1701->regmap = devm_regmap_init(dev, NULL, client,
+                                           &adau1701_regmap);
+       if (IS_ERR(adau1701->regmap))
+               return PTR_ERR(adau1701->regmap);
+
+       if (dev->of_node) {
+               gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0);
+               if (gpio_nreset < 0 && gpio_nreset != -ENOENT)
+                       return gpio_nreset;
+
+               gpio_pll_mode[0] = of_get_named_gpio(dev->of_node,
+                                                  "adi,pll-mode-gpios", 0);
+               if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT)
+                       return gpio_pll_mode[0];
+
+               gpio_pll_mode[1] = of_get_named_gpio(dev->of_node,
+                                                  "adi,pll-mode-gpios", 1);
+               if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT)
+                       return gpio_pll_mode[1];
+
+               of_property_read_u32(dev->of_node, "adi,pll-clkdiv",
+                                    &adau1701->pll_clkdiv);
+
+               of_property_read_u8_array(dev->of_node, "adi,pin-config",
+                                         adau1701->pin_config,
+                                         ARRAY_SIZE(adau1701->pin_config));
+       }
+
+       if (gpio_is_valid(gpio_nreset)) {
+               ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW,
+                                           "ADAU1701 Reset");
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (gpio_is_valid(gpio_pll_mode[0]) &&
+           gpio_is_valid(gpio_pll_mode[1])) {
+               ret = devm_gpio_request_one(dev, gpio_pll_mode[0],
+                                           GPIOF_OUT_INIT_LOW,
+                                           "ADAU1701 PLL mode 0");
+               if (ret < 0)
+                       return ret;
+
+               ret = devm_gpio_request_one(dev, gpio_pll_mode[1],
+                                           GPIOF_OUT_INIT_LOW,
+                                           "ADAU1701 PLL mode 1");
+               if (ret < 0)
+                       return ret;
+       }
+
+       adau1701->gpio_nreset = gpio_nreset;
+       adau1701->gpio_pll_mode[0] = gpio_pll_mode[0];
+       adau1701->gpio_pll_mode[1] = gpio_pll_mode[1];
+
        i2c_set_clientdata(client, adau1701);
        ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
                        &adau1701_dai, 1);
@@ -521,6 +743,7 @@ static struct i2c_driver adau1701_i2c_driver = {
        .driver = {
                .name   = "adau1701",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(adau1701_dt_ids),
        },
        .probe          = adau1701_i2c_probe,
        .remove         = adau1701_i2c_remove,
index 389f232538311fcf57f1e2431ddd3da8a8c146eb..de625813c0e65c7aff7807d6904c53d2c581249d 100644 (file)
@@ -1198,6 +1198,13 @@ const struct snd_soc_dai_ops arizona_dai_ops = {
 };
 EXPORT_SYMBOL_GPL(arizona_dai_ops);
 
+const struct snd_soc_dai_ops arizona_simple_dai_ops = {
+       .startup = arizona_startup,
+       .hw_params = arizona_hw_params_rate,
+       .set_sysclk = arizona_dai_set_sysclk,
+};
+EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
+
 int arizona_init_dai(struct arizona_priv *priv, int id)
 {
        struct arizona_dai_priv *dai_priv = &priv->dai[id];
index af39f10064273e0d9110b1b90f63b1587df01960..b60b08ccc1d06e54bf09579ec1ffff3640cb2d15 100644 (file)
@@ -57,7 +57,7 @@
 #define ARIZONA_CLK_98MHZ  5
 #define ARIZONA_CLK_147MHZ 6
 
-#define ARIZONA_MAX_DAI  4
+#define ARIZONA_MAX_DAI  6
 #define ARIZONA_MAX_ADSP 4
 
 struct arizona;
@@ -213,6 +213,7 @@ extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                              int source, unsigned int freq, int dir);
 
 extern const struct snd_soc_dai_ops arizona_dai_ops;
+extern const struct snd_soc_dai_ops arizona_simple_dai_ops;
 
 #define ARIZONA_FLL_NAME_LEN 20
 
similarity index 53%
rename from sound/soc/codecs/dfbmcs320.c
rename to sound/soc/codecs/bt-sco.c
index 4f4f7f41a7d11b5fa79245f06474d27d54fe3e47..a081d9fcb1668ed8393429d60d3cecac63ea7ae5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Driver for the DFBM-CS320 bluetooth module
+ * Driver for generic Bluetooth SCO link
  * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de>
  *
  *  This program is free software; you can redistribute  it and/or modify it
@@ -15,8 +15,8 @@
 
 #include <sound/soc.h>
 
-static struct snd_soc_dai_driver dfbmcs320_dai = {
-       .name = "dfbmcs320-pcm",
+static struct snd_soc_dai_driver bt_sco_dai = {
+       .name = "bt-sco-pcm",
        .playback = {
                .channels_min = 1,
                .channels_max = 1,
@@ -31,32 +31,41 @@ static struct snd_soc_dai_driver dfbmcs320_dai = {
        },
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_dfbmcs320;
+static struct snd_soc_codec_driver soc_codec_dev_bt_sco;
 
-static int dfbmcs320_probe(struct platform_device *pdev)
+static int bt_sco_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_dfbmcs320,
-                       &dfbmcs320_dai, 1);
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco,
+                       &bt_sco_dai, 1);
 }
 
-static int dfbmcs320_remove(struct platform_device *pdev)
+static int bt_sco_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
 
        return 0;
 }
 
-static struct platform_driver dfmcs320_driver = {
+static struct platform_device_id bt_sco_driver_ids[] = {
+       {
+               .name           = "dfbmcs320",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
+
+static struct platform_driver bt_sco_driver = {
        .driver = {
-               .name = "dfbmcs320",
+               .name = "bt-sco",
                .owner = THIS_MODULE,
        },
-       .probe = dfbmcs320_probe,
-       .remove = dfbmcs320_remove,
+       .probe = bt_sco_probe,
+       .remove = bt_sco_remove,
+       .id_table = bt_sco_driver_ids,
 };
 
-module_platform_driver(dfmcs320_driver);
+module_platform_driver(bt_sco_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("ASoC DFBM-CS320 bluethooth module driver");
+MODULE_DESCRIPTION("ASoC generic bluethooth sco link driver");
 MODULE_LICENSE("GPL");
similarity index 69%
rename from sound/soc/codecs/omap-hdmi.c
rename to sound/soc/codecs/hdmi.c
index 529d06444c546711c1fcbabffbf75c660486ce1b..2bcae2b40c92cd48a35aaf59ad333bb689851ff2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * ALSA SoC codec driver for HDMI audio on OMAP processors.
+ * ALSA SoC codec driver for HDMI audio codecs.
  * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
  * Author: Ricardo Neri <ricardo.neri@ti.com>
  *
 
 #define DRV_NAME "hdmi-audio-codec"
 
-static struct snd_soc_codec_driver omap_hdmi_codec;
+static struct snd_soc_codec_driver hdmi_codec;
 
-static struct snd_soc_dai_driver omap_hdmi_codec_dai = {
-       .name = "omap-hdmi-hifi",
+static struct snd_soc_dai_driver hdmi_codec_dai = {
+       .name = "hdmi-hifi",
        .playback = {
                .channels_min = 2,
                .channels_max = 8,
@@ -39,31 +39,31 @@ static struct snd_soc_dai_driver omap_hdmi_codec_dai = {
        },
 };
 
-static int omap_hdmi_codec_probe(struct platform_device *pdev)
+static int hdmi_codec_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_codec(&pdev->dev, &omap_hdmi_codec,
-                       &omap_hdmi_codec_dai, 1);
+       return snd_soc_register_codec(&pdev->dev, &hdmi_codec,
+                       &hdmi_codec_dai, 1);
 }
 
-static int omap_hdmi_codec_remove(struct platform_device *pdev)
+static int hdmi_codec_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
-static struct platform_driver omap_hdmi_codec_driver = {
+static struct platform_driver hdmi_codec_driver = {
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
        },
 
-       .probe          = omap_hdmi_codec_probe,
-       .remove         = omap_hdmi_codec_remove,
+       .probe          = hdmi_codec_probe,
+       .remove         = hdmi_codec_remove,
 };
 
-module_platform_driver(omap_hdmi_codec_driver);
+module_platform_driver(hdmi_codec_driver);
 
 MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
-MODULE_DESCRIPTION("ASoC OMAP HDMI codec driver");
+MODULE_DESCRIPTION("ASoC generic HDMI codec driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRV_NAME);
index 5f607b35b68b4c46aa6e3f8337730d66647d877b..bcebd1a9ce313bce582284f17009ff82708d82cb 100644 (file)
@@ -384,8 +384,6 @@ static int jz4740_codec_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 8d14a76c7249ade32bdc627fee92a5cefe6eaf91..ad5313f98f286b8f95223b56ef88ae4718f7a73d 100644 (file)
@@ -857,6 +857,14 @@ static const struct soc_enum mic2_mux_enum =
 static const struct snd_kcontrol_new max98090_mic2_mux =
        SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum);
 
+static const char *dmic_mux_text[] = { "ADC", "DMIC" };
+
+static const struct soc_enum dmic_mux_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dmic_mux_text), dmic_mux_text);
+
+static const struct snd_kcontrol_new max98090_dmic_mux =
+       SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum);
+
 static const char *max98090_micpre_text[] = { "Off", "On" };
 
 static const struct soc_enum max98090_pa1en_enum =
@@ -1144,6 +1152,9 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
        SND_SOC_DAPM_MUX("MIC2 Mux", SND_SOC_NOPM,
                0, 0, &max98090_mic2_mux),
 
+       SND_SOC_DAPM_VIRT_MUX("DMIC Mux", SND_SOC_NOPM,
+               0, 0, &max98090_dmic_mux),
+
        SND_SOC_DAPM_PGA_E("MIC1 Input", M98090_REG_MIC1_INPUT_LEVEL,
                M98090_MIC_PA1EN_SHIFT, 0, NULL, 0, max98090_micinput_event,
                SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -1336,11 +1347,14 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
        {"ADCL", NULL, "SHDN"},
        {"ADCR", NULL, "SHDN"},
 
-       {"LBENL Mux", "Normal", "ADCL"},
-       {"LBENL Mux", "Normal", "DMICL"},
+       {"DMIC Mux", "ADC", "ADCL"},
+       {"DMIC Mux", "ADC", "ADCR"},
+       {"DMIC Mux", "DMIC", "DMICL"},
+       {"DMIC Mux", "DMIC", "DMICR"},
+
+       {"LBENL Mux", "Normal", "DMIC Mux"},
        {"LBENL Mux", "Loopback", "LTENL Mux"},
-       {"LBENR Mux", "Normal", "ADCR"},
-       {"LBENR Mux", "Normal", "DMICR"},
+       {"LBENR Mux", "Normal", "DMIC Mux"},
        {"LBENR Mux", "Loopback", "LTENR Mux"},
 
        {"AIFOUTL", NULL, "LBENL Mux"},
@@ -2336,6 +2350,7 @@ static int max98090_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_RUNTIME
 static int max98090_runtime_resume(struct device *dev)
 {
        struct max98090_priv *max98090 = dev_get_drvdata(dev);
@@ -2355,6 +2370,7 @@ static int max98090_runtime_suspend(struct device *dev)
 
        return 0;
 }
+#endif
 
 static const struct dev_pm_ops max98090_pm = {
        SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
new file mode 100644 (file)
index 0000000..ce585e3
--- /dev/null
@@ -0,0 +1,2128 @@
+/*
+ * rt5640.c  --  RT5640 ALSA SoC audio codec driver
+ *
+ * Copyright 2011 Realtek Semiconductor Corp.
+ * Author: Johnny Hsu <johnnyhsu@realtek.com>
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "rt5640.h"
+
+#define RT5640_DEVICE_ID 0x6231
+
+#define RT5640_PR_RANGE_BASE (0xff + 1)
+#define RT5640_PR_SPACING 0x100
+
+#define RT5640_PR_BASE (RT5640_PR_RANGE_BASE + (0 * RT5640_PR_SPACING))
+
+static const struct regmap_range_cfg rt5640_ranges[] = {
+       { .name = "PR", .range_min = RT5640_PR_BASE,
+         .range_max = RT5640_PR_BASE + 0xb4,
+         .selector_reg = RT5640_PRIV_INDEX,
+         .selector_mask = 0xff,
+         .selector_shift = 0x0,
+         .window_start = RT5640_PRIV_DATA,
+         .window_len = 0x1, },
+};
+
+static struct reg_default init_list[] = {
+       {RT5640_PR_BASE + 0x3d, 0x3600},
+       {RT5640_PR_BASE + 0x1c, 0x0D21},
+       {RT5640_PR_BASE + 0x1b, 0x0000},
+       {RT5640_PR_BASE + 0x12, 0x0aa8},
+       {RT5640_PR_BASE + 0x14, 0x0aaa},
+       {RT5640_PR_BASE + 0x20, 0x6110},
+       {RT5640_PR_BASE + 0x21, 0xe0e0},
+       {RT5640_PR_BASE + 0x23, 0x1804},
+};
+#define RT5640_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static const struct reg_default rt5640_reg[RT5640_VENDOR_ID2 + 1] = {
+       { 0x00, 0x000e },
+       { 0x01, 0xc8c8 },
+       { 0x02, 0xc8c8 },
+       { 0x03, 0xc8c8 },
+       { 0x04, 0x8000 },
+       { 0x0d, 0x0000 },
+       { 0x0e, 0x0000 },
+       { 0x0f, 0x0808 },
+       { 0x19, 0xafaf },
+       { 0x1a, 0xafaf },
+       { 0x1b, 0x0000 },
+       { 0x1c, 0x2f2f },
+       { 0x1d, 0x2f2f },
+       { 0x1e, 0x0000 },
+       { 0x27, 0x7060 },
+       { 0x28, 0x7070 },
+       { 0x29, 0x8080 },
+       { 0x2a, 0x5454 },
+       { 0x2b, 0x5454 },
+       { 0x2c, 0xaa00 },
+       { 0x2d, 0x0000 },
+       { 0x2e, 0xa000 },
+       { 0x2f, 0x0000 },
+       { 0x3b, 0x0000 },
+       { 0x3c, 0x007f },
+       { 0x3d, 0x0000 },
+       { 0x3e, 0x007f },
+       { 0x45, 0xe000 },
+       { 0x46, 0x003e },
+       { 0x47, 0x003e },
+       { 0x48, 0xf800 },
+       { 0x49, 0x3800 },
+       { 0x4a, 0x0004 },
+       { 0x4c, 0xfc00 },
+       { 0x4d, 0x0000 },
+       { 0x4f, 0x01ff },
+       { 0x50, 0x0000 },
+       { 0x51, 0x0000 },
+       { 0x52, 0x01ff },
+       { 0x53, 0xf000 },
+       { 0x61, 0x0000 },
+       { 0x62, 0x0000 },
+       { 0x63, 0x00c0 },
+       { 0x64, 0x0000 },
+       { 0x65, 0x0000 },
+       { 0x66, 0x0000 },
+       { 0x6a, 0x0000 },
+       { 0x6c, 0x0000 },
+       { 0x70, 0x8000 },
+       { 0x71, 0x8000 },
+       { 0x72, 0x8000 },
+       { 0x73, 0x1114 },
+       { 0x74, 0x0c00 },
+       { 0x75, 0x1d00 },
+       { 0x80, 0x0000 },
+       { 0x81, 0x0000 },
+       { 0x82, 0x0000 },
+       { 0x83, 0x0000 },
+       { 0x84, 0x0000 },
+       { 0x85, 0x0008 },
+       { 0x89, 0x0000 },
+       { 0x8a, 0x0000 },
+       { 0x8b, 0x0600 },
+       { 0x8c, 0x0228 },
+       { 0x8d, 0xa000 },
+       { 0x8e, 0x0004 },
+       { 0x8f, 0x1100 },
+       { 0x90, 0x0646 },
+       { 0x91, 0x0c00 },
+       { 0x92, 0x0000 },
+       { 0x93, 0x3000 },
+       { 0xb0, 0x2080 },
+       { 0xb1, 0x0000 },
+       { 0xb4, 0x2206 },
+       { 0xb5, 0x1f00 },
+       { 0xb6, 0x0000 },
+       { 0xb8, 0x034b },
+       { 0xb9, 0x0066 },
+       { 0xba, 0x000b },
+       { 0xbb, 0x0000 },
+       { 0xbc, 0x0000 },
+       { 0xbd, 0x0000 },
+       { 0xbe, 0x0000 },
+       { 0xbf, 0x0000 },
+       { 0xc0, 0x0400 },
+       { 0xc2, 0x0000 },
+       { 0xc4, 0x0000 },
+       { 0xc5, 0x0000 },
+       { 0xc6, 0x2000 },
+       { 0xc8, 0x0000 },
+       { 0xc9, 0x0000 },
+       { 0xca, 0x0000 },
+       { 0xcb, 0x0000 },
+       { 0xcc, 0x0000 },
+       { 0xcf, 0x0013 },
+       { 0xd0, 0x0680 },
+       { 0xd1, 0x1c17 },
+       { 0xd2, 0x8c00 },
+       { 0xd3, 0xaa20 },
+       { 0xd6, 0x0400 },
+       { 0xd9, 0x0809 },
+       { 0xfe, 0x10ec },
+       { 0xff, 0x6231 },
+};
+
+static int rt5640_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, RT5640_RESET, 0);
+}
+
+static bool rt5640_volatile_register(struct device *dev, unsigned int reg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rt5640_ranges); i++)
+               if ((reg >= rt5640_ranges[i].window_start &&
+                    reg <= rt5640_ranges[i].window_start +
+                    rt5640_ranges[i].window_len) ||
+                   (reg >= rt5640_ranges[i].range_min &&
+                    reg <= rt5640_ranges[i].range_max))
+                       return true;
+
+       switch (reg) {
+       case RT5640_RESET:
+       case RT5640_ASRC_5:
+       case RT5640_EQ_CTRL1:
+       case RT5640_DRC_AGC_1:
+       case RT5640_ANC_CTRL1:
+       case RT5640_IRQ_CTRL2:
+       case RT5640_INT_IRQ_ST:
+       case RT5640_DSP_CTRL2:
+       case RT5640_DSP_CTRL3:
+       case RT5640_PRIV_INDEX:
+       case RT5640_PRIV_DATA:
+       case RT5640_PGM_REG_ARR1:
+       case RT5640_PGM_REG_ARR3:
+       case RT5640_VENDOR_ID:
+       case RT5640_VENDOR_ID1:
+       case RT5640_VENDOR_ID2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool rt5640_readable_register(struct device *dev, unsigned int reg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rt5640_ranges); i++)
+               if ((reg >= rt5640_ranges[i].window_start &&
+                    reg <= rt5640_ranges[i].window_start +
+                    rt5640_ranges[i].window_len) ||
+                   (reg >= rt5640_ranges[i].range_min &&
+                    reg <= rt5640_ranges[i].range_max))
+                       return true;
+
+       switch (reg) {
+       case RT5640_RESET:
+       case RT5640_SPK_VOL:
+       case RT5640_HP_VOL:
+       case RT5640_OUTPUT:
+       case RT5640_MONO_OUT:
+       case RT5640_IN1_IN2:
+       case RT5640_IN3_IN4:
+       case RT5640_INL_INR_VOL:
+       case RT5640_DAC1_DIG_VOL:
+       case RT5640_DAC2_DIG_VOL:
+       case RT5640_DAC2_CTRL:
+       case RT5640_ADC_DIG_VOL:
+       case RT5640_ADC_DATA:
+       case RT5640_ADC_BST_VOL:
+       case RT5640_STO_ADC_MIXER:
+       case RT5640_MONO_ADC_MIXER:
+       case RT5640_AD_DA_MIXER:
+       case RT5640_STO_DAC_MIXER:
+       case RT5640_MONO_DAC_MIXER:
+       case RT5640_DIG_MIXER:
+       case RT5640_DSP_PATH1:
+       case RT5640_DSP_PATH2:
+       case RT5640_DIG_INF_DATA:
+       case RT5640_REC_L1_MIXER:
+       case RT5640_REC_L2_MIXER:
+       case RT5640_REC_R1_MIXER:
+       case RT5640_REC_R2_MIXER:
+       case RT5640_HPO_MIXER:
+       case RT5640_SPK_L_MIXER:
+       case RT5640_SPK_R_MIXER:
+       case RT5640_SPO_L_MIXER:
+       case RT5640_SPO_R_MIXER:
+       case RT5640_SPO_CLSD_RATIO:
+       case RT5640_MONO_MIXER:
+       case RT5640_OUT_L1_MIXER:
+       case RT5640_OUT_L2_MIXER:
+       case RT5640_OUT_L3_MIXER:
+       case RT5640_OUT_R1_MIXER:
+       case RT5640_OUT_R2_MIXER:
+       case RT5640_OUT_R3_MIXER:
+       case RT5640_LOUT_MIXER:
+       case RT5640_PWR_DIG1:
+       case RT5640_PWR_DIG2:
+       case RT5640_PWR_ANLG1:
+       case RT5640_PWR_ANLG2:
+       case RT5640_PWR_MIXER:
+       case RT5640_PWR_VOL:
+       case RT5640_PRIV_INDEX:
+       case RT5640_PRIV_DATA:
+       case RT5640_I2S1_SDP:
+       case RT5640_I2S2_SDP:
+       case RT5640_ADDA_CLK1:
+       case RT5640_ADDA_CLK2:
+       case RT5640_DMIC:
+       case RT5640_GLB_CLK:
+       case RT5640_PLL_CTRL1:
+       case RT5640_PLL_CTRL2:
+       case RT5640_ASRC_1:
+       case RT5640_ASRC_2:
+       case RT5640_ASRC_3:
+       case RT5640_ASRC_4:
+       case RT5640_ASRC_5:
+       case RT5640_HP_OVCD:
+       case RT5640_CLS_D_OVCD:
+       case RT5640_CLS_D_OUT:
+       case RT5640_DEPOP_M1:
+       case RT5640_DEPOP_M2:
+       case RT5640_DEPOP_M3:
+       case RT5640_CHARGE_PUMP:
+       case RT5640_PV_DET_SPK_G:
+       case RT5640_MICBIAS:
+       case RT5640_EQ_CTRL1:
+       case RT5640_EQ_CTRL2:
+       case RT5640_WIND_FILTER:
+       case RT5640_DRC_AGC_1:
+       case RT5640_DRC_AGC_2:
+       case RT5640_DRC_AGC_3:
+       case RT5640_SVOL_ZC:
+       case RT5640_ANC_CTRL1:
+       case RT5640_ANC_CTRL2:
+       case RT5640_ANC_CTRL3:
+       case RT5640_JD_CTRL:
+       case RT5640_ANC_JD:
+       case RT5640_IRQ_CTRL1:
+       case RT5640_IRQ_CTRL2:
+       case RT5640_INT_IRQ_ST:
+       case RT5640_GPIO_CTRL1:
+       case RT5640_GPIO_CTRL2:
+       case RT5640_GPIO_CTRL3:
+       case RT5640_DSP_CTRL1:
+       case RT5640_DSP_CTRL2:
+       case RT5640_DSP_CTRL3:
+       case RT5640_DSP_CTRL4:
+       case RT5640_PGM_REG_ARR1:
+       case RT5640_PGM_REG_ARR2:
+       case RT5640_PGM_REG_ARR3:
+       case RT5640_PGM_REG_ARR4:
+       case RT5640_PGM_REG_ARR5:
+       case RT5640_SCB_FUNC:
+       case RT5640_SCB_CTRL:
+       case RT5640_BASE_BACK:
+       case RT5640_MP3_PLUS1:
+       case RT5640_MP3_PLUS2:
+       case RT5640_3D_HP:
+       case RT5640_ADJ_HPF:
+       case RT5640_HP_CALIB_AMP_DET:
+       case RT5640_HP_CALIB2:
+       case RT5640_SV_ZCD1:
+       case RT5640_SV_ZCD2:
+       case RT5640_DUMMY1:
+       case RT5640_DUMMY2:
+       case RT5640_DUMMY3:
+       case RT5640_VENDOR_ID:
+       case RT5640_VENDOR_ID1:
+       case RT5640_VENDOR_ID2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static unsigned int bst_tlv[] = {
+       TLV_DB_RANGE_HEAD(7),
+       0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+       3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+       6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+       7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+       8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
+};
+
+/* Interface data select */
+static const char * const rt5640_data_select[] = {
+       "Normal", "left copy to right", "right copy to left", "Swap"};
+
+static const SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA,
+                               RT5640_IF1_DAC_SEL_SFT, rt5640_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA,
+                               RT5640_IF1_ADC_SEL_SFT, rt5640_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA,
+                               RT5640_IF2_DAC_SEL_SFT, rt5640_data_select);
+
+static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA,
+                               RT5640_IF2_ADC_SEL_SFT, rt5640_data_select);
+
+/* Class D speaker gain ratio */
+static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x",
+       "2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT,
+       RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio);
+
+static const struct snd_kcontrol_new rt5640_snd_controls[] = {
+       /* Speaker Output Volume */
+       SOC_DOUBLE("Speaker Playback Switch", RT5640_SPK_VOL,
+               RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE("Speaker Channel Switch", RT5640_SPK_VOL,
+               RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
+       SOC_DOUBLE_TLV("Speaker Playback Volume", RT5640_SPK_VOL,
+               RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
+       /* Headphone Output Volume */
+       SOC_DOUBLE("HP Playback Switch", RT5640_HP_VOL,
+               RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE("HP Channel Switch", RT5640_HP_VOL,
+               RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
+       SOC_DOUBLE_TLV("HP Playback Volume", RT5640_HP_VOL,
+               RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
+       /* OUTPUT Control */
+       SOC_DOUBLE("OUT Playback Switch", RT5640_OUTPUT,
+               RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE("OUT Channel Switch", RT5640_OUTPUT,
+               RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
+       SOC_DOUBLE_TLV("OUT Playback Volume", RT5640_OUTPUT,
+               RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
+       /* MONO Output Control */
+       SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT,
+                               RT5640_L_MUTE_SFT, 1, 1),
+       /* DAC Digital Volume */
+       SOC_DOUBLE("DAC2 Playback Switch", RT5640_DAC2_CTRL,
+               RT5640_M_DAC_L2_VOL_SFT, RT5640_M_DAC_R2_VOL_SFT, 1, 1),
+       SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL,
+                       RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+                       175, 0, dac_vol_tlv),
+       SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL,
+                       RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+                       175, 0, dac_vol_tlv),
+       /* IN1/IN2 Control */
+       SOC_SINGLE_TLV("IN1 Boost", RT5640_IN1_IN2,
+               RT5640_BST_SFT1, 8, 0, bst_tlv),
+       SOC_SINGLE_TLV("IN2 Boost", RT5640_IN3_IN4,
+               RT5640_BST_SFT2, 8, 0, bst_tlv),
+       /* INL/INR Volume Control */
+       SOC_DOUBLE_TLV("IN Capture Volume", RT5640_INL_INR_VOL,
+                       RT5640_INL_VOL_SFT, RT5640_INR_VOL_SFT,
+                       31, 1, in_vol_tlv),
+       /* ADC Digital Volume Control */
+       SOC_DOUBLE("ADC Capture Switch", RT5640_ADC_DIG_VOL,
+               RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+       SOC_DOUBLE_TLV("ADC Capture Volume", RT5640_ADC_DIG_VOL,
+                       RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+                       127, 0, adc_vol_tlv),
+       SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5640_ADC_DATA,
+                       RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,
+                       127, 0, adc_vol_tlv),
+       /* ADC Boost Volume Control */
+       SOC_DOUBLE_TLV("ADC Boost Gain", RT5640_ADC_BST_VOL,
+                       RT5640_ADC_L_BST_SFT, RT5640_ADC_R_BST_SFT,
+                       3, 0, adc_bst_tlv),
+       /* Class D speaker gain ratio */
+       SOC_ENUM("Class D SPK Ratio Control", rt5640_clsd_spk_ratio_enum),
+
+       SOC_ENUM("ADC IF1 Data Switch", rt5640_if1_adc_enum),
+       SOC_ENUM("DAC IF1 Data Switch", rt5640_if1_dac_enum),
+       SOC_ENUM("ADC IF2 Data Switch", rt5640_if2_adc_enum),
+       SOC_ENUM("DAC IF2 Data Switch", rt5640_if2_dac_enum),
+};
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       int div[] = {2, 3, 4, 6, 8, 12};
+       int idx = -EINVAL, i;
+       int rate, red, bound, temp;
+
+       rate = rt5640->sysclk;
+       red = 3000000 * 12;
+       for (i = 0; i < ARRAY_SIZE(div); i++) {
+               bound = div[i] * 3000000;
+               if (rate > bound)
+                       continue;
+               temp = bound - rate;
+               if (temp < red) {
+                       red = temp;
+                       idx = i;
+               }
+       }
+       if (idx < 0)
+               dev_err(codec->dev, "Failed to set DMIC clock\n");
+       else
+               snd_soc_update_bits(codec, RT5640_DMIC, RT5640_DMIC_CLK_MASK,
+                                       idx << RT5640_DMIC_CLK_SFT);
+       return idx;
+}
+
+static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int val;
+
+       val = snd_soc_read(source->codec, RT5640_GLB_CLK);
+       val &= RT5640_SCLK_SRC_MASK;
+       if (val == RT5640_SCLK_SRC_PLL1 || val == RT5640_SCLK_SRC_PLL1T)
+               return 1;
+       else
+               return 0;
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
+                       RT5640_M_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5640_STO_ADC_MIXER,
+                       RT5640_M_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_sto_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
+                       RT5640_M_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5640_STO_ADC_MIXER,
+                       RT5640_M_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_adc_l_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5640_MONO_ADC_MIXER,
+                       RT5640_M_MONO_ADC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5640_MONO_ADC_MIXER,
+                       RT5640_M_MONO_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_adc_r_mix[] = {
+       SOC_DAPM_SINGLE("ADC1 Switch", RT5640_MONO_ADC_MIXER,
+                       RT5640_M_MONO_ADC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ADC2 Switch", RT5640_MONO_ADC_MIXER,
+                       RT5640_M_MONO_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5640_AD_DA_MIXER,
+                       RT5640_M_ADCMIX_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INF1 Switch", RT5640_AD_DA_MIXER,
+                       RT5640_M_IF1_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("Stereo ADC Switch", RT5640_AD_DA_MIXER,
+                       RT5640_M_ADCMIX_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INF1 Switch", RT5640_AD_DA_MIXER,
+                       RT5640_M_IF1_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_sto_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_L1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_L2_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ANC Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_ANC_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_sto_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_R1_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_DAC_R2_SFT, 1, 1),
+       SOC_DAPM_SINGLE("ANC Switch", RT5640_STO_DAC_MIXER,
+                       RT5640_M_ANC_DAC_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_dac_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_L1_MONO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_L2_MONO_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_R2_MONO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_dac_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_R1_MONO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_R2_MONO_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_MONO_DAC_MIXER,
+                       RT5640_M_DAC_L2_MONO_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dig_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_DIG_MIXER,
+                       RT5640_M_STO_L_DAC_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_DIG_MIXER,
+                       RT5640_M_DAC_L2_DAC_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_dig_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_DIG_MIXER,
+                       RT5640_M_STO_R_DAC_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_DIG_MIXER,
+                       RT5640_M_DAC_R2_DAC_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5640_rec_l_mix[] = {
+       SOC_DAPM_SINGLE("HPOL Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_HP_L_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_IN_L_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_BST4_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_BST1_RM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUT MIXL Switch", RT5640_REC_L2_MIXER,
+                       RT5640_M_OM_L_RM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_rec_r_mix[] = {
+       SOC_DAPM_SINGLE("HPOR Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_HP_R_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_IN_R_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_BST4_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_BST1_RM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUT MIXR Switch", RT5640_REC_R2_MIXER,
+                       RT5640_M_OM_R_RM_R_SFT, 1, 1),
+};
+
+/* Analog Output Mixer */
+static const struct snd_kcontrol_new rt5640_spk_l_mix[] = {
+       SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_SPK_L_MIXER,
+                       RT5640_M_RM_L_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5640_SPK_L_MIXER,
+                       RT5640_M_IN_L_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_SPK_L_MIXER,
+                       RT5640_M_DAC_L1_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_SPK_L_MIXER,
+                       RT5640_M_DAC_L2_SM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUT MIXL Switch", RT5640_SPK_L_MIXER,
+                       RT5640_M_OM_L_SM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_spk_r_mix[] = {
+       SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_SPK_R_MIXER,
+                       RT5640_M_RM_R_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5640_SPK_R_MIXER,
+                       RT5640_M_IN_R_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPK_R_MIXER,
+                       RT5640_M_DAC_R1_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_SPK_R_MIXER,
+                       RT5640_M_DAC_R2_SM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUT MIXR Switch", RT5640_SPK_R_MIXER,
+                       RT5640_M_OM_R_SM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_out_l_mix[] = {
+       SOC_DAPM_SINGLE("SPK MIXL Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_SM_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_BST1_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INL Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_IN_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_RM_L_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_DAC_R2_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_DAC_L2_OM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_OUT_L3_MIXER,
+                       RT5640_M_DAC_L1_OM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_out_r_mix[] = {
+       SOC_DAPM_SINGLE("SPK MIXR Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_SM_L_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST2 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_BST4_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_BST1_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("INR Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_IN_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_RM_R_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_DAC_L2_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_DAC_R2_OM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_OUT_R3_MIXER,
+                       RT5640_M_DAC_R1_OM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_spo_l_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_L_MIXER,
+                       RT5640_M_DAC_R1_SPM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_SPO_L_MIXER,
+                       RT5640_M_DAC_L1_SPM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("SPKVOL R Switch", RT5640_SPO_L_MIXER,
+                       RT5640_M_SV_R_SPM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("SPKVOL L Switch", RT5640_SPO_L_MIXER,
+                       RT5640_M_SV_L_SPM_L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_SPO_L_MIXER,
+                       RT5640_M_BST1_SPM_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_spo_r_mix[] = {
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_R_MIXER,
+                       RT5640_M_DAC_R1_SPM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("SPKVOL R Switch", RT5640_SPO_R_MIXER,
+                       RT5640_M_SV_R_SPM_R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_SPO_R_MIXER,
+                       RT5640_M_BST1_SPM_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_hpo_mix[] = {
+       SOC_DAPM_SINGLE("HPO MIX DAC2 Switch", RT5640_HPO_MIXER,
+                       RT5640_M_DAC2_HM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5640_HPO_MIXER,
+                       RT5640_M_DAC1_HM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5640_HPO_MIXER,
+                       RT5640_M_HPVOL_HM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_lout_mix[] = {
+       SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_LOUT_MIXER,
+                       RT5640_M_DAC_L1_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_LOUT_MIXER,
+                       RT5640_M_DAC_R1_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL L Switch", RT5640_LOUT_MIXER,
+                       RT5640_M_OV_L_LM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL R Switch", RT5640_LOUT_MIXER,
+                       RT5640_M_OV_R_LM_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5640_mono_mix[] = {
+       SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_MONO_MIXER,
+                       RT5640_M_DAC_R2_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_MONO_MIXER,
+                       RT5640_M_DAC_L2_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL R Switch", RT5640_MONO_MIXER,
+                       RT5640_M_OV_R_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("OUTVOL L Switch", RT5640_MONO_MIXER,
+                       RT5640_M_OV_L_MM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("BST1 Switch", RT5640_MONO_MIXER,
+                       RT5640_M_BST1_MM_SFT, 1, 1),
+};
+
+/* INL/R source */
+static const char * const rt5640_inl_src[] = {
+       "IN2P", "MONOP"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_inl_enum, RT5640_INL_INR_VOL,
+       RT5640_INL_SEL_SFT, rt5640_inl_src);
+
+static const struct snd_kcontrol_new rt5640_inl_mux =
+       SOC_DAPM_ENUM("INL source", rt5640_inl_enum);
+
+static const char * const rt5640_inr_src[] = {
+       "IN2N", "MONON"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_inr_enum, RT5640_INL_INR_VOL,
+       RT5640_INR_SEL_SFT, rt5640_inr_src);
+
+static const struct snd_kcontrol_new rt5640_inr_mux =
+       SOC_DAPM_ENUM("INR source", rt5640_inr_enum);
+
+/* Stereo ADC source */
+static const char * const rt5640_stereo_adc1_src[] = {
+       "DIG MIX", "ADC"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER,
+       RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src);
+
+static const struct snd_kcontrol_new rt5640_sto_adc_1_mux =
+       SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum);
+
+static const char * const rt5640_stereo_adc2_src[] = {
+       "DMIC1", "DMIC2", "DIG MIX"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER,
+       RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src);
+
+static const struct snd_kcontrol_new rt5640_sto_adc_2_mux =
+       SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum);
+
+/* Mono ADC source */
+static const char * const rt5640_mono_adc_l1_src[] = {
+       "Mono DAC MIXL", "ADCL"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER,
+       RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux =
+       SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum);
+
+static const char * const rt5640_mono_adc_l2_src[] = {
+       "DMIC L1", "DMIC L2", "Mono DAC MIXL"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER,
+       RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux =
+       SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum);
+
+static const char * const rt5640_mono_adc_r1_src[] = {
+       "Mono DAC MIXR", "ADCR"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER,
+       RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux =
+       SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum);
+
+static const char * const rt5640_mono_adc_r2_src[] = {
+       "DMIC R1", "DMIC R2", "Mono DAC MIXR"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER,
+       RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src);
+
+static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux =
+       SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum);
+
+/* DAC2 channel source */
+static const char * const rt5640_dac_l2_src[] = {
+       "IF2", "Base L/R"
+};
+
+static int rt5640_dac_l2_values[] = {
+       0,
+       3,
+};
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5640_dac_l2_enum, RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT,
+       0x3, rt5640_dac_l2_src, rt5640_dac_l2_values);
+
+static const struct snd_kcontrol_new rt5640_dac_l2_mux =
+       SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum);
+
+static const char * const rt5640_dac_r2_src[] = {
+       "IF2",
+};
+
+static int rt5640_dac_r2_values[] = {
+       0,
+};
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5640_dac_r2_enum, RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT,
+       0x3, rt5640_dac_r2_src, rt5640_dac_r2_values);
+
+static const struct snd_kcontrol_new rt5640_dac_r2_mux =
+       SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum);
+
+/* digital interface and iis interface map */
+static const char * const rt5640_dai_iis_map[] = {
+       "1:1|2:2", "1:2|2:1", "1:1|2:1", "1:2|2:2"
+};
+
+static int rt5640_dai_iis_map_values[] = {
+       0,
+       5,
+       6,
+       7,
+};
+
+static const SOC_VALUE_ENUM_SINGLE_DECL(
+       rt5640_dai_iis_map_enum, RT5640_I2S1_SDP, RT5640_I2S_IF_SFT,
+       0x7, rt5640_dai_iis_map, rt5640_dai_iis_map_values);
+
+static const struct snd_kcontrol_new rt5640_dai_mux =
+       SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum);
+
+/* SDI select */
+static const char * const rt5640_sdi_sel[] = {
+       "IF1", "IF2"
+};
+
+static const SOC_ENUM_SINGLE_DECL(
+       rt5640_sdi_sel_enum, RT5640_I2S2_SDP,
+       RT5640_I2S2_SDI_SFT, rt5640_sdi_sel);
+
+static const struct snd_kcontrol_new rt5640_sdi_mux =
+       SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
+
+static int spk_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
+                                       0x0001, 0x0001);
+               regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
+                                       0xf000, 0xf000);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
+                                       0xf000, 0x0000);
+               regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
+                                       0x0001, 0x0000);
+               break;
+
+       default:
+               return 0;
+       }
+       return 0;
+}
+
+static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, RT5640_GPIO_CTRL1,
+                       RT5640_GP2_PIN_MASK | RT5640_GP3_PIN_MASK,
+                       RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP3_PIN_DMIC1_SDA);
+               snd_soc_update_bits(codec, RT5640_DMIC,
+                       RT5640_DMIC_1L_LH_MASK | RT5640_DMIC_1R_LH_MASK |
+                       RT5640_DMIC_1_DP_MASK,
+                       RT5640_DMIC_1L_LH_FALLING | RT5640_DMIC_1R_LH_RISING |
+                       RT5640_DMIC_1_DP_IN1P);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, RT5640_GPIO_CTRL1,
+                       RT5640_GP2_PIN_MASK | RT5640_GP4_PIN_MASK,
+                       RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP4_PIN_DMIC2_SDA);
+               snd_soc_update_bits(codec, RT5640_DMIC,
+                       RT5640_DMIC_2L_LH_MASK | RT5640_DMIC_2R_LH_MASK |
+                       RT5640_DMIC_2_DP_MASK,
+                       RT5640_DMIC_2L_LH_FALLING | RT5640_DMIC_2R_LH_RISING |
+                       RT5640_DMIC_2_DP_IN1N);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
+       SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
+                       RT5640_PWR_PLL_BIT, 0, NULL, 0),
+       /* Input Side */
+       /* micbias */
+       SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1,
+                       RT5640_PWR_LDO2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5640_PWR_ANLG2,
+                       RT5640_PWR_MB1_BIT, 0, NULL, 0),
+       /* Input Lines */
+       SND_SOC_DAPM_INPUT("DMIC1"),
+       SND_SOC_DAPM_INPUT("DMIC2"),
+       SND_SOC_DAPM_INPUT("IN1P"),
+       SND_SOC_DAPM_INPUT("IN1N"),
+       SND_SOC_DAPM_INPUT("IN2P"),
+       SND_SOC_DAPM_INPUT("IN2N"),
+       SND_SOC_DAPM_PGA("DMIC L1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC R1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC L2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("DMIC R2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+               set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC,
+               RT5640_DMIC_1_EN_SFT, 0, rt5640_set_dmic1_event,
+               SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC,
+               RT5640_DMIC_2_EN_SFT, 0, rt5640_set_dmic2_event,
+               SND_SOC_DAPM_PRE_PMU),
+       /* Boost */
+       SND_SOC_DAPM_PGA("BST1", RT5640_PWR_ANLG2,
+               RT5640_PWR_BST1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("BST2", RT5640_PWR_ANLG2,
+               RT5640_PWR_BST4_BIT, 0, NULL, 0),
+       /* Input Volume */
+       SND_SOC_DAPM_PGA("INL VOL", RT5640_PWR_VOL,
+               RT5640_PWR_IN_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("INR VOL", RT5640_PWR_VOL,
+               RT5640_PWR_IN_R_BIT, 0, NULL, 0),
+       /* IN Mux */
+       SND_SOC_DAPM_MUX("INL Mux", SND_SOC_NOPM, 0, 0, &rt5640_inl_mux),
+       SND_SOC_DAPM_MUX("INR Mux", SND_SOC_NOPM, 0, 0, &rt5640_inr_mux),
+       /* REC Mixer */
+       SND_SOC_DAPM_MIXER("RECMIXL", RT5640_PWR_MIXER, RT5640_PWR_RM_L_BIT, 0,
+                       rt5640_rec_l_mix, ARRAY_SIZE(rt5640_rec_l_mix)),
+       SND_SOC_DAPM_MIXER("RECMIXR", RT5640_PWR_MIXER, RT5640_PWR_RM_R_BIT, 0,
+                       rt5640_rec_r_mix, ARRAY_SIZE(rt5640_rec_r_mix)),
+       /* ADCs */
+       SND_SOC_DAPM_ADC("ADC L", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_ADC_L_BIT, 0),
+       SND_SOC_DAPM_ADC("ADC R", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_ADC_R_BIT, 0),
+       /* ADC Mux */
+       SND_SOC_DAPM_MUX("Stereo ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_sto_adc_2_mux),
+       SND_SOC_DAPM_MUX("Stereo ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_sto_adc_2_mux),
+       SND_SOC_DAPM_MUX("Stereo ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_sto_adc_1_mux),
+       SND_SOC_DAPM_MUX("Stereo ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_sto_adc_1_mux),
+       SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_mono_adc_l2_mux),
+       SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_mono_adc_l1_mux),
+       SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_mono_adc_r1_mux),
+       SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_mono_adc_r2_mux),
+       /* ADC Mixer */
+       SND_SOC_DAPM_SUPPLY("Stereo Filter", RT5640_PWR_DIG2,
+               RT5640_PWR_ADC_SF_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Stereo ADC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_sto_adc_l_mix, ARRAY_SIZE(rt5640_sto_adc_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo ADC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_sto_adc_r_mix, ARRAY_SIZE(rt5640_sto_adc_r_mix)),
+       SND_SOC_DAPM_SUPPLY("Mono Left Filter", RT5640_PWR_DIG2,
+               RT5640_PWR_ADC_MF_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Mono ADC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_mono_adc_l_mix, ARRAY_SIZE(rt5640_mono_adc_l_mix)),
+       SND_SOC_DAPM_SUPPLY("Mono Right Filter", RT5640_PWR_DIG2,
+               RT5640_PWR_ADC_MF_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("Mono ADC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_mono_adc_r_mix, ARRAY_SIZE(rt5640_mono_adc_r_mix)),
+
+       /* Digital Interface */
+       SND_SOC_DAPM_SUPPLY("I2S1", RT5640_PWR_DIG1,
+               RT5640_PWR_I2S1_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S2", RT5640_PWR_DIG1,
+               RT5640_PWR_I2S2_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("IF2 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0),
+       /* Digital Interface Select */
+       SND_SOC_DAPM_MUX("DAI1 RX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI1 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI1 IF1 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI1 IF2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("SDI1 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_sdi_mux),
+       SND_SOC_DAPM_MUX("DAI2 RX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI2 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI2 IF1 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("DAI2 IF2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dai_mux),
+       SND_SOC_DAPM_MUX("SDI2 TX Mux", SND_SOC_NOPM, 0, 0, &rt5640_sdi_mux),
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
+       /* Audio DSP */
+       SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0),
+       /* ANC */
+       SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       /* Output Side */
+       /* DAC mixer before sound effect  */
+       SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_dac_l_mix, ARRAY_SIZE(rt5640_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_dac_r_mix, ARRAY_SIZE(rt5640_dac_r_mix)),
+       /* DAC2 channel Mux */
+       SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_dac_l2_mux),
+       SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0,
+                               &rt5640_dac_r2_mux),
+       /* DAC Mixer */
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)),
+       SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_mono_dac_l_mix, ARRAY_SIZE(rt5640_mono_dac_l_mix)),
+       SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_mono_dac_r_mix, ARRAY_SIZE(rt5640_mono_dac_r_mix)),
+       SND_SOC_DAPM_MIXER("DIG MIXL", SND_SOC_NOPM, 0, 0,
+               rt5640_dig_l_mix, ARRAY_SIZE(rt5640_dig_l_mix)),
+       SND_SOC_DAPM_MIXER("DIG MIXR", SND_SOC_NOPM, 0, 0,
+               rt5640_dig_r_mix, ARRAY_SIZE(rt5640_dig_r_mix)),
+       /* DACs */
+       SND_SOC_DAPM_DAC("DAC L1", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_DAC_L1_BIT, 0),
+       SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_DAC_L2_BIT, 0),
+       SND_SOC_DAPM_DAC("DAC R1", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_DAC_R1_BIT, 0),
+       SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1,
+                       RT5640_PWR_DAC_R2_BIT, 0),
+       /* SPK/OUT Mixer */
+       SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT,
+               0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)),
+       SND_SOC_DAPM_MIXER("SPK MIXR", RT5640_PWR_MIXER, RT5640_PWR_SM_R_BIT,
+               0, rt5640_spk_r_mix, ARRAY_SIZE(rt5640_spk_r_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT,
+               0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)),
+       SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT,
+               0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)),
+       /* Ouput Volume */
+       SND_SOC_DAPM_PGA("SPKVOL L", RT5640_PWR_VOL,
+               RT5640_PWR_SV_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("SPKVOL R", RT5640_PWR_VOL,
+               RT5640_PWR_SV_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("OUTVOL L", RT5640_PWR_VOL,
+               RT5640_PWR_OV_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("OUTVOL R", RT5640_PWR_VOL,
+               RT5640_PWR_OV_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HPOVOL L", RT5640_PWR_VOL,
+               RT5640_PWR_HV_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HPOVOL R", RT5640_PWR_VOL,
+               RT5640_PWR_HV_R_BIT, 0, NULL, 0),
+       /* SPO/HPO/LOUT/Mono Mixer */
+       SND_SOC_DAPM_MIXER("SPOL MIX", SND_SOC_NOPM, 0,
+               0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)),
+       SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0,
+               0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)),
+       SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0,
+               rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
+       SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0,
+               rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),
+       SND_SOC_DAPM_MIXER("LOUT MIX", RT5640_PWR_ANLG1, RT5640_PWR_LM_BIT, 0,
+               rt5640_lout_mix, ARRAY_SIZE(rt5640_lout_mix)),
+       SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0,
+               rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
+       SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
+               RT5640_PWR_MA_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Improve HP Amp Drv", RT5640_PWR_ANLG1,
+               SND_SOC_NOPM, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP L Amp", RT5640_PWR_ANLG1,
+               RT5640_PWR_HP_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP R Amp", RT5640_PWR_ANLG1,
+               RT5640_PWR_HP_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Improve SPK Amp Drv", RT5640_PWR_DIG1,
+               SND_SOC_NOPM, 0, spk_event,
+               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+       /* Output Lines */
+       SND_SOC_DAPM_OUTPUT("SPOLP"),
+       SND_SOC_DAPM_OUTPUT("SPOLN"),
+       SND_SOC_DAPM_OUTPUT("SPORP"),
+       SND_SOC_DAPM_OUTPUT("SPORN"),
+       SND_SOC_DAPM_OUTPUT("HPOL"),
+       SND_SOC_DAPM_OUTPUT("HPOR"),
+       SND_SOC_DAPM_OUTPUT("LOUTL"),
+       SND_SOC_DAPM_OUTPUT("LOUTR"),
+       SND_SOC_DAPM_OUTPUT("MONOP"),
+       SND_SOC_DAPM_OUTPUT("MONON"),
+};
+
+static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
+       {"IN1P", NULL, "LDO2"},
+       {"IN2P", NULL, "LDO2"},
+
+       {"DMIC L1", NULL, "DMIC1"},
+       {"DMIC R1", NULL, "DMIC1"},
+       {"DMIC L2", NULL, "DMIC2"},
+       {"DMIC R2", NULL, "DMIC2"},
+
+       {"BST1", NULL, "IN1P"},
+       {"BST1", NULL, "IN1N"},
+       {"BST2", NULL, "IN2P"},
+       {"BST2", NULL, "IN2N"},
+
+       {"INL VOL", NULL, "IN2P"},
+       {"INR VOL", NULL, "IN2N"},
+
+       {"RECMIXL", "HPOL Switch", "HPOL"},
+       {"RECMIXL", "INL Switch", "INL VOL"},
+       {"RECMIXL", "BST2 Switch", "BST2"},
+       {"RECMIXL", "BST1 Switch", "BST1"},
+       {"RECMIXL", "OUT MIXL Switch", "OUT MIXL"},
+
+       {"RECMIXR", "HPOR Switch", "HPOR"},
+       {"RECMIXR", "INR Switch", "INR VOL"},
+       {"RECMIXR", "BST2 Switch", "BST2"},
+       {"RECMIXR", "BST1 Switch", "BST1"},
+       {"RECMIXR", "OUT MIXR Switch", "OUT MIXR"},
+
+       {"ADC L", NULL, "RECMIXL"},
+       {"ADC R", NULL, "RECMIXR"},
+
+       {"DMIC L1", NULL, "DMIC CLK"},
+       {"DMIC L1", NULL, "DMIC1 Power"},
+       {"DMIC R1", NULL, "DMIC CLK"},
+       {"DMIC R1", NULL, "DMIC1 Power"},
+       {"DMIC L2", NULL, "DMIC CLK"},
+       {"DMIC L2", NULL, "DMIC2 Power"},
+       {"DMIC R2", NULL, "DMIC CLK"},
+       {"DMIC R2", NULL, "DMIC2 Power"},
+
+       {"Stereo ADC L2 Mux", "DMIC1", "DMIC L1"},
+       {"Stereo ADC L2 Mux", "DMIC2", "DMIC L2"},
+       {"Stereo ADC L2 Mux", "DIG MIX", "DIG MIXL"},
+       {"Stereo ADC L1 Mux", "ADC", "ADC L"},
+       {"Stereo ADC L1 Mux", "DIG MIX", "DIG MIXL"},
+
+       {"Stereo ADC R1 Mux", "ADC", "ADC R"},
+       {"Stereo ADC R1 Mux", "DIG MIX", "DIG MIXR"},
+       {"Stereo ADC R2 Mux", "DMIC1", "DMIC R1"},
+       {"Stereo ADC R2 Mux", "DMIC2", "DMIC R2"},
+       {"Stereo ADC R2 Mux", "DIG MIX", "DIG MIXR"},
+
+       {"Mono ADC L2 Mux", "DMIC L1", "DMIC L1"},
+       {"Mono ADC L2 Mux", "DMIC L2", "DMIC L2"},
+       {"Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL"},
+       {"Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL"},
+       {"Mono ADC L1 Mux", "ADCL", "ADC L"},
+
+       {"Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR"},
+       {"Mono ADC R1 Mux", "ADCR", "ADC R"},
+       {"Mono ADC R2 Mux", "DMIC R1", "DMIC R1"},
+       {"Mono ADC R2 Mux", "DMIC R2", "DMIC R2"},
+       {"Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR"},
+
+       {"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"},
+       {"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"},
+       {"Stereo ADC MIXL", NULL, "Stereo Filter"},
+       {"Stereo Filter", NULL, "PLL1", check_sysclk1_source},
+
+       {"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"},
+       {"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"},
+       {"Stereo ADC MIXR", NULL, "Stereo Filter"},
+       {"Stereo Filter", NULL, "PLL1", check_sysclk1_source},
+
+       {"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},
+       {"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},
+       {"Mono ADC MIXL", NULL, "Mono Left Filter"},
+       {"Mono Left Filter", NULL, "PLL1", check_sysclk1_source},
+
+       {"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},
+       {"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},
+       {"Mono ADC MIXR", NULL, "Mono Right Filter"},
+       {"Mono Right Filter", NULL, "PLL1", check_sysclk1_source},
+
+       {"IF2 ADC L", NULL, "Mono ADC MIXL"},
+       {"IF2 ADC R", NULL, "Mono ADC MIXR"},
+       {"IF1 ADC L", NULL, "Stereo ADC MIXL"},
+       {"IF1 ADC R", NULL, "Stereo ADC MIXR"},
+
+       {"IF1 ADC", NULL, "I2S1"},
+       {"IF1 ADC", NULL, "IF1 ADC L"},
+       {"IF1 ADC", NULL, "IF1 ADC R"},
+       {"IF2 ADC", NULL, "I2S2"},
+       {"IF2 ADC", NULL, "IF2 ADC L"},
+       {"IF2 ADC", NULL, "IF2 ADC R"},
+
+       {"DAI1 TX Mux", "1:1|2:2", "IF1 ADC"},
+       {"DAI1 TX Mux", "1:2|2:1", "IF2 ADC"},
+       {"DAI1 IF1 Mux", "1:1|2:1", "IF1 ADC"},
+       {"DAI1 IF2 Mux", "1:1|2:1", "IF2 ADC"},
+       {"SDI1 TX Mux", "IF1", "DAI1 IF1 Mux"},
+       {"SDI1 TX Mux", "IF2", "DAI1 IF2 Mux"},
+
+       {"DAI2 TX Mux", "1:2|2:1", "IF1 ADC"},
+       {"DAI2 TX Mux", "1:1|2:2", "IF2 ADC"},
+       {"DAI2 IF1 Mux", "1:2|2:2", "IF1 ADC"},
+       {"DAI2 IF2 Mux", "1:2|2:2", "IF2 ADC"},
+       {"SDI2 TX Mux", "IF1", "DAI2 IF1 Mux"},
+       {"SDI2 TX Mux", "IF2", "DAI2 IF2 Mux"},
+
+       {"AIF1TX", NULL, "DAI1 TX Mux"},
+       {"AIF1TX", NULL, "SDI1 TX Mux"},
+       {"AIF2TX", NULL, "DAI2 TX Mux"},
+       {"AIF2TX", NULL, "SDI2 TX Mux"},
+
+       {"DAI1 RX Mux", "1:1|2:2", "AIF1RX"},
+       {"DAI1 RX Mux", "1:1|2:1", "AIF1RX"},
+       {"DAI1 RX Mux", "1:2|2:1", "AIF2RX"},
+       {"DAI1 RX Mux", "1:2|2:2", "AIF2RX"},
+
+       {"DAI2 RX Mux", "1:2|2:1", "AIF1RX"},
+       {"DAI2 RX Mux", "1:1|2:1", "AIF1RX"},
+       {"DAI2 RX Mux", "1:1|2:2", "AIF2RX"},
+       {"DAI2 RX Mux", "1:2|2:2", "AIF2RX"},
+
+       {"IF1 DAC", NULL, "I2S1"},
+       {"IF1 DAC", NULL, "DAI1 RX Mux"},
+       {"IF2 DAC", NULL, "I2S2"},
+       {"IF2 DAC", NULL, "DAI2 RX Mux"},
+
+       {"IF1 DAC L", NULL, "IF1 DAC"},
+       {"IF1 DAC R", NULL, "IF1 DAC"},
+       {"IF2 DAC L", NULL, "IF2 DAC"},
+       {"IF2 DAC R", NULL, "IF2 DAC"},
+
+       {"DAC MIXL", "Stereo ADC Switch", "Stereo ADC MIXL"},
+       {"DAC MIXL", "INF1 Switch", "IF1 DAC L"},
+       {"DAC MIXR", "Stereo ADC Switch", "Stereo ADC MIXR"},
+       {"DAC MIXR", "INF1 Switch", "IF1 DAC R"},
+
+       {"ANC", NULL, "Stereo ADC MIXL"},
+       {"ANC", NULL, "Stereo ADC MIXR"},
+
+       {"Audio DSP", NULL, "DAC MIXL"},
+       {"Audio DSP", NULL, "DAC MIXR"},
+
+       {"DAC L2 Mux", "IF2", "IF2 DAC L"},
+       {"DAC L2 Mux", "Base L/R", "Audio DSP"},
+
+       {"DAC R2 Mux", "IF2", "IF2 DAC R"},
+
+       {"Stereo DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
+       {"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Stereo DAC MIXL", "ANC Switch", "ANC"},
+       {"Stereo DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
+       {"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+       {"Stereo DAC MIXR", "ANC Switch", "ANC"},
+
+       {"Mono DAC MIXL", "DAC L1 Switch", "DAC MIXL"},
+       {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},
+       {"Mono DAC MIXR", "DAC R1 Switch", "DAC MIXR"},
+       {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+       {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},
+
+       {"DIG MIXL", "DAC L1 Switch", "DAC MIXL"},
+       {"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},
+       {"DIG MIXR", "DAC R1 Switch", "DAC MIXR"},
+       {"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"},
+
+       {"DAC L1", NULL, "Stereo DAC MIXL"},
+       {"DAC L1", NULL, "PLL1", check_sysclk1_source},
+       {"DAC R1", NULL, "Stereo DAC MIXR"},
+       {"DAC R1", NULL, "PLL1", check_sysclk1_source},
+       {"DAC L2", NULL, "Mono DAC MIXL"},
+       {"DAC L2", NULL, "PLL1", check_sysclk1_source},
+       {"DAC R2", NULL, "Mono DAC MIXR"},
+       {"DAC R2", NULL, "PLL1", check_sysclk1_source},
+
+       {"SPK MIXL", "REC MIXL Switch", "RECMIXL"},
+       {"SPK MIXL", "INL Switch", "INL VOL"},
+       {"SPK MIXL", "DAC L1 Switch", "DAC L1"},
+       {"SPK MIXL", "DAC L2 Switch", "DAC L2"},
+       {"SPK MIXL", "OUT MIXL Switch", "OUT MIXL"},
+       {"SPK MIXR", "REC MIXR Switch", "RECMIXR"},
+       {"SPK MIXR", "INR Switch", "INR VOL"},
+       {"SPK MIXR", "DAC R1 Switch", "DAC R1"},
+       {"SPK MIXR", "DAC R2 Switch", "DAC R2"},
+       {"SPK MIXR", "OUT MIXR Switch", "OUT MIXR"},
+
+       {"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"},
+       {"OUT MIXL", "BST1 Switch", "BST1"},
+       {"OUT MIXL", "INL Switch", "INL VOL"},
+       {"OUT MIXL", "REC MIXL Switch", "RECMIXL"},
+       {"OUT MIXL", "DAC R2 Switch", "DAC R2"},
+       {"OUT MIXL", "DAC L2 Switch", "DAC L2"},
+       {"OUT MIXL", "DAC L1 Switch", "DAC L1"},
+
+       {"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"},
+       {"OUT MIXR", "BST2 Switch", "BST2"},
+       {"OUT MIXR", "BST1 Switch", "BST1"},
+       {"OUT MIXR", "INR Switch", "INR VOL"},
+       {"OUT MIXR", "REC MIXR Switch", "RECMIXR"},
+       {"OUT MIXR", "DAC L2 Switch", "DAC L2"},
+       {"OUT MIXR", "DAC R2 Switch", "DAC R2"},
+       {"OUT MIXR", "DAC R1 Switch", "DAC R1"},
+
+       {"SPKVOL L", NULL, "SPK MIXL"},
+       {"SPKVOL R", NULL, "SPK MIXR"},
+       {"HPOVOL L", NULL, "OUT MIXL"},
+       {"HPOVOL R", NULL, "OUT MIXR"},
+       {"OUTVOL L", NULL, "OUT MIXL"},
+       {"OUTVOL R", NULL, "OUT MIXR"},
+
+       {"SPOL MIX", "DAC R1 Switch", "DAC R1"},
+       {"SPOL MIX", "DAC L1 Switch", "DAC L1"},
+       {"SPOL MIX", "SPKVOL R Switch", "SPKVOL R"},
+       {"SPOL MIX", "SPKVOL L Switch", "SPKVOL L"},
+       {"SPOL MIX", "BST1 Switch", "BST1"},
+       {"SPOR MIX", "DAC R1 Switch", "DAC R1"},
+       {"SPOR MIX", "SPKVOL R Switch", "SPKVOL R"},
+       {"SPOR MIX", "BST1 Switch", "BST1"},
+
+       {"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},
+       {"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"},
+       {"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"},
+       {"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},
+       {"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"},
+       {"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"},
+
+       {"LOUT MIX", "DAC L1 Switch", "DAC L1"},
+       {"LOUT MIX", "DAC R1 Switch", "DAC R1"},
+       {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},
+       {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"},
+
+       {"Mono MIX", "DAC R2 Switch", "DAC R2"},
+       {"Mono MIX", "DAC L2 Switch", "DAC L2"},
+       {"Mono MIX", "OUTVOL R Switch", "OUTVOL R"},
+       {"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
+       {"Mono MIX", "BST1 Switch", "BST1"},
+
+       {"HP L Amp", NULL, "HPO MIX L"},
+       {"HP R Amp", NULL, "HPO MIX R"},
+
+       {"SPOLP", NULL, "SPOL MIX"},
+       {"SPOLN", NULL, "SPOL MIX"},
+       {"SPORP", NULL, "SPOR MIX"},
+       {"SPORN", NULL, "SPOR MIX"},
+
+       {"SPOLP", NULL, "Improve SPK Amp Drv"},
+       {"SPOLN", NULL, "Improve SPK Amp Drv"},
+       {"SPORP", NULL, "Improve SPK Amp Drv"},
+       {"SPORN", NULL, "Improve SPK Amp Drv"},
+
+       {"HPOL", NULL, "Improve HP Amp Drv"},
+       {"HPOR", NULL, "Improve HP Amp Drv"},
+
+       {"HPOL", NULL, "HP L Amp"},
+       {"HPOR", NULL, "HP R Amp"},
+       {"LOUTL", NULL, "LOUT MIX"},
+       {"LOUTR", NULL, "LOUT MIX"},
+       {"MONOP", NULL, "Mono MIX"},
+       {"MONON", NULL, "Mono MIX"},
+       {"MONOP", NULL, "Improve MONO Amp Drv"},
+};
+
+static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
+{
+       int ret = 0, val;
+
+       if (codec == NULL)
+               return -EINVAL;
+
+       val = snd_soc_read(codec, RT5640_I2S1_SDP);
+       val = (val & RT5640_I2S_IF_MASK) >> RT5640_I2S_IF_SFT;
+       switch (dai_id) {
+       case RT5640_AIF1:
+               switch (val) {
+               case RT5640_IF_123:
+               case RT5640_IF_132:
+                       ret |= RT5640_U_IF1;
+                       break;
+               case RT5640_IF_113:
+                       ret |= RT5640_U_IF1;
+               case RT5640_IF_312:
+               case RT5640_IF_213:
+                       ret |= RT5640_U_IF2;
+                       break;
+               }
+               break;
+
+       case RT5640_AIF2:
+               switch (val) {
+               case RT5640_IF_231:
+               case RT5640_IF_213:
+                       ret |= RT5640_U_IF1;
+                       break;
+               case RT5640_IF_223:
+                       ret |= RT5640_U_IF1;
+               case RT5640_IF_123:
+               case RT5640_IF_321:
+                       ret |= RT5640_U_IF2;
+                       break;
+               }
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int get_clk_info(int sclk, int rate)
+{
+       int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16};
+
+       if (sclk <= 0 || rate <= 0)
+               return -EINVAL;
+
+       rate = rate << 8;
+       for (i = 0; i < ARRAY_SIZE(pd); i++)
+               if (sclk == rate * pd[i])
+                       return i;
+
+       return -EINVAL;
+}
+
+static int rt5640_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val_len = 0, val_clk, mask_clk, dai_sel;
+       int pre_div, bclk_ms, frame_size;
+
+       rt5640->lrck[dai->id] = params_rate(params);
+       pre_div = get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);
+       if (pre_div < 0) {
+               dev_err(codec->dev, "Unsupported clock setting\n");
+               return -EINVAL;
+       }
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0) {
+               dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+               return frame_size;
+       }
+       if (frame_size > 32)
+               bclk_ms = 1;
+       else
+               bclk_ms = 0;
+       rt5640->bclk[dai->id] = rt5640->lrck[dai->id] * (32 << bclk_ms);
+
+       dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n",
+               rt5640->bclk[dai->id], rt5640->lrck[dai->id]);
+       dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",
+                               bclk_ms, pre_div, dai->id);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val_len |= RT5640_I2S_DL_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               val_len |= RT5640_I2S_DL_24;
+               break;
+       case SNDRV_PCM_FORMAT_S8:
+               val_len |= RT5640_I2S_DL_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dai_sel = get_sdp_info(codec, dai->id);
+       if (dai_sel < 0) {
+               dev_err(codec->dev, "Failed to get sdp info: %d\n", dai_sel);
+               return -EINVAL;
+       }
+       if (dai_sel & RT5640_U_IF1) {
+               mask_clk = RT5640_I2S_BCLK_MS1_MASK | RT5640_I2S_PD1_MASK;
+               val_clk = bclk_ms << RT5640_I2S_BCLK_MS1_SFT |
+                       pre_div << RT5640_I2S_PD1_SFT;
+               snd_soc_update_bits(codec, RT5640_I2S1_SDP,
+                       RT5640_I2S_DL_MASK, val_len);
+               snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
+       }
+       if (dai_sel & RT5640_U_IF2) {
+               mask_clk = RT5640_I2S_BCLK_MS2_MASK | RT5640_I2S_PD2_MASK;
+               val_clk = bclk_ms << RT5640_I2S_BCLK_MS2_SFT |
+                       pre_div << RT5640_I2S_PD2_SFT;
+               snd_soc_update_bits(codec, RT5640_I2S2_SDP,
+                       RT5640_I2S_DL_MASK, val_len);
+               snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
+       }
+
+       return 0;
+}
+
+static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0, dai_sel;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               rt5640->master[dai->id] = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               reg_val |= RT5640_I2S_MS_S;
+               rt5640->master[dai->id] = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               reg_val |= RT5640_I2S_BP_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               reg_val |= RT5640_I2S_DF_LEFT;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               reg_val |= RT5640_I2S_DF_PCM_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               reg_val  |= RT5640_I2S_DF_PCM_B;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dai_sel = get_sdp_info(codec, dai->id);
+       if (dai_sel < 0) {
+               dev_err(codec->dev, "Failed to get sdp info: %d\n", dai_sel);
+               return -EINVAL;
+       }
+       if (dai_sel & RT5640_U_IF1) {
+               snd_soc_update_bits(codec, RT5640_I2S1_SDP,
+                       RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
+                       RT5640_I2S_DF_MASK, reg_val);
+       }
+       if (dai_sel & RT5640_U_IF2) {
+               snd_soc_update_bits(codec, RT5640_I2S2_SDP,
+                       RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
+                       RT5640_I2S_DF_MASK, reg_val);
+       }
+
+       return 0;
+}
+
+static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg_val = 0;
+
+       if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src)
+               return 0;
+
+       switch (clk_id) {
+       case RT5640_SCLK_S_MCLK:
+               reg_val |= RT5640_SCLK_SRC_MCLK;
+               break;
+       case RT5640_SCLK_S_PLL1:
+               reg_val |= RT5640_SCLK_SRC_PLL1;
+               break;
+       case RT5640_SCLK_S_PLL1_TK:
+               reg_val |= RT5640_SCLK_SRC_PLL1T;
+               break;
+       case RT5640_SCLK_S_RCCLK:
+               reg_val |= RT5640_SCLK_SRC_RCCLK;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, RT5640_GLB_CLK,
+               RT5640_SCLK_SRC_MASK, reg_val);
+       rt5640->sysclk = freq;
+       rt5640->sysclk_src = clk_id;
+
+       dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+       return 0;
+}
+
+/**
+ * rt5640_pll_calc - Calculate PLL M/N/K code.
+ * @freq_in: external clock provided to codec.
+ * @freq_out: target clock which codec works on.
+ * @pll_code: Pointer to structure with M, N, K and bypass flag.
+ *
+ * Calculate M/N/K code to configure PLL for codec. And K is assigned to 2
+ * which make calculation more efficiently.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5640_pll_calc(const unsigned int freq_in,
+       const unsigned int freq_out, struct rt5640_pll_code *pll_code)
+{
+       int max_n = RT5640_PLL_N_MAX, max_m = RT5640_PLL_M_MAX;
+       int n = 0, m = 0, red, n_t, m_t, in_t, out_t;
+       int red_t = abs(freq_out - freq_in);
+       bool bypass = false;
+
+       if (RT5640_PLL_INP_MAX < freq_in || RT5640_PLL_INP_MIN > freq_in)
+               return -EINVAL;
+
+       for (n_t = 0; n_t <= max_n; n_t++) {
+               in_t = (freq_in >> 1) + (freq_in >> 2) * n_t;
+               if (in_t < 0)
+                       continue;
+               if (in_t == freq_out) {
+                       bypass = true;
+                       n = n_t;
+                       goto code_find;
+               }
+               for (m_t = 0; m_t <= max_m; m_t++) {
+                       out_t = in_t / (m_t + 2);
+                       red = abs(out_t - freq_out);
+                       if (red < red_t) {
+                               n = n_t;
+                               m = m_t;
+                               if (red == 0)
+                                       goto code_find;
+                               red_t = red;
+                       }
+               }
+       }
+       pr_debug("Only get approximation about PLL\n");
+
+code_find:
+       pll_code->m_bp = bypass;
+       pll_code->m_code = m;
+       pll_code->n_code = n;
+       pll_code->k_code = 2;
+       return 0;
+}
+
+static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
+                       unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       struct rt5640_pll_code *pll_code = &rt5640->pll_code;
+       int ret, dai_sel;
+
+       if (source == rt5640->pll_src && freq_in == rt5640->pll_in &&
+           freq_out == rt5640->pll_out)
+               return 0;
+
+       if (!freq_in || !freq_out) {
+               dev_dbg(codec->dev, "PLL disabled\n");
+
+               rt5640->pll_in = 0;
+               rt5640->pll_out = 0;
+               snd_soc_update_bits(codec, RT5640_GLB_CLK,
+                       RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_MCLK);
+               return 0;
+       }
+
+       switch (source) {
+       case RT5640_PLL1_S_MCLK:
+               snd_soc_update_bits(codec, RT5640_GLB_CLK,
+                       RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_MCLK);
+               break;
+       case RT5640_PLL1_S_BCLK1:
+       case RT5640_PLL1_S_BCLK2:
+               dai_sel = get_sdp_info(codec, dai->id);
+               if (dai_sel < 0) {
+                       dev_err(codec->dev,
+                               "Failed to get sdp info: %d\n", dai_sel);
+                       return -EINVAL;
+               }
+               if (dai_sel & RT5640_U_IF1) {
+                       snd_soc_update_bits(codec, RT5640_GLB_CLK,
+                               RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK1);
+               }
+               if (dai_sel & RT5640_U_IF2) {
+                       snd_soc_update_bits(codec, RT5640_GLB_CLK,
+                               RT5640_PLL1_SRC_MASK, RT5640_PLL1_SRC_BCLK2);
+               }
+               break;
+       default:
+               dev_err(codec->dev, "Unknown PLL source %d\n", source);
+               return -EINVAL;
+       }
+
+       ret = rt5640_pll_calc(freq_in, freq_out, pll_code);
+       if (ret < 0) {
+               dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+               return ret;
+       }
+
+       dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp,
+               (pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code);
+
+       snd_soc_write(codec, RT5640_PLL_CTRL1,
+               pll_code->n_code << RT5640_PLL_N_SFT | pll_code->k_code);
+       snd_soc_write(codec, RT5640_PLL_CTRL2,
+               (pll_code->m_bp ? 0 : pll_code->m_code) << RT5640_PLL_M_SFT |
+               pll_code->m_bp << RT5640_PLL_M_BP_SFT);
+
+       rt5640->pll_in = freq_in;
+       rt5640->pll_out = freq_out;
+       rt5640->pll_src = source;
+
+       return 0;
+}
+
+static int rt5640_set_bias_level(struct snd_soc_codec *codec,
+                       enum snd_soc_bias_level level)
+{
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+                       regcache_cache_only(rt5640->regmap, false);
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_VREF1 | RT5640_PWR_MB |
+                               RT5640_PWR_BG | RT5640_PWR_VREF2,
+                               RT5640_PWR_VREF1 | RT5640_PWR_MB |
+                               RT5640_PWR_BG | RT5640_PWR_VREF2);
+                       mdelay(10);
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_FV1 | RT5640_PWR_FV2,
+                               RT5640_PWR_FV1 | RT5640_PWR_FV2);
+                       regcache_sync(rt5640->regmap);
+                       snd_soc_update_bits(codec, RT5640_DUMMY1,
+                                               0x0301, 0x0301);
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+                                               0x001d, 0x0019);
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M2,
+                                               0x2000, 0x2000);
+                       snd_soc_update_bits(codec, RT5640_MICBIAS,
+                                               0x0030, 0x0030);
+               }
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_write(codec, RT5640_DEPOP_M1, 0x0004);
+               snd_soc_write(codec, RT5640_DEPOP_M2, 0x1100);
+               snd_soc_update_bits(codec, RT5640_DUMMY1, 0x1, 0);
+               snd_soc_write(codec, RT5640_PWR_DIG1, 0x0000);
+               snd_soc_write(codec, RT5640_PWR_DIG2, 0x0000);
+               snd_soc_write(codec, RT5640_PWR_VOL, 0x0000);
+               snd_soc_write(codec, RT5640_PWR_MIXER, 0x0000);
+               snd_soc_write(codec, RT5640_PWR_ANLG1, 0x0000);
+               snd_soc_write(codec, RT5640_PWR_ANLG2, 0x0000);
+               break;
+
+       default:
+               break;
+       }
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int rt5640_probe(struct snd_soc_codec *codec)
+{
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       rt5640->codec = codec;
+       codec->control_data = rt5640->regmap;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       codec->dapm.idle_bias_off = 1;
+       rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1, 0x001d, 0x0019);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M2, 0x2000, 0x2000);
+       snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
+       snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
+
+       return 0;
+}
+
+static int rt5640_remove(struct snd_soc_codec *codec)
+{
+       rt5640_reset(codec);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int rt5640_suspend(struct snd_soc_codec *codec)
+{
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+       rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       rt5640_reset(codec);
+       regcache_cache_only(rt5640->regmap, true);
+       regcache_mark_dirty(rt5640->regmap);
+
+       return 0;
+}
+
+static int rt5640_resume(struct snd_soc_codec *codec)
+{
+       rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+#else
+#define rt5640_suspend NULL
+#define rt5640_resume NULL
+#endif
+
+#define RT5640_STEREO_RATES SNDRV_PCM_RATE_8000_96000
+#define RT5640_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5640_aif_dai_ops = {
+       .hw_params = rt5640_hw_params,
+       .set_fmt = rt5640_set_dai_fmt,
+       .set_sysclk = rt5640_set_dai_sysclk,
+       .set_pll = rt5640_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver rt5640_dai[] = {
+       {
+               .name = "rt5640-aif1",
+               .id = RT5640_AIF1,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5640_STEREO_RATES,
+                       .formats = RT5640_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5640_STEREO_RATES,
+                       .formats = RT5640_FORMATS,
+               },
+               .ops = &rt5640_aif_dai_ops,
+       },
+       {
+               .name = "rt5640-aif2",
+               .id = RT5640_AIF2,
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5640_STEREO_RATES,
+                       .formats = RT5640_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "AIF2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5640_STEREO_RATES,
+                       .formats = RT5640_FORMATS,
+               },
+               .ops = &rt5640_aif_dai_ops,
+       },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
+       .probe = rt5640_probe,
+       .remove = rt5640_remove,
+       .suspend = rt5640_suspend,
+       .resume = rt5640_resume,
+       .set_bias_level = rt5640_set_bias_level,
+       .controls = rt5640_snd_controls,
+       .num_controls = ARRAY_SIZE(rt5640_snd_controls),
+       .dapm_widgets = rt5640_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rt5640_dapm_widgets),
+       .dapm_routes = rt5640_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes),
+};
+
+static const struct regmap_config rt5640_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+
+       .max_register = RT5640_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5640_ranges) *
+                                              RT5640_PR_SPACING),
+       .volatile_reg = rt5640_volatile_register,
+       .readable_reg = rt5640_readable_register,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = rt5640_reg,
+       .num_reg_defaults = ARRAY_SIZE(rt5640_reg),
+       .ranges = rt5640_ranges,
+       .num_ranges = ARRAY_SIZE(rt5640_ranges),
+};
+
+static const struct i2c_device_id rt5640_i2c_id[] = {
+       { "rt5640", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
+
+static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
+{
+       rt5640->pdata.in1_diff = of_property_read_bool(np,
+                                       "realtek,in1-differential");
+       rt5640->pdata.in2_diff = of_property_read_bool(np,
+                                       "realtek,in2-differential");
+
+       rt5640->pdata.ldo1_en = of_get_named_gpio(np,
+                                       "realtek,ldo1-en-gpios", 0);
+       /*
+        * LDO1_EN is optional (it may be statically tied on the board).
+        * -ENOENT means that the property doesn't exist, i.e. there is no
+        * GPIO, so is not an error. Any other error code means the property
+        * exists, but could not be parsed.
+        */
+       if (!gpio_is_valid(rt5640->pdata.ldo1_en) &&
+                       (rt5640->pdata.ldo1_en != -ENOENT))
+               return rt5640->pdata.ldo1_en;
+
+       return 0;
+}
+
+static int rt5640_i2c_probe(struct i2c_client *i2c,
+                   const struct i2c_device_id *id)
+{
+       struct rt5640_platform_data *pdata = dev_get_platdata(&i2c->dev);
+       struct rt5640_priv *rt5640;
+       int ret;
+       unsigned int val;
+
+       rt5640 = devm_kzalloc(&i2c->dev,
+                               sizeof(struct rt5640_priv),
+                               GFP_KERNEL);
+       if (NULL == rt5640)
+               return -ENOMEM;
+       i2c_set_clientdata(i2c, rt5640);
+
+       if (pdata) {
+               rt5640->pdata = *pdata;
+               /*
+                * Translate zero'd out (default) pdata value to an invalid
+                * GPIO ID. This makes the pdata and DT paths consistent in
+                * terms of the value left in this field when no GPIO is
+                * specified, but means we can't actually use GPIO 0.
+                */
+               if (!rt5640->pdata.ldo1_en)
+                       rt5640->pdata.ldo1_en = -EINVAL;
+       } else if (i2c->dev.of_node) {
+               ret = rt5640_parse_dt(rt5640, i2c->dev.of_node);
+               if (ret)
+                       return ret;
+       } else
+               rt5640->pdata.ldo1_en = -EINVAL;
+
+       rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap);
+       if (IS_ERR(rt5640->regmap)) {
+               ret = PTR_ERR(rt5640->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
+               ret = devm_gpio_request_one(&i2c->dev, rt5640->pdata.ldo1_en,
+                                           GPIOF_OUT_INIT_HIGH,
+                                           "RT5640 LDO1_EN");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request LDO1_EN %d: %d\n",
+                               rt5640->pdata.ldo1_en, ret);
+                       return ret;
+               }
+               msleep(400);
+       }
+
+       regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val);
+       if ((val != RT5640_DEVICE_ID)) {
+               dev_err(&i2c->dev,
+                       "Device with ID register %x is not rt5640/39\n", val);
+               return -ENODEV;
+       }
+
+       regmap_write(rt5640->regmap, RT5640_RESET, 0);
+
+       ret = regmap_register_patch(rt5640->regmap, init_list,
+                                   ARRAY_SIZE(init_list));
+       if (ret != 0)
+               dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+       if (rt5640->pdata.in1_diff)
+               regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2,
+                                       RT5640_IN_DF1, RT5640_IN_DF1);
+
+       if (rt5640->pdata.in2_diff)
+               regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
+                                       RT5640_IN_DF2, RT5640_IN_DF2);
+
+       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
+                       rt5640_dai, ARRAY_SIZE(rt5640_dai));
+       if (ret < 0)
+               goto err;
+
+       return 0;
+err:
+       return ret;
+}
+
+static int rt5640_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+
+       return 0;
+}
+
+static struct i2c_driver rt5640_i2c_driver = {
+       .driver = {
+               .name = "rt5640",
+               .owner = THIS_MODULE,
+       },
+       .probe = rt5640_i2c_probe,
+       .remove   = rt5640_i2c_remove,
+       .id_table = rt5640_i2c_id,
+};
+module_i2c_driver(rt5640_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5640 driver");
+MODULE_AUTHOR("Johnny Hsu <johnnyhsu@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
new file mode 100644 (file)
index 0000000..c48286d
--- /dev/null
@@ -0,0 +1,2092 @@
+/*
+ * rt5640.h  --  RT5640 ALSA SoC audio driver
+ *
+ * Copyright 2011 Realtek Microelectronics
+ * Author: Johnny Hsu <johnnyhsu@realtek.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 _RT5640_H
+#define _RT5640_H
+
+#include <sound/rt5640.h>
+
+/* Info */
+#define RT5640_RESET                           0x00
+#define RT5640_VENDOR_ID                       0xfd
+#define RT5640_VENDOR_ID1                      0xfe
+#define RT5640_VENDOR_ID2                      0xff
+/*  I/O - Output */
+#define RT5640_SPK_VOL                         0x01
+#define RT5640_HP_VOL                          0x02
+#define RT5640_OUTPUT                          0x03
+#define RT5640_MONO_OUT                                0x04
+/* I/O - Input */
+#define RT5640_IN1_IN2                         0x0d
+#define RT5640_IN3_IN4                         0x0e
+#define RT5640_INL_INR_VOL                     0x0f
+/* I/O - ADC/DAC/DMIC */
+#define RT5640_DAC1_DIG_VOL                    0x19
+#define RT5640_DAC2_DIG_VOL                    0x1a
+#define RT5640_DAC2_CTRL                       0x1b
+#define RT5640_ADC_DIG_VOL                     0x1c
+#define RT5640_ADC_DATA                                0x1d
+#define RT5640_ADC_BST_VOL                     0x1e
+/* Mixer - D-D */
+#define RT5640_STO_ADC_MIXER                   0x27
+#define RT5640_MONO_ADC_MIXER                  0x28
+#define RT5640_AD_DA_MIXER                     0x29
+#define RT5640_STO_DAC_MIXER                   0x2a
+#define RT5640_MONO_DAC_MIXER                  0x2b
+#define RT5640_DIG_MIXER                       0x2c
+#define RT5640_DSP_PATH1                       0x2d
+#define RT5640_DSP_PATH2                       0x2e
+#define RT5640_DIG_INF_DATA                    0x2f
+/* Mixer - ADC */
+#define RT5640_REC_L1_MIXER                    0x3b
+#define RT5640_REC_L2_MIXER                    0x3c
+#define RT5640_REC_R1_MIXER                    0x3d
+#define RT5640_REC_R2_MIXER                    0x3e
+/* Mixer - DAC */
+#define RT5640_HPO_MIXER                       0x45
+#define RT5640_SPK_L_MIXER                     0x46
+#define RT5640_SPK_R_MIXER                     0x47
+#define RT5640_SPO_L_MIXER                     0x48
+#define RT5640_SPO_R_MIXER                     0x49
+#define RT5640_SPO_CLSD_RATIO                  0x4a
+#define RT5640_MONO_MIXER                      0x4c
+#define RT5640_OUT_L1_MIXER                    0x4d
+#define RT5640_OUT_L2_MIXER                    0x4e
+#define RT5640_OUT_L3_MIXER                    0x4f
+#define RT5640_OUT_R1_MIXER                    0x50
+#define RT5640_OUT_R2_MIXER                    0x51
+#define RT5640_OUT_R3_MIXER                    0x52
+#define RT5640_LOUT_MIXER                      0x53
+/* Power */
+#define RT5640_PWR_DIG1                                0x61
+#define RT5640_PWR_DIG2                                0x62
+#define RT5640_PWR_ANLG1                       0x63
+#define RT5640_PWR_ANLG2                       0x64
+#define RT5640_PWR_MIXER                       0x65
+#define RT5640_PWR_VOL                         0x66
+/* Private Register Control */
+#define RT5640_PRIV_INDEX                      0x6a
+#define RT5640_PRIV_DATA                       0x6c
+/* Format - ADC/DAC */
+#define RT5640_I2S1_SDP                                0x70
+#define RT5640_I2S2_SDP                                0x71
+#define RT5640_ADDA_CLK1                       0x73
+#define RT5640_ADDA_CLK2                       0x74
+#define RT5640_DMIC                            0x75
+/* Function - Analog */
+#define RT5640_GLB_CLK                         0x80
+#define RT5640_PLL_CTRL1                       0x81
+#define RT5640_PLL_CTRL2                       0x82
+#define RT5640_ASRC_1                          0x83
+#define RT5640_ASRC_2                          0x84
+#define RT5640_ASRC_3                          0x85
+#define RT5640_ASRC_4                          0x89
+#define RT5640_ASRC_5                          0x8a
+#define RT5640_HP_OVCD                         0x8b
+#define RT5640_CLS_D_OVCD                      0x8c
+#define RT5640_CLS_D_OUT                       0x8d
+#define RT5640_DEPOP_M1                                0x8e
+#define RT5640_DEPOP_M2                                0x8f
+#define RT5640_DEPOP_M3                                0x90
+#define RT5640_CHARGE_PUMP                     0x91
+#define RT5640_PV_DET_SPK_G                    0x92
+#define RT5640_MICBIAS                         0x93
+/* Function - Digital */
+#define RT5640_EQ_CTRL1                                0xb0
+#define RT5640_EQ_CTRL2                                0xb1
+#define RT5640_WIND_FILTER                     0xb2
+#define RT5640_DRC_AGC_1                       0xb4
+#define RT5640_DRC_AGC_2                       0xb5
+#define RT5640_DRC_AGC_3                       0xb6
+#define RT5640_SVOL_ZC                         0xb7
+#define RT5640_ANC_CTRL1                       0xb8
+#define RT5640_ANC_CTRL2                       0xb9
+#define RT5640_ANC_CTRL3                       0xba
+#define RT5640_JD_CTRL                         0xbb
+#define RT5640_ANC_JD                          0xbc
+#define RT5640_IRQ_CTRL1                       0xbd
+#define RT5640_IRQ_CTRL2                       0xbe
+#define RT5640_INT_IRQ_ST                      0xbf
+#define RT5640_GPIO_CTRL1                      0xc0
+#define RT5640_GPIO_CTRL2                      0xc1
+#define RT5640_GPIO_CTRL3                      0xc2
+#define RT5640_DSP_CTRL1                       0xc4
+#define RT5640_DSP_CTRL2                       0xc5
+#define RT5640_DSP_CTRL3                       0xc6
+#define RT5640_DSP_CTRL4                       0xc7
+#define RT5640_PGM_REG_ARR1                    0xc8
+#define RT5640_PGM_REG_ARR2                    0xc9
+#define RT5640_PGM_REG_ARR3                    0xca
+#define RT5640_PGM_REG_ARR4                    0xcb
+#define RT5640_PGM_REG_ARR5                    0xcc
+#define RT5640_SCB_FUNC                                0xcd
+#define RT5640_SCB_CTRL                                0xce
+#define RT5640_BASE_BACK                       0xcf
+#define RT5640_MP3_PLUS1                       0xd0
+#define RT5640_MP3_PLUS2                       0xd1
+#define RT5640_3D_HP                           0xd2
+#define RT5640_ADJ_HPF                         0xd3
+#define RT5640_HP_CALIB_AMP_DET                        0xd6
+#define RT5640_HP_CALIB2                       0xd7
+#define RT5640_SV_ZCD1                         0xd9
+#define RT5640_SV_ZCD2                         0xda
+/* Dummy Register */
+#define RT5640_DUMMY1                          0xfa
+#define RT5640_DUMMY2                          0xfb
+#define RT5640_DUMMY3                          0xfc
+
+
+/* Index of Codec Private Register definition */
+#define RT5640_3D_SPK                          0x63
+#define RT5640_WND_1                           0x6c
+#define RT5640_WND_2                           0x6d
+#define RT5640_WND_3                           0x6e
+#define RT5640_WND_4                           0x6f
+#define RT5640_WND_5                           0x70
+#define RT5640_WND_8                           0x73
+#define RT5640_DIP_SPK_INF                     0x75
+#define RT5640_EQ_BW_LOP                       0xa0
+#define RT5640_EQ_GN_LOP                       0xa1
+#define RT5640_EQ_FC_BP1                       0xa2
+#define RT5640_EQ_BW_BP1                       0xa3
+#define RT5640_EQ_GN_BP1                       0xa4
+#define RT5640_EQ_FC_BP2                       0xa5
+#define RT5640_EQ_BW_BP2                       0xa6
+#define RT5640_EQ_GN_BP2                       0xa7
+#define RT5640_EQ_FC_BP3                       0xa8
+#define RT5640_EQ_BW_BP3                       0xa9
+#define RT5640_EQ_GN_BP3                       0xaa
+#define RT5640_EQ_FC_BP4                       0xab
+#define RT5640_EQ_BW_BP4                       0xac
+#define RT5640_EQ_GN_BP4                       0xad
+#define RT5640_EQ_FC_HIP1                      0xae
+#define RT5640_EQ_GN_HIP1                      0xaf
+#define RT5640_EQ_FC_HIP2                      0xb0
+#define RT5640_EQ_BW_HIP2                      0xb1
+#define RT5640_EQ_GN_HIP2                      0xb2
+#define RT5640_EQ_PRE_VOL                      0xb3
+#define RT5640_EQ_PST_VOL                      0xb4
+
+/* global definition */
+#define RT5640_L_MUTE                          (0x1 << 15)
+#define RT5640_L_MUTE_SFT                      15
+#define RT5640_VOL_L_MUTE                      (0x1 << 14)
+#define RT5640_VOL_L_SFT                       14
+#define RT5640_R_MUTE                          (0x1 << 7)
+#define RT5640_R_MUTE_SFT                      7
+#define RT5640_VOL_R_MUTE                      (0x1 << 6)
+#define RT5640_VOL_R_SFT                       6
+#define RT5640_L_VOL_MASK                      (0x3f << 8)
+#define RT5640_L_VOL_SFT                       8
+#define RT5640_R_VOL_MASK                      (0x3f)
+#define RT5640_R_VOL_SFT                       0
+
+/* IN1 and IN2 Control (0x0d) */
+/* IN3 and IN4 Control (0x0e) */
+#define RT5640_BST_SFT1                                12
+#define RT5640_BST_SFT2                                8
+#define RT5640_IN_DF1                          (0x1 << 7)
+#define RT5640_IN_SFT1                         7
+#define RT5640_IN_DF2                          (0x1 << 6)
+#define RT5640_IN_SFT2                         6
+
+/* INL and INR Volume Control (0x0f) */
+#define RT5640_INL_SEL_MASK                    (0x1 << 15)
+#define RT5640_INL_SEL_SFT                     15
+#define RT5640_INL_SEL_IN4P                    (0x0 << 15)
+#define RT5640_INL_SEL_MONOP                   (0x1 << 15)
+#define RT5640_INL_VOL_MASK                    (0x1f << 8)
+#define RT5640_INL_VOL_SFT                     8
+#define RT5640_INR_SEL_MASK                    (0x1 << 7)
+#define RT5640_INR_SEL_SFT                     7
+#define RT5640_INR_SEL_IN4N                    (0x0 << 7)
+#define RT5640_INR_SEL_MONON                   (0x1 << 7)
+#define RT5640_INR_VOL_MASK                    (0x1f)
+#define RT5640_INR_VOL_SFT                     0
+
+/* DAC1 Digital Volume (0x19) */
+#define RT5640_DAC_L1_VOL_MASK                 (0xff << 8)
+#define RT5640_DAC_L1_VOL_SFT                  8
+#define RT5640_DAC_R1_VOL_MASK                 (0xff)
+#define RT5640_DAC_R1_VOL_SFT                  0
+
+/* DAC2 Digital Volume (0x1a) */
+#define RT5640_DAC_L2_VOL_MASK                 (0xff << 8)
+#define RT5640_DAC_L2_VOL_SFT                  8
+#define RT5640_DAC_R2_VOL_MASK                 (0xff)
+#define RT5640_DAC_R2_VOL_SFT                  0
+
+/* DAC2 Control (0x1b) */
+#define RT5640_M_DAC_L2_VOL                    (0x1 << 13)
+#define RT5640_M_DAC_L2_VOL_SFT                        13
+#define RT5640_M_DAC_R2_VOL                    (0x1 << 12)
+#define RT5640_M_DAC_R2_VOL_SFT                        12
+
+/* ADC Digital Volume Control (0x1c) */
+#define RT5640_ADC_L_VOL_MASK                  (0x7f << 8)
+#define RT5640_ADC_L_VOL_SFT                   8
+#define RT5640_ADC_R_VOL_MASK                  (0x7f)
+#define RT5640_ADC_R_VOL_SFT                   0
+
+/* Mono ADC Digital Volume Control (0x1d) */
+#define RT5640_MONO_ADC_L_VOL_MASK             (0x7f << 8)
+#define RT5640_MONO_ADC_L_VOL_SFT              8
+#define RT5640_MONO_ADC_R_VOL_MASK             (0x7f)
+#define RT5640_MONO_ADC_R_VOL_SFT              0
+
+/* ADC Boost Volume Control (0x1e) */
+#define RT5640_ADC_L_BST_MASK                  (0x3 << 14)
+#define RT5640_ADC_L_BST_SFT                   14
+#define RT5640_ADC_R_BST_MASK                  (0x3 << 12)
+#define RT5640_ADC_R_BST_SFT                   12
+#define RT5640_ADC_COMP_MASK                   (0x3 << 10)
+#define RT5640_ADC_COMP_SFT                    10
+
+/* Stereo ADC Mixer Control (0x27) */
+#define RT5640_M_ADC_L1                                (0x1 << 14)
+#define RT5640_M_ADC_L1_SFT                    14
+#define RT5640_M_ADC_L2                                (0x1 << 13)
+#define RT5640_M_ADC_L2_SFT                    13
+#define RT5640_ADC_1_SRC_MASK                  (0x1 << 12)
+#define RT5640_ADC_1_SRC_SFT                   12
+#define RT5640_ADC_1_SRC_ADC                   (0x1 << 12)
+#define RT5640_ADC_1_SRC_DACMIX                        (0x0 << 12)
+#define RT5640_ADC_2_SRC_MASK                  (0x3 << 10)
+#define RT5640_ADC_2_SRC_SFT                   10
+#define RT5640_ADC_2_SRC_DMIC1                 (0x0 << 10)
+#define RT5640_ADC_2_SRC_DMIC2                 (0x1 << 10)
+#define RT5640_ADC_2_SRC_DACMIX                        (0x2 << 10)
+#define RT5640_M_ADC_R1                                (0x1 << 6)
+#define RT5640_M_ADC_R1_SFT                    6
+#define RT5640_M_ADC_R2                                (0x1 << 5)
+#define RT5640_M_ADC_R2_SFT                    5
+
+/* Mono ADC Mixer Control (0x28) */
+#define RT5640_M_MONO_ADC_L1                   (0x1 << 14)
+#define RT5640_M_MONO_ADC_L1_SFT               14
+#define RT5640_M_MONO_ADC_L2                   (0x1 << 13)
+#define RT5640_M_MONO_ADC_L2_SFT               13
+#define RT5640_MONO_ADC_L1_SRC_MASK            (0x1 << 12)
+#define RT5640_MONO_ADC_L1_SRC_SFT             12
+#define RT5640_MONO_ADC_L1_SRC_DACMIXL         (0x0 << 12)
+#define RT5640_MONO_ADC_L1_SRC_ADCL            (0x1 << 12)
+#define RT5640_MONO_ADC_L2_SRC_MASK            (0x3 << 10)
+#define RT5640_MONO_ADC_L2_SRC_SFT             10
+#define RT5640_MONO_ADC_L2_SRC_DMIC_L1         (0x0 << 10)
+#define RT5640_MONO_ADC_L2_SRC_DMIC_L2         (0x1 << 10)
+#define RT5640_MONO_ADC_L2_SRC_DACMIXL         (0x2 << 10)
+#define RT5640_M_MONO_ADC_R1                   (0x1 << 6)
+#define RT5640_M_MONO_ADC_R1_SFT               6
+#define RT5640_M_MONO_ADC_R2                   (0x1 << 5)
+#define RT5640_M_MONO_ADC_R2_SFT               5
+#define RT5640_MONO_ADC_R1_SRC_MASK            (0x1 << 4)
+#define RT5640_MONO_ADC_R1_SRC_SFT             4
+#define RT5640_MONO_ADC_R1_SRC_ADCR            (0x1 << 4)
+#define RT5640_MONO_ADC_R1_SRC_DACMIXR         (0x0 << 4)
+#define RT5640_MONO_ADC_R2_SRC_MASK            (0x3 << 2)
+#define RT5640_MONO_ADC_R2_SRC_SFT             2
+#define RT5640_MONO_ADC_R2_SRC_DMIC_R1         (0x0 << 2)
+#define RT5640_MONO_ADC_R2_SRC_DMIC_R2         (0x1 << 2)
+#define RT5640_MONO_ADC_R2_SRC_DACMIXR         (0x2 << 2)
+
+/* ADC Mixer to DAC Mixer Control (0x29) */
+#define RT5640_M_ADCMIX_L                      (0x1 << 15)
+#define RT5640_M_ADCMIX_L_SFT                  15
+#define RT5640_M_IF1_DAC_L                     (0x1 << 14)
+#define RT5640_M_IF1_DAC_L_SFT                 14
+#define RT5640_M_ADCMIX_R                      (0x1 << 7)
+#define RT5640_M_ADCMIX_R_SFT                  7
+#define RT5640_M_IF1_DAC_R                     (0x1 << 6)
+#define RT5640_M_IF1_DAC_R_SFT                 6
+
+/* Stereo DAC Mixer Control (0x2a) */
+#define RT5640_M_DAC_L1                                (0x1 << 14)
+#define RT5640_M_DAC_L1_SFT                    14
+#define RT5640_DAC_L1_STO_L_VOL_MASK           (0x1 << 13)
+#define RT5640_DAC_L1_STO_L_VOL_SFT            13
+#define RT5640_M_DAC_L2                                (0x1 << 12)
+#define RT5640_M_DAC_L2_SFT                    12
+#define RT5640_DAC_L2_STO_L_VOL_MASK           (0x1 << 11)
+#define RT5640_DAC_L2_STO_L_VOL_SFT            11
+#define RT5640_M_ANC_DAC_L                     (0x1 << 10)
+#define RT5640_M_ANC_DAC_L_SFT                 10
+#define RT5640_M_DAC_R1                                (0x1 << 6)
+#define RT5640_M_DAC_R1_SFT                    6
+#define RT5640_DAC_R1_STO_R_VOL_MASK           (0x1 << 5)
+#define RT5640_DAC_R1_STO_R_VOL_SFT            5
+#define RT5640_M_DAC_R2                                (0x1 << 4)
+#define RT5640_M_DAC_R2_SFT                    4
+#define RT5640_DAC_R2_STO_R_VOL_MASK           (0x1 << 3)
+#define RT5640_DAC_R2_STO_R_VOL_SFT            3
+#define RT5640_M_ANC_DAC_R                     (0x1 << 2)
+#define RT5640_M_ANC_DAC_R_SFT         2
+
+/* Mono DAC Mixer Control (0x2b) */
+#define RT5640_M_DAC_L1_MONO_L                 (0x1 << 14)
+#define RT5640_M_DAC_L1_MONO_L_SFT             14
+#define RT5640_DAC_L1_MONO_L_VOL_MASK          (0x1 << 13)
+#define RT5640_DAC_L1_MONO_L_VOL_SFT           13
+#define RT5640_M_DAC_L2_MONO_L                 (0x1 << 12)
+#define RT5640_M_DAC_L2_MONO_L_SFT             12
+#define RT5640_DAC_L2_MONO_L_VOL_MASK          (0x1 << 11)
+#define RT5640_DAC_L2_MONO_L_VOL_SFT           11
+#define RT5640_M_DAC_R2_MONO_L                 (0x1 << 10)
+#define RT5640_M_DAC_R2_MONO_L_SFT             10
+#define RT5640_DAC_R2_MONO_L_VOL_MASK          (0x1 << 9)
+#define RT5640_DAC_R2_MONO_L_VOL_SFT           9
+#define RT5640_M_DAC_R1_MONO_R                 (0x1 << 6)
+#define RT5640_M_DAC_R1_MONO_R_SFT             6
+#define RT5640_DAC_R1_MONO_R_VOL_MASK          (0x1 << 5)
+#define RT5640_DAC_R1_MONO_R_VOL_SFT           5
+#define RT5640_M_DAC_R2_MONO_R                 (0x1 << 4)
+#define RT5640_M_DAC_R2_MONO_R_SFT             4
+#define RT5640_DAC_R2_MONO_R_VOL_MASK          (0x1 << 3)
+#define RT5640_DAC_R2_MONO_R_VOL_SFT           3
+#define RT5640_M_DAC_L2_MONO_R                 (0x1 << 2)
+#define RT5640_M_DAC_L2_MONO_R_SFT             2
+#define RT5640_DAC_L2_MONO_R_VOL_MASK          (0x1 << 1)
+#define RT5640_DAC_L2_MONO_R_VOL_SFT           1
+
+/* Digital Mixer Control (0x2c) */
+#define RT5640_M_STO_L_DAC_L                   (0x1 << 15)
+#define RT5640_M_STO_L_DAC_L_SFT               15
+#define RT5640_STO_L_DAC_L_VOL_MASK            (0x1 << 14)
+#define RT5640_STO_L_DAC_L_VOL_SFT             14
+#define RT5640_M_DAC_L2_DAC_L                  (0x1 << 13)
+#define RT5640_M_DAC_L2_DAC_L_SFT              13
+#define RT5640_DAC_L2_DAC_L_VOL_MASK           (0x1 << 12)
+#define RT5640_DAC_L2_DAC_L_VOL_SFT            12
+#define RT5640_M_STO_R_DAC_R                   (0x1 << 11)
+#define RT5640_M_STO_R_DAC_R_SFT               11
+#define RT5640_STO_R_DAC_R_VOL_MASK            (0x1 << 10)
+#define RT5640_STO_R_DAC_R_VOL_SFT             10
+#define RT5640_M_DAC_R2_DAC_R                  (0x1 << 9)
+#define RT5640_M_DAC_R2_DAC_R_SFT              9
+#define RT5640_DAC_R2_DAC_R_VOL_MASK           (0x1 << 8)
+#define RT5640_DAC_R2_DAC_R_VOL_SFT            8
+
+/* DSP Path Control 1 (0x2d) */
+#define RT5640_RXDP_SRC_MASK                   (0x1 << 15)
+#define RT5640_RXDP_SRC_SFT                    15
+#define RT5640_RXDP_SRC_NOR                    (0x0 << 15)
+#define RT5640_RXDP_SRC_DIV3                   (0x1 << 15)
+#define RT5640_TXDP_SRC_MASK                   (0x1 << 14)
+#define RT5640_TXDP_SRC_SFT                    14
+#define RT5640_TXDP_SRC_NOR                    (0x0 << 14)
+#define RT5640_TXDP_SRC_DIV3                   (0x1 << 14)
+
+/* DSP Path Control 2 (0x2e) */
+#define RT5640_DAC_L2_SEL_MASK                 (0x3 << 14)
+#define RT5640_DAC_L2_SEL_SFT                  14
+#define RT5640_DAC_L2_SEL_IF2                  (0x0 << 14)
+#define RT5640_DAC_L2_SEL_IF3                  (0x1 << 14)
+#define RT5640_DAC_L2_SEL_TXDC                 (0x2 << 14)
+#define RT5640_DAC_L2_SEL_BASS                 (0x3 << 14)
+#define RT5640_DAC_R2_SEL_MASK                 (0x3 << 12)
+#define RT5640_DAC_R2_SEL_SFT                  12
+#define RT5640_DAC_R2_SEL_IF2                  (0x0 << 12)
+#define RT5640_DAC_R2_SEL_IF3                  (0x1 << 12)
+#define RT5640_DAC_R2_SEL_TXDC                 (0x2 << 12)
+#define RT5640_IF2_ADC_L_SEL_MASK              (0x1 << 11)
+#define RT5640_IF2_ADC_L_SEL_SFT               11
+#define RT5640_IF2_ADC_L_SEL_TXDP              (0x0 << 11)
+#define RT5640_IF2_ADC_L_SEL_PASS              (0x1 << 11)
+#define RT5640_IF2_ADC_R_SEL_MASK              (0x1 << 10)
+#define RT5640_IF2_ADC_R_SEL_SFT               10
+#define RT5640_IF2_ADC_R_SEL_TXDP              (0x0 << 10)
+#define RT5640_IF2_ADC_R_SEL_PASS              (0x1 << 10)
+#define RT5640_RXDC_SEL_MASK                   (0x3 << 8)
+#define RT5640_RXDC_SEL_SFT                    8
+#define RT5640_RXDC_SEL_NOR                    (0x0 << 8)
+#define RT5640_RXDC_SEL_L2R                    (0x1 << 8)
+#define RT5640_RXDC_SEL_R2L                    (0x2 << 8)
+#define RT5640_RXDC_SEL_SWAP                   (0x3 << 8)
+#define RT5640_RXDP_SEL_MASK                   (0x3 << 6)
+#define RT5640_RXDP_SEL_SFT                    6
+#define RT5640_RXDP_SEL_NOR                    (0x0 << 6)
+#define RT5640_RXDP_SEL_L2R                    (0x1 << 6)
+#define RT5640_RXDP_SEL_R2L                    (0x2 << 6)
+#define RT5640_RXDP_SEL_SWAP                   (0x3 << 6)
+#define RT5640_TXDC_SEL_MASK                   (0x3 << 4)
+#define RT5640_TXDC_SEL_SFT                    4
+#define RT5640_TXDC_SEL_NOR                    (0x0 << 4)
+#define RT5640_TXDC_SEL_L2R                    (0x1 << 4)
+#define RT5640_TXDC_SEL_R2L                    (0x2 << 4)
+#define RT5640_TXDC_SEL_SWAP                   (0x3 << 4)
+#define RT5640_TXDP_SEL_MASK                   (0x3 << 2)
+#define RT5640_TXDP_SEL_SFT                    2
+#define RT5640_TXDP_SEL_NOR                    (0x0 << 2)
+#define RT5640_TXDP_SEL_L2R                    (0x1 << 2)
+#define RT5640_TXDP_SEL_R2L                    (0x2 << 2)
+#define RT5640_TRXDP_SEL_SWAP                  (0x3 << 2)
+
+/* Digital Interface Data Control (0x2f) */
+#define RT5640_IF1_DAC_SEL_MASK                        (0x3 << 14)
+#define RT5640_IF1_DAC_SEL_SFT                 14
+#define RT5640_IF1_DAC_SEL_NOR                 (0x0 << 14)
+#define RT5640_IF1_DAC_SEL_L2R                 (0x1 << 14)
+#define RT5640_IF1_DAC_SEL_R2L                 (0x2 << 14)
+#define RT5640_IF1_DAC_SEL_SWAP                        (0x3 << 14)
+#define RT5640_IF1_ADC_SEL_MASK                        (0x3 << 12)
+#define RT5640_IF1_ADC_SEL_SFT                 12
+#define RT5640_IF1_ADC_SEL_NOR                 (0x0 << 12)
+#define RT5640_IF1_ADC_SEL_L2R                 (0x1 << 12)
+#define RT5640_IF1_ADC_SEL_R2L                 (0x2 << 12)
+#define RT5640_IF1_ADC_SEL_SWAP                        (0x3 << 12)
+#define RT5640_IF2_DAC_SEL_MASK                        (0x3 << 10)
+#define RT5640_IF2_DAC_SEL_SFT                 10
+#define RT5640_IF2_DAC_SEL_NOR                 (0x0 << 10)
+#define RT5640_IF2_DAC_SEL_L2R                 (0x1 << 10)
+#define RT5640_IF2_DAC_SEL_R2L                 (0x2 << 10)
+#define RT5640_IF2_DAC_SEL_SWAP                        (0x3 << 10)
+#define RT5640_IF2_ADC_SEL_MASK                        (0x3 << 8)
+#define RT5640_IF2_ADC_SEL_SFT                 8
+#define RT5640_IF2_ADC_SEL_NOR                 (0x0 << 8)
+#define RT5640_IF2_ADC_SEL_L2R                 (0x1 << 8)
+#define RT5640_IF2_ADC_SEL_R2L                 (0x2 << 8)
+#define RT5640_IF2_ADC_SEL_SWAP                        (0x3 << 8)
+#define RT5640_IF3_DAC_SEL_MASK                        (0x3 << 6)
+#define RT5640_IF3_DAC_SEL_SFT                 6
+#define RT5640_IF3_DAC_SEL_NOR                 (0x0 << 6)
+#define RT5640_IF3_DAC_SEL_L2R                 (0x1 << 6)
+#define RT5640_IF3_DAC_SEL_R2L                 (0x2 << 6)
+#define RT5640_IF3_DAC_SEL_SWAP                        (0x3 << 6)
+#define RT5640_IF3_ADC_SEL_MASK                        (0x3 << 4)
+#define RT5640_IF3_ADC_SEL_SFT                 4
+#define RT5640_IF3_ADC_SEL_NOR                 (0x0 << 4)
+#define RT5640_IF3_ADC_SEL_L2R                 (0x1 << 4)
+#define RT5640_IF3_ADC_SEL_R2L                 (0x2 << 4)
+#define RT5640_IF3_ADC_SEL_SWAP                        (0x3 << 4)
+
+/* REC Left Mixer Control 1 (0x3b) */
+#define RT5640_G_HP_L_RM_L_MASK                        (0x7 << 13)
+#define RT5640_G_HP_L_RM_L_SFT                 13
+#define RT5640_G_IN_L_RM_L_MASK                        (0x7 << 10)
+#define RT5640_G_IN_L_RM_L_SFT                 10
+#define RT5640_G_BST4_RM_L_MASK                        (0x7 << 7)
+#define RT5640_G_BST4_RM_L_SFT                 7
+#define RT5640_G_BST3_RM_L_MASK                        (0x7 << 4)
+#define RT5640_G_BST3_RM_L_SFT                 4
+#define RT5640_G_BST2_RM_L_MASK                        (0x7 << 1)
+#define RT5640_G_BST2_RM_L_SFT                 1
+
+/* REC Left Mixer Control 2 (0x3c) */
+#define RT5640_G_BST1_RM_L_MASK                        (0x7 << 13)
+#define RT5640_G_BST1_RM_L_SFT                 13
+#define RT5640_G_OM_L_RM_L_MASK                        (0x7 << 10)
+#define RT5640_G_OM_L_RM_L_SFT                 10
+#define RT5640_M_HP_L_RM_L                     (0x1 << 6)
+#define RT5640_M_HP_L_RM_L_SFT                 6
+#define RT5640_M_IN_L_RM_L                     (0x1 << 5)
+#define RT5640_M_IN_L_RM_L_SFT                 5
+#define RT5640_M_BST4_RM_L                     (0x1 << 4)
+#define RT5640_M_BST4_RM_L_SFT                 4
+#define RT5640_M_BST3_RM_L                     (0x1 << 3)
+#define RT5640_M_BST3_RM_L_SFT                 3
+#define RT5640_M_BST2_RM_L                     (0x1 << 2)
+#define RT5640_M_BST2_RM_L_SFT                 2
+#define RT5640_M_BST1_RM_L                     (0x1 << 1)
+#define RT5640_M_BST1_RM_L_SFT                 1
+#define RT5640_M_OM_L_RM_L                     (0x1)
+#define RT5640_M_OM_L_RM_L_SFT                 0
+
+/* REC Right Mixer Control 1 (0x3d) */
+#define RT5640_G_HP_R_RM_R_MASK                        (0x7 << 13)
+#define RT5640_G_HP_R_RM_R_SFT                 13
+#define RT5640_G_IN_R_RM_R_MASK                        (0x7 << 10)
+#define RT5640_G_IN_R_RM_R_SFT                 10
+#define RT5640_G_BST4_RM_R_MASK                        (0x7 << 7)
+#define RT5640_G_BST4_RM_R_SFT                 7
+#define RT5640_G_BST3_RM_R_MASK                        (0x7 << 4)
+#define RT5640_G_BST3_RM_R_SFT                 4
+#define RT5640_G_BST2_RM_R_MASK                        (0x7 << 1)
+#define RT5640_G_BST2_RM_R_SFT                 1
+
+/* REC Right Mixer Control 2 (0x3e) */
+#define RT5640_G_BST1_RM_R_MASK                        (0x7 << 13)
+#define RT5640_G_BST1_RM_R_SFT                 13
+#define RT5640_G_OM_R_RM_R_MASK                        (0x7 << 10)
+#define RT5640_G_OM_R_RM_R_SFT                 10
+#define RT5640_M_HP_R_RM_R                     (0x1 << 6)
+#define RT5640_M_HP_R_RM_R_SFT                 6
+#define RT5640_M_IN_R_RM_R                     (0x1 << 5)
+#define RT5640_M_IN_R_RM_R_SFT                 5
+#define RT5640_M_BST4_RM_R                     (0x1 << 4)
+#define RT5640_M_BST4_RM_R_SFT                 4
+#define RT5640_M_BST3_RM_R                     (0x1 << 3)
+#define RT5640_M_BST3_RM_R_SFT                 3
+#define RT5640_M_BST2_RM_R                     (0x1 << 2)
+#define RT5640_M_BST2_RM_R_SFT                 2
+#define RT5640_M_BST1_RM_R                     (0x1 << 1)
+#define RT5640_M_BST1_RM_R_SFT                 1
+#define RT5640_M_OM_R_RM_R                     (0x1)
+#define RT5640_M_OM_R_RM_R_SFT                 0
+
+/* HPMIX Control (0x45) */
+#define RT5640_M_DAC2_HM                       (0x1 << 15)
+#define RT5640_M_DAC2_HM_SFT                   15
+#define RT5640_M_DAC1_HM                       (0x1 << 14)
+#define RT5640_M_DAC1_HM_SFT                   14
+#define RT5640_M_HPVOL_HM                      (0x1 << 13)
+#define RT5640_M_HPVOL_HM_SFT                  13
+#define RT5640_G_HPOMIX_MASK                   (0x1 << 12)
+#define RT5640_G_HPOMIX_SFT                    12
+
+/* SPK Left Mixer Control (0x46) */
+#define RT5640_G_RM_L_SM_L_MASK                        (0x3 << 14)
+#define RT5640_G_RM_L_SM_L_SFT                 14
+#define RT5640_G_IN_L_SM_L_MASK                        (0x3 << 12)
+#define RT5640_G_IN_L_SM_L_SFT                 12
+#define RT5640_G_DAC_L1_SM_L_MASK              (0x3 << 10)
+#define RT5640_G_DAC_L1_SM_L_SFT               10
+#define RT5640_G_DAC_L2_SM_L_MASK              (0x3 << 8)
+#define RT5640_G_DAC_L2_SM_L_SFT               8
+#define RT5640_G_OM_L_SM_L_MASK                        (0x3 << 6)
+#define RT5640_G_OM_L_SM_L_SFT                 6
+#define RT5640_M_RM_L_SM_L                     (0x1 << 5)
+#define RT5640_M_RM_L_SM_L_SFT                 5
+#define RT5640_M_IN_L_SM_L                     (0x1 << 4)
+#define RT5640_M_IN_L_SM_L_SFT                 4
+#define RT5640_M_DAC_L1_SM_L                   (0x1 << 3)
+#define RT5640_M_DAC_L1_SM_L_SFT               3
+#define RT5640_M_DAC_L2_SM_L                   (0x1 << 2)
+#define RT5640_M_DAC_L2_SM_L_SFT               2
+#define RT5640_M_OM_L_SM_L                     (0x1 << 1)
+#define RT5640_M_OM_L_SM_L_SFT         1
+
+/* SPK Right Mixer Control (0x47) */
+#define RT5640_G_RM_R_SM_R_MASK                        (0x3 << 14)
+#define RT5640_G_RM_R_SM_R_SFT                 14
+#define RT5640_G_IN_R_SM_R_MASK                        (0x3 << 12)
+#define RT5640_G_IN_R_SM_R_SFT                 12
+#define RT5640_G_DAC_R1_SM_R_MASK              (0x3 << 10)
+#define RT5640_G_DAC_R1_SM_R_SFT               10
+#define RT5640_G_DAC_R2_SM_R_MASK              (0x3 << 8)
+#define RT5640_G_DAC_R2_SM_R_SFT               8
+#define RT5640_G_OM_R_SM_R_MASK                        (0x3 << 6)
+#define RT5640_G_OM_R_SM_R_SFT                 6
+#define RT5640_M_RM_R_SM_R                     (0x1 << 5)
+#define RT5640_M_RM_R_SM_R_SFT                 5
+#define RT5640_M_IN_R_SM_R                     (0x1 << 4)
+#define RT5640_M_IN_R_SM_R_SFT                 4
+#define RT5640_M_DAC_R1_SM_R                   (0x1 << 3)
+#define RT5640_M_DAC_R1_SM_R_SFT               3
+#define RT5640_M_DAC_R2_SM_R                   (0x1 << 2)
+#define RT5640_M_DAC_R2_SM_R_SFT               2
+#define RT5640_M_OM_R_SM_R                     (0x1 << 1)
+#define RT5640_M_OM_R_SM_R_SFT                 1
+
+/* SPOLMIX Control (0x48) */
+#define RT5640_M_DAC_R1_SPM_L                  (0x1 << 15)
+#define RT5640_M_DAC_R1_SPM_L_SFT              15
+#define RT5640_M_DAC_L1_SPM_L                  (0x1 << 14)
+#define RT5640_M_DAC_L1_SPM_L_SFT              14
+#define RT5640_M_SV_R_SPM_L                    (0x1 << 13)
+#define RT5640_M_SV_R_SPM_L_SFT                        13
+#define RT5640_M_SV_L_SPM_L                    (0x1 << 12)
+#define RT5640_M_SV_L_SPM_L_SFT                        12
+#define RT5640_M_BST1_SPM_L                    (0x1 << 11)
+#define RT5640_M_BST1_SPM_L_SFT                        11
+
+/* SPORMIX Control (0x49) */
+#define RT5640_M_DAC_R1_SPM_R                  (0x1 << 13)
+#define RT5640_M_DAC_R1_SPM_R_SFT              13
+#define RT5640_M_SV_R_SPM_R                    (0x1 << 12)
+#define RT5640_M_SV_R_SPM_R_SFT                        12
+#define RT5640_M_BST1_SPM_R                    (0x1 << 11)
+#define RT5640_M_BST1_SPM_R_SFT                        11
+
+/* SPOLMIX / SPORMIX Ratio Control (0x4a) */
+#define RT5640_SPO_CLSD_RATIO_MASK             (0x7)
+#define RT5640_SPO_CLSD_RATIO_SFT              0
+
+/* Mono Output Mixer Control (0x4c) */
+#define RT5640_M_DAC_R2_MM                     (0x1 << 15)
+#define RT5640_M_DAC_R2_MM_SFT                 15
+#define RT5640_M_DAC_L2_MM                     (0x1 << 14)
+#define RT5640_M_DAC_L2_MM_SFT                 14
+#define RT5640_M_OV_R_MM                       (0x1 << 13)
+#define RT5640_M_OV_R_MM_SFT                   13
+#define RT5640_M_OV_L_MM                       (0x1 << 12)
+#define RT5640_M_OV_L_MM_SFT                   12
+#define RT5640_M_BST1_MM                       (0x1 << 11)
+#define RT5640_M_BST1_MM_SFT                   11
+#define RT5640_G_MONOMIX_MASK                  (0x1 << 10)
+#define RT5640_G_MONOMIX_SFT                   10
+
+/* Output Left Mixer Control 1 (0x4d) */
+#define RT5640_G_BST3_OM_L_MASK                        (0x7 << 13)
+#define RT5640_G_BST3_OM_L_SFT                 13
+#define RT5640_G_BST2_OM_L_MASK                        (0x7 << 10)
+#define RT5640_G_BST2_OM_L_SFT                 10
+#define RT5640_G_BST1_OM_L_MASK                        (0x7 << 7)
+#define RT5640_G_BST1_OM_L_SFT                 7
+#define RT5640_G_IN_L_OM_L_MASK                        (0x7 << 4)
+#define RT5640_G_IN_L_OM_L_SFT                 4
+#define RT5640_G_RM_L_OM_L_MASK                        (0x7 << 1)
+#define RT5640_G_RM_L_OM_L_SFT                 1
+
+/* Output Left Mixer Control 2 (0x4e) */
+#define RT5640_G_DAC_R2_OM_L_MASK              (0x7 << 13)
+#define RT5640_G_DAC_R2_OM_L_SFT               13
+#define RT5640_G_DAC_L2_OM_L_MASK              (0x7 << 10)
+#define RT5640_G_DAC_L2_OM_L_SFT               10
+#define RT5640_G_DAC_L1_OM_L_MASK              (0x7 << 7)
+#define RT5640_G_DAC_L1_OM_L_SFT               7
+
+/* Output Left Mixer Control 3 (0x4f) */
+#define RT5640_M_SM_L_OM_L                     (0x1 << 8)
+#define RT5640_M_SM_L_OM_L_SFT                 8
+#define RT5640_M_BST3_OM_L                     (0x1 << 7)
+#define RT5640_M_BST3_OM_L_SFT                 7
+#define RT5640_M_BST2_OM_L                     (0x1 << 6)
+#define RT5640_M_BST2_OM_L_SFT                 6
+#define RT5640_M_BST1_OM_L                     (0x1 << 5)
+#define RT5640_M_BST1_OM_L_SFT                 5
+#define RT5640_M_IN_L_OM_L                     (0x1 << 4)
+#define RT5640_M_IN_L_OM_L_SFT                 4
+#define RT5640_M_RM_L_OM_L                     (0x1 << 3)
+#define RT5640_M_RM_L_OM_L_SFT                 3
+#define RT5640_M_DAC_R2_OM_L                   (0x1 << 2)
+#define RT5640_M_DAC_R2_OM_L_SFT               2
+#define RT5640_M_DAC_L2_OM_L                   (0x1 << 1)
+#define RT5640_M_DAC_L2_OM_L_SFT               1
+#define RT5640_M_DAC_L1_OM_L                   (0x1)
+#define RT5640_M_DAC_L1_OM_L_SFT               0
+
+/* Output Right Mixer Control 1 (0x50) */
+#define RT5640_G_BST4_OM_R_MASK                        (0x7 << 13)
+#define RT5640_G_BST4_OM_R_SFT                 13
+#define RT5640_G_BST2_OM_R_MASK                        (0x7 << 10)
+#define RT5640_G_BST2_OM_R_SFT                 10
+#define RT5640_G_BST1_OM_R_MASK                        (0x7 << 7)
+#define RT5640_G_BST1_OM_R_SFT                 7
+#define RT5640_G_IN_R_OM_R_MASK                        (0x7 << 4)
+#define RT5640_G_IN_R_OM_R_SFT                 4
+#define RT5640_G_RM_R_OM_R_MASK                        (0x7 << 1)
+#define RT5640_G_RM_R_OM_R_SFT                 1
+
+/* Output Right Mixer Control 2 (0x51) */
+#define RT5640_G_DAC_L2_OM_R_MASK              (0x7 << 13)
+#define RT5640_G_DAC_L2_OM_R_SFT               13
+#define RT5640_G_DAC_R2_OM_R_MASK              (0x7 << 10)
+#define RT5640_G_DAC_R2_OM_R_SFT               10
+#define RT5640_G_DAC_R1_OM_R_MASK              (0x7 << 7)
+#define RT5640_G_DAC_R1_OM_R_SFT               7
+
+/* Output Right Mixer Control 3 (0x52) */
+#define RT5640_M_SM_L_OM_R                     (0x1 << 8)
+#define RT5640_M_SM_L_OM_R_SFT                 8
+#define RT5640_M_BST4_OM_R                     (0x1 << 7)
+#define RT5640_M_BST4_OM_R_SFT                 7
+#define RT5640_M_BST2_OM_R                     (0x1 << 6)
+#define RT5640_M_BST2_OM_R_SFT                 6
+#define RT5640_M_BST1_OM_R                     (0x1 << 5)
+#define RT5640_M_BST1_OM_R_SFT                 5
+#define RT5640_M_IN_R_OM_R                     (0x1 << 4)
+#define RT5640_M_IN_R_OM_R_SFT                 4
+#define RT5640_M_RM_R_OM_R                     (0x1 << 3)
+#define RT5640_M_RM_R_OM_R_SFT                 3
+#define RT5640_M_DAC_L2_OM_R                   (0x1 << 2)
+#define RT5640_M_DAC_L2_OM_R_SFT               2
+#define RT5640_M_DAC_R2_OM_R                   (0x1 << 1)
+#define RT5640_M_DAC_R2_OM_R_SFT               1
+#define RT5640_M_DAC_R1_OM_R                   (0x1)
+#define RT5640_M_DAC_R1_OM_R_SFT               0
+
+/* LOUT Mixer Control (0x53) */
+#define RT5640_M_DAC_L1_LM                     (0x1 << 15)
+#define RT5640_M_DAC_L1_LM_SFT                 15
+#define RT5640_M_DAC_R1_LM                     (0x1 << 14)
+#define RT5640_M_DAC_R1_LM_SFT                 14
+#define RT5640_M_OV_L_LM                       (0x1 << 13)
+#define RT5640_M_OV_L_LM_SFT                   13
+#define RT5640_M_OV_R_LM                       (0x1 << 12)
+#define RT5640_M_OV_R_LM_SFT                   12
+#define RT5640_G_LOUTMIX_MASK                  (0x1 << 11)
+#define RT5640_G_LOUTMIX_SFT                   11
+
+/* Power Management for Digital 1 (0x61) */
+#define RT5640_PWR_I2S1                                (0x1 << 15)
+#define RT5640_PWR_I2S1_BIT                    15
+#define RT5640_PWR_I2S2                                (0x1 << 14)
+#define RT5640_PWR_I2S2_BIT                    14
+#define RT5640_PWR_DAC_L1                      (0x1 << 12)
+#define RT5640_PWR_DAC_L1_BIT                  12
+#define RT5640_PWR_DAC_R1                      (0x1 << 11)
+#define RT5640_PWR_DAC_R1_BIT                  11
+#define RT5640_PWR_DAC_L2                      (0x1 << 7)
+#define RT5640_PWR_DAC_L2_BIT                  7
+#define RT5640_PWR_DAC_R2                      (0x1 << 6)
+#define RT5640_PWR_DAC_R2_BIT                  6
+#define RT5640_PWR_ADC_L                       (0x1 << 2)
+#define RT5640_PWR_ADC_L_BIT                   2
+#define RT5640_PWR_ADC_R                       (0x1 << 1)
+#define RT5640_PWR_ADC_R_BIT                   1
+#define RT5640_PWR_CLS_D                       (0x1)
+#define RT5640_PWR_CLS_D_BIT                   0
+
+/* Power Management for Digital 2 (0x62) */
+#define RT5640_PWR_ADC_SF                      (0x1 << 15)
+#define RT5640_PWR_ADC_SF_BIT                  15
+#define RT5640_PWR_ADC_MF_L                    (0x1 << 14)
+#define RT5640_PWR_ADC_MF_L_BIT                        14
+#define RT5640_PWR_ADC_MF_R                    (0x1 << 13)
+#define RT5640_PWR_ADC_MF_R_BIT                        13
+#define RT5640_PWR_I2S_DSP                     (0x1 << 12)
+#define RT5640_PWR_I2S_DSP_BIT                 12
+
+/* Power Management for Analog 1 (0x63) */
+#define RT5640_PWR_VREF1                       (0x1 << 15)
+#define RT5640_PWR_VREF1_BIT                   15
+#define RT5640_PWR_FV1                         (0x1 << 14)
+#define RT5640_PWR_FV1_BIT                     14
+#define RT5640_PWR_MB                          (0x1 << 13)
+#define RT5640_PWR_MB_BIT                      13
+#define RT5640_PWR_LM                          (0x1 << 12)
+#define RT5640_PWR_LM_BIT                      12
+#define RT5640_PWR_BG                          (0x1 << 11)
+#define RT5640_PWR_BG_BIT                      11
+#define RT5640_PWR_MM                          (0x1 << 10)
+#define RT5640_PWR_MM_BIT                      10
+#define RT5640_PWR_MA                          (0x1 << 8)
+#define RT5640_PWR_MA_BIT                      8
+#define RT5640_PWR_HP_L                                (0x1 << 7)
+#define RT5640_PWR_HP_L_BIT                    7
+#define RT5640_PWR_HP_R                                (0x1 << 6)
+#define RT5640_PWR_HP_R_BIT                    6
+#define RT5640_PWR_HA                          (0x1 << 5)
+#define RT5640_PWR_HA_BIT                      5
+#define RT5640_PWR_VREF2                       (0x1 << 4)
+#define RT5640_PWR_VREF2_BIT                   4
+#define RT5640_PWR_FV2                         (0x1 << 3)
+#define RT5640_PWR_FV2_BIT                     3
+#define RT5640_PWR_LDO2                                (0x1 << 2)
+#define RT5640_PWR_LDO2_BIT                    2
+
+/* Power Management for Analog 2 (0x64) */
+#define RT5640_PWR_BST1                                (0x1 << 15)
+#define RT5640_PWR_BST1_BIT                    15
+#define RT5640_PWR_BST2                                (0x1 << 14)
+#define RT5640_PWR_BST2_BIT                    14
+#define RT5640_PWR_BST3                                (0x1 << 13)
+#define RT5640_PWR_BST3_BIT                    13
+#define RT5640_PWR_BST4                                (0x1 << 12)
+#define RT5640_PWR_BST4_BIT                    12
+#define RT5640_PWR_MB1                         (0x1 << 11)
+#define RT5640_PWR_MB1_BIT                     11
+#define RT5640_PWR_PLL                         (0x1 << 9)
+#define RT5640_PWR_PLL_BIT                     9
+
+/* Power Management for Mixer (0x65) */
+#define RT5640_PWR_OM_L                                (0x1 << 15)
+#define RT5640_PWR_OM_L_BIT                    15
+#define RT5640_PWR_OM_R                                (0x1 << 14)
+#define RT5640_PWR_OM_R_BIT                    14
+#define RT5640_PWR_SM_L                                (0x1 << 13)
+#define RT5640_PWR_SM_L_BIT                    13
+#define RT5640_PWR_SM_R                                (0x1 << 12)
+#define RT5640_PWR_SM_R_BIT                    12
+#define RT5640_PWR_RM_L                                (0x1 << 11)
+#define RT5640_PWR_RM_L_BIT                    11
+#define RT5640_PWR_RM_R                                (0x1 << 10)
+#define RT5640_PWR_RM_R_BIT                    10
+
+/* Power Management for Volume (0x66) */
+#define RT5640_PWR_SV_L                                (0x1 << 15)
+#define RT5640_PWR_SV_L_BIT                    15
+#define RT5640_PWR_SV_R                                (0x1 << 14)
+#define RT5640_PWR_SV_R_BIT                    14
+#define RT5640_PWR_OV_L                                (0x1 << 13)
+#define RT5640_PWR_OV_L_BIT                    13
+#define RT5640_PWR_OV_R                                (0x1 << 12)
+#define RT5640_PWR_OV_R_BIT                    12
+#define RT5640_PWR_HV_L                                (0x1 << 11)
+#define RT5640_PWR_HV_L_BIT                    11
+#define RT5640_PWR_HV_R                                (0x1 << 10)
+#define RT5640_PWR_HV_R_BIT                    10
+#define RT5640_PWR_IN_L                                (0x1 << 9)
+#define RT5640_PWR_IN_L_BIT                    9
+#define RT5640_PWR_IN_R                                (0x1 << 8)
+#define RT5640_PWR_IN_R_BIT                    8
+
+/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71 0x72) */
+#define RT5640_I2S_MS_MASK                     (0x1 << 15)
+#define RT5640_I2S_MS_SFT                      15
+#define RT5640_I2S_MS_M                                (0x0 << 15)
+#define RT5640_I2S_MS_S                                (0x1 << 15)
+#define RT5640_I2S_IF_MASK                     (0x7 << 12)
+#define RT5640_I2S_IF_SFT                      12
+#define RT5640_I2S_O_CP_MASK                   (0x3 << 10)
+#define RT5640_I2S_O_CP_SFT                    10
+#define RT5640_I2S_O_CP_OFF                    (0x0 << 10)
+#define RT5640_I2S_O_CP_U_LAW                  (0x1 << 10)
+#define RT5640_I2S_O_CP_A_LAW                  (0x2 << 10)
+#define RT5640_I2S_I_CP_MASK                   (0x3 << 8)
+#define RT5640_I2S_I_CP_SFT                    8
+#define RT5640_I2S_I_CP_OFF                    (0x0 << 8)
+#define RT5640_I2S_I_CP_U_LAW                  (0x1 << 8)
+#define RT5640_I2S_I_CP_A_LAW                  (0x2 << 8)
+#define RT5640_I2S_BP_MASK                     (0x1 << 7)
+#define RT5640_I2S_BP_SFT                      7
+#define RT5640_I2S_BP_NOR                      (0x0 << 7)
+#define RT5640_I2S_BP_INV                      (0x1 << 7)
+#define RT5640_I2S_DL_MASK                     (0x3 << 2)
+#define RT5640_I2S_DL_SFT                      2
+#define RT5640_I2S_DL_16                       (0x0 << 2)
+#define RT5640_I2S_DL_20                       (0x1 << 2)
+#define RT5640_I2S_DL_24                       (0x2 << 2)
+#define RT5640_I2S_DL_8                                (0x3 << 2)
+#define RT5640_I2S_DF_MASK                     (0x3)
+#define RT5640_I2S_DF_SFT                      0
+#define RT5640_I2S_DF_I2S                      (0x0)
+#define RT5640_I2S_DF_LEFT                     (0x1)
+#define RT5640_I2S_DF_PCM_A                    (0x2)
+#define RT5640_I2S_DF_PCM_B                    (0x3)
+
+/* I2S2 Audio Serial Data Port Control (0x71) */
+#define RT5640_I2S2_SDI_MASK                   (0x1 << 6)
+#define RT5640_I2S2_SDI_SFT                    6
+#define RT5640_I2S2_SDI_I2S1                   (0x0 << 6)
+#define RT5640_I2S2_SDI_I2S2                   (0x1 << 6)
+
+/* ADC/DAC Clock Control 1 (0x73) */
+#define RT5640_I2S_BCLK_MS1_MASK               (0x1 << 15)
+#define RT5640_I2S_BCLK_MS1_SFT                        15
+#define RT5640_I2S_BCLK_MS1_32                 (0x0 << 15)
+#define RT5640_I2S_BCLK_MS1_64                 (0x1 << 15)
+#define RT5640_I2S_PD1_MASK                    (0x7 << 12)
+#define RT5640_I2S_PD1_SFT                     12
+#define RT5640_I2S_PD1_1                       (0x0 << 12)
+#define RT5640_I2S_PD1_2                       (0x1 << 12)
+#define RT5640_I2S_PD1_3                       (0x2 << 12)
+#define RT5640_I2S_PD1_4                       (0x3 << 12)
+#define RT5640_I2S_PD1_6                       (0x4 << 12)
+#define RT5640_I2S_PD1_8                       (0x5 << 12)
+#define RT5640_I2S_PD1_12                      (0x6 << 12)
+#define RT5640_I2S_PD1_16                      (0x7 << 12)
+#define RT5640_I2S_BCLK_MS2_MASK               (0x1 << 11)
+#define RT5640_I2S_BCLK_MS2_SFT                        11
+#define RT5640_I2S_BCLK_MS2_32                 (0x0 << 11)
+#define RT5640_I2S_BCLK_MS2_64                 (0x1 << 11)
+#define RT5640_I2S_PD2_MASK                    (0x7 << 8)
+#define RT5640_I2S_PD2_SFT                     8
+#define RT5640_I2S_PD2_1                       (0x0 << 8)
+#define RT5640_I2S_PD2_2                       (0x1 << 8)
+#define RT5640_I2S_PD2_3                       (0x2 << 8)
+#define RT5640_I2S_PD2_4                       (0x3 << 8)
+#define RT5640_I2S_PD2_6                       (0x4 << 8)
+#define RT5640_I2S_PD2_8                       (0x5 << 8)
+#define RT5640_I2S_PD2_12                      (0x6 << 8)
+#define RT5640_I2S_PD2_16                      (0x7 << 8)
+#define RT5640_I2S_BCLK_MS3_MASK               (0x1 << 7)
+#define RT5640_I2S_BCLK_MS3_SFT                        7
+#define RT5640_I2S_BCLK_MS3_32                 (0x0 << 7)
+#define RT5640_I2S_BCLK_MS3_64                 (0x1 << 7)
+#define RT5640_I2S_PD3_MASK                    (0x7 << 4)
+#define RT5640_I2S_PD3_SFT                     4
+#define RT5640_I2S_PD3_1                       (0x0 << 4)
+#define RT5640_I2S_PD3_2                       (0x1 << 4)
+#define RT5640_I2S_PD3_3                       (0x2 << 4)
+#define RT5640_I2S_PD3_4                       (0x3 << 4)
+#define RT5640_I2S_PD3_6                       (0x4 << 4)
+#define RT5640_I2S_PD3_8                       (0x5 << 4)
+#define RT5640_I2S_PD3_12                      (0x6 << 4)
+#define RT5640_I2S_PD3_16                      (0x7 << 4)
+#define RT5640_DAC_OSR_MASK                    (0x3 << 2)
+#define RT5640_DAC_OSR_SFT                     2
+#define RT5640_DAC_OSR_128                     (0x0 << 2)
+#define RT5640_DAC_OSR_64                      (0x1 << 2)
+#define RT5640_DAC_OSR_32                      (0x2 << 2)
+#define RT5640_DAC_OSR_16                      (0x3 << 2)
+#define RT5640_ADC_OSR_MASK                    (0x3)
+#define RT5640_ADC_OSR_SFT                     0
+#define RT5640_ADC_OSR_128                     (0x0)
+#define RT5640_ADC_OSR_64                      (0x1)
+#define RT5640_ADC_OSR_32                      (0x2)
+#define RT5640_ADC_OSR_16                      (0x3)
+
+/* ADC/DAC Clock Control 2 (0x74) */
+#define RT5640_DAC_L_OSR_MASK                  (0x3 << 14)
+#define RT5640_DAC_L_OSR_SFT                   14
+#define RT5640_DAC_L_OSR_128                   (0x0 << 14)
+#define RT5640_DAC_L_OSR_64                    (0x1 << 14)
+#define RT5640_DAC_L_OSR_32                    (0x2 << 14)
+#define RT5640_DAC_L_OSR_16                    (0x3 << 14)
+#define RT5640_ADC_R_OSR_MASK                  (0x3 << 12)
+#define RT5640_ADC_R_OSR_SFT                   12
+#define RT5640_ADC_R_OSR_128                   (0x0 << 12)
+#define RT5640_ADC_R_OSR_64                    (0x1 << 12)
+#define RT5640_ADC_R_OSR_32                    (0x2 << 12)
+#define RT5640_ADC_R_OSR_16                    (0x3 << 12)
+#define RT5640_DAHPF_EN                                (0x1 << 11)
+#define RT5640_DAHPF_EN_SFT                    11
+#define RT5640_ADHPF_EN                                (0x1 << 10)
+#define RT5640_ADHPF_EN_SFT                    10
+
+/* Digital Microphone Control (0x75) */
+#define RT5640_DMIC_1_EN_MASK                  (0x1 << 15)
+#define RT5640_DMIC_1_EN_SFT                   15
+#define RT5640_DMIC_1_DIS                      (0x0 << 15)
+#define RT5640_DMIC_1_EN                       (0x1 << 15)
+#define RT5640_DMIC_2_EN_MASK                  (0x1 << 14)
+#define RT5640_DMIC_2_EN_SFT                   14
+#define RT5640_DMIC_2_DIS                      (0x0 << 14)
+#define RT5640_DMIC_2_EN                       (0x1 << 14)
+#define RT5640_DMIC_1L_LH_MASK                 (0x1 << 13)
+#define RT5640_DMIC_1L_LH_SFT                  13
+#define RT5640_DMIC_1L_LH_FALLING              (0x0 << 13)
+#define RT5640_DMIC_1L_LH_RISING               (0x1 << 13)
+#define RT5640_DMIC_1R_LH_MASK                 (0x1 << 12)
+#define RT5640_DMIC_1R_LH_SFT                  12
+#define RT5640_DMIC_1R_LH_FALLING              (0x0 << 12)
+#define RT5640_DMIC_1R_LH_RISING               (0x1 << 12)
+#define RT5640_DMIC_1_DP_MASK                  (0x1 << 11)
+#define RT5640_DMIC_1_DP_SFT                   11
+#define RT5640_DMIC_1_DP_GPIO3                 (0x0 << 11)
+#define RT5640_DMIC_1_DP_IN1P                  (0x1 << 11)
+#define RT5640_DMIC_2_DP_MASK                  (0x1 << 10)
+#define RT5640_DMIC_2_DP_SFT                   10
+#define RT5640_DMIC_2_DP_GPIO4                 (0x0 << 10)
+#define RT5640_DMIC_2_DP_IN1N                  (0x1 << 10)
+#define RT5640_DMIC_2L_LH_MASK                 (0x1 << 9)
+#define RT5640_DMIC_2L_LH_SFT                  9
+#define RT5640_DMIC_2L_LH_FALLING              (0x0 << 9)
+#define RT5640_DMIC_2L_LH_RISING               (0x1 << 9)
+#define RT5640_DMIC_2R_LH_MASK                 (0x1 << 8)
+#define RT5640_DMIC_2R_LH_SFT                  8
+#define RT5640_DMIC_2R_LH_FALLING              (0x0 << 8)
+#define RT5640_DMIC_2R_LH_RISING               (0x1 << 8)
+#define RT5640_DMIC_CLK_MASK                   (0x7 << 5)
+#define RT5640_DMIC_CLK_SFT                    5
+
+/* Global Clock Control (0x80) */
+#define RT5640_SCLK_SRC_MASK                   (0x3 << 14)
+#define RT5640_SCLK_SRC_SFT                    14
+#define RT5640_SCLK_SRC_MCLK                   (0x0 << 14)
+#define RT5640_SCLK_SRC_PLL1                   (0x1 << 14)
+#define RT5640_SCLK_SRC_PLL1T                  (0x2 << 14)
+#define RT5640_SCLK_SRC_RCCLK                  (0x3 << 14) /* 15MHz */
+#define RT5640_PLL1_SRC_MASK                   (0x3 << 12)
+#define RT5640_PLL1_SRC_SFT                    12
+#define RT5640_PLL1_SRC_MCLK                   (0x0 << 12)
+#define RT5640_PLL1_SRC_BCLK1                  (0x1 << 12)
+#define RT5640_PLL1_SRC_BCLK2                  (0x2 << 12)
+#define RT5640_PLL1_SRC_BCLK3                  (0x3 << 12)
+#define RT5640_PLL1_PD_MASK                    (0x1 << 3)
+#define RT5640_PLL1_PD_SFT                     3
+#define RT5640_PLL1_PD_1                       (0x0 << 3)
+#define RT5640_PLL1_PD_2                       (0x1 << 3)
+
+#define RT5640_PLL_INP_MAX                     40000000
+#define RT5640_PLL_INP_MIN                     256000
+/* PLL M/N/K Code Control 1 (0x81) */
+#define RT5640_PLL_N_MAX                       0x1ff
+#define RT5640_PLL_N_MASK                      (RT5640_PLL_N_MAX << 7)
+#define RT5640_PLL_N_SFT                       7
+#define RT5640_PLL_K_MAX                       0x1f
+#define RT5640_PLL_K_MASK                      (RT5640_PLL_K_MAX)
+#define RT5640_PLL_K_SFT                       0
+
+/* PLL M/N/K Code Control 2 (0x82) */
+#define RT5640_PLL_M_MAX                       0xf
+#define RT5640_PLL_M_MASK                      (RT5640_PLL_M_MAX << 12)
+#define RT5640_PLL_M_SFT                       12
+#define RT5640_PLL_M_BP                                (0x1 << 11)
+#define RT5640_PLL_M_BP_SFT                    11
+
+/* ASRC Control 1 (0x83) */
+#define RT5640_STO_T_MASK                      (0x1 << 15)
+#define RT5640_STO_T_SFT                       15
+#define RT5640_STO_T_SCLK                      (0x0 << 15)
+#define RT5640_STO_T_LRCK1                     (0x1 << 15)
+#define RT5640_M1_T_MASK                       (0x1 << 14)
+#define RT5640_M1_T_SFT                                14
+#define RT5640_M1_T_I2S2                       (0x0 << 14)
+#define RT5640_M1_T_I2S2_D3                    (0x1 << 14)
+#define RT5640_I2S2_F_MASK                     (0x1 << 12)
+#define RT5640_I2S2_F_SFT                      12
+#define RT5640_I2S2_F_I2S2_D2                  (0x0 << 12)
+#define RT5640_I2S2_F_I2S1_TCLK                        (0x1 << 12)
+#define RT5640_DMIC_1_M_MASK                   (0x1 << 9)
+#define RT5640_DMIC_1_M_SFT                    9
+#define RT5640_DMIC_1_M_NOR                    (0x0 << 9)
+#define RT5640_DMIC_1_M_ASYN                   (0x1 << 9)
+#define RT5640_DMIC_2_M_MASK                   (0x1 << 8)
+#define RT5640_DMIC_2_M_SFT                    8
+#define RT5640_DMIC_2_M_NOR                    (0x0 << 8)
+#define RT5640_DMIC_2_M_ASYN                   (0x1 << 8)
+
+/* ASRC Control 2 (0x84) */
+#define RT5640_MDA_L_M_MASK                    (0x1 << 15)
+#define RT5640_MDA_L_M_SFT                     15
+#define RT5640_MDA_L_M_NOR                     (0x0 << 15)
+#define RT5640_MDA_L_M_ASYN                    (0x1 << 15)
+#define RT5640_MDA_R_M_MASK                    (0x1 << 14)
+#define RT5640_MDA_R_M_SFT                     14
+#define RT5640_MDA_R_M_NOR                     (0x0 << 14)
+#define RT5640_MDA_R_M_ASYN                    (0x1 << 14)
+#define RT5640_MAD_L_M_MASK                    (0x1 << 13)
+#define RT5640_MAD_L_M_SFT                     13
+#define RT5640_MAD_L_M_NOR                     (0x0 << 13)
+#define RT5640_MAD_L_M_ASYN                    (0x1 << 13)
+#define RT5640_MAD_R_M_MASK                    (0x1 << 12)
+#define RT5640_MAD_R_M_SFT                     12
+#define RT5640_MAD_R_M_NOR                     (0x0 << 12)
+#define RT5640_MAD_R_M_ASYN                    (0x1 << 12)
+#define RT5640_ADC_M_MASK                      (0x1 << 11)
+#define RT5640_ADC_M_SFT                       11
+#define RT5640_ADC_M_NOR                       (0x0 << 11)
+#define RT5640_ADC_M_ASYN                      (0x1 << 11)
+#define RT5640_STO_DAC_M_MASK                  (0x1 << 5)
+#define RT5640_STO_DAC_M_SFT                   5
+#define RT5640_STO_DAC_M_NOR                   (0x0 << 5)
+#define RT5640_STO_DAC_M_ASYN                  (0x1 << 5)
+#define RT5640_I2S1_R_D_MASK                   (0x1 << 4)
+#define RT5640_I2S1_R_D_SFT                    4
+#define RT5640_I2S1_R_D_DIS                    (0x0 << 4)
+#define RT5640_I2S1_R_D_EN                     (0x1 << 4)
+#define RT5640_I2S2_R_D_MASK                   (0x1 << 3)
+#define RT5640_I2S2_R_D_SFT                    3
+#define RT5640_I2S2_R_D_DIS                    (0x0 << 3)
+#define RT5640_I2S2_R_D_EN                     (0x1 << 3)
+#define RT5640_PRE_SCLK_MASK                   (0x3)
+#define RT5640_PRE_SCLK_SFT                    0
+#define RT5640_PRE_SCLK_512                    (0x0)
+#define RT5640_PRE_SCLK_1024                   (0x1)
+#define RT5640_PRE_SCLK_2048                   (0x2)
+
+/* ASRC Control 3 (0x85) */
+#define RT5640_I2S1_RATE_MASK                  (0xf << 12)
+#define RT5640_I2S1_RATE_SFT                   12
+#define RT5640_I2S2_RATE_MASK                  (0xf << 8)
+#define RT5640_I2S2_RATE_SFT                   8
+
+/* ASRC Control 4 (0x89) */
+#define RT5640_I2S1_PD_MASK                    (0x7 << 12)
+#define RT5640_I2S1_PD_SFT                     12
+#define RT5640_I2S2_PD_MASK                    (0x7 << 8)
+#define RT5640_I2S2_PD_SFT                     8
+
+/* HPOUT Over Current Detection (0x8b) */
+#define RT5640_HP_OVCD_MASK                    (0x1 << 10)
+#define RT5640_HP_OVCD_SFT                     10
+#define RT5640_HP_OVCD_DIS                     (0x0 << 10)
+#define RT5640_HP_OVCD_EN                      (0x1 << 10)
+#define RT5640_HP_OC_TH_MASK                   (0x3 << 8)
+#define RT5640_HP_OC_TH_SFT                    8
+#define RT5640_HP_OC_TH_90                     (0x0 << 8)
+#define RT5640_HP_OC_TH_105                    (0x1 << 8)
+#define RT5640_HP_OC_TH_120                    (0x2 << 8)
+#define RT5640_HP_OC_TH_135                    (0x3 << 8)
+
+/* Class D Over Current Control (0x8c) */
+#define RT5640_CLSD_OC_MASK                    (0x1 << 9)
+#define RT5640_CLSD_OC_SFT                     9
+#define RT5640_CLSD_OC_PU                      (0x0 << 9)
+#define RT5640_CLSD_OC_PD                      (0x1 << 9)
+#define RT5640_AUTO_PD_MASK                    (0x1 << 8)
+#define RT5640_AUTO_PD_SFT                     8
+#define RT5640_AUTO_PD_DIS                     (0x0 << 8)
+#define RT5640_AUTO_PD_EN                      (0x1 << 8)
+#define RT5640_CLSD_OC_TH_MASK                 (0x3f)
+#define RT5640_CLSD_OC_TH_SFT                  0
+
+/* Class D Output Control (0x8d) */
+#define RT5640_CLSD_RATIO_MASK                 (0xf << 12)
+#define RT5640_CLSD_RATIO_SFT                  12
+#define RT5640_CLSD_OM_MASK                    (0x1 << 11)
+#define RT5640_CLSD_OM_SFT                     11
+#define RT5640_CLSD_OM_MONO                    (0x0 << 11)
+#define RT5640_CLSD_OM_STO                     (0x1 << 11)
+#define RT5640_CLSD_SCH_MASK                   (0x1 << 10)
+#define RT5640_CLSD_SCH_SFT                    10
+#define RT5640_CLSD_SCH_L                      (0x0 << 10)
+#define RT5640_CLSD_SCH_S                      (0x1 << 10)
+
+/* Depop Mode Control 1 (0x8e) */
+#define RT5640_SMT_TRIG_MASK                   (0x1 << 15)
+#define RT5640_SMT_TRIG_SFT                    15
+#define RT5640_SMT_TRIG_DIS                    (0x0 << 15)
+#define RT5640_SMT_TRIG_EN                     (0x1 << 15)
+#define RT5640_HP_L_SMT_MASK                   (0x1 << 9)
+#define RT5640_HP_L_SMT_SFT                    9
+#define RT5640_HP_L_SMT_DIS                    (0x0 << 9)
+#define RT5640_HP_L_SMT_EN                     (0x1 << 9)
+#define RT5640_HP_R_SMT_MASK                   (0x1 << 8)
+#define RT5640_HP_R_SMT_SFT                    8
+#define RT5640_HP_R_SMT_DIS                    (0x0 << 8)
+#define RT5640_HP_R_SMT_EN                     (0x1 << 8)
+#define RT5640_HP_CD_PD_MASK                   (0x1 << 7)
+#define RT5640_HP_CD_PD_SFT                    7
+#define RT5640_HP_CD_PD_DIS                    (0x0 << 7)
+#define RT5640_HP_CD_PD_EN                     (0x1 << 7)
+#define RT5640_RSTN_MASK                       (0x1 << 6)
+#define RT5640_RSTN_SFT                                6
+#define RT5640_RSTN_DIS                                (0x0 << 6)
+#define RT5640_RSTN_EN                         (0x1 << 6)
+#define RT5640_RSTP_MASK                       (0x1 << 5)
+#define RT5640_RSTP_SFT                                5
+#define RT5640_RSTP_DIS                                (0x0 << 5)
+#define RT5640_RSTP_EN                         (0x1 << 5)
+#define RT5640_HP_CO_MASK                      (0x1 << 4)
+#define RT5640_HP_CO_SFT                       4
+#define RT5640_HP_CO_DIS                       (0x0 << 4)
+#define RT5640_HP_CO_EN                                (0x1 << 4)
+#define RT5640_HP_CP_MASK                      (0x1 << 3)
+#define RT5640_HP_CP_SFT                       3
+#define RT5640_HP_CP_PD                                (0x0 << 3)
+#define RT5640_HP_CP_PU                                (0x1 << 3)
+#define RT5640_HP_SG_MASK                      (0x1 << 2)
+#define RT5640_HP_SG_SFT                       2
+#define RT5640_HP_SG_DIS                       (0x0 << 2)
+#define RT5640_HP_SG_EN                                (0x1 << 2)
+#define RT5640_HP_DP_MASK                      (0x1 << 1)
+#define RT5640_HP_DP_SFT                       1
+#define RT5640_HP_DP_PD                                (0x0 << 1)
+#define RT5640_HP_DP_PU                                (0x1 << 1)
+#define RT5640_HP_CB_MASK                      (0x1)
+#define RT5640_HP_CB_SFT                       0
+#define RT5640_HP_CB_PD                                (0x0)
+#define RT5640_HP_CB_PU                                (0x1)
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5640_DEPOP_MASK                      (0x1 << 13)
+#define RT5640_DEPOP_SFT                       13
+#define RT5640_DEPOP_AUTO                      (0x0 << 13)
+#define RT5640_DEPOP_MAN                       (0x1 << 13)
+#define RT5640_RAMP_MASK                       (0x1 << 12)
+#define RT5640_RAMP_SFT                                12
+#define RT5640_RAMP_DIS                                (0x0 << 12)
+#define RT5640_RAMP_EN                         (0x1 << 12)
+#define RT5640_BPS_MASK                                (0x1 << 11)
+#define RT5640_BPS_SFT                         11
+#define RT5640_BPS_DIS                         (0x0 << 11)
+#define RT5640_BPS_EN                          (0x1 << 11)
+#define RT5640_FAST_UPDN_MASK                  (0x1 << 10)
+#define RT5640_FAST_UPDN_SFT                   10
+#define RT5640_FAST_UPDN_DIS                   (0x0 << 10)
+#define RT5640_FAST_UPDN_EN                    (0x1 << 10)
+#define RT5640_MRES_MASK                       (0x3 << 8)
+#define RT5640_MRES_SFT                                8
+#define RT5640_MRES_15MO                       (0x0 << 8)
+#define RT5640_MRES_25MO                       (0x1 << 8)
+#define RT5640_MRES_35MO                       (0x2 << 8)
+#define RT5640_MRES_45MO                       (0x3 << 8)
+#define RT5640_VLO_MASK                                (0x1 << 7)
+#define RT5640_VLO_SFT                         7
+#define RT5640_VLO_3V                          (0x0 << 7)
+#define RT5640_VLO_32V                         (0x1 << 7)
+#define RT5640_DIG_DP_MASK                     (0x1 << 6)
+#define RT5640_DIG_DP_SFT                      6
+#define RT5640_DIG_DP_DIS                      (0x0 << 6)
+#define RT5640_DIG_DP_EN                       (0x1 << 6)
+#define RT5640_DP_TH_MASK                      (0x3 << 4)
+#define RT5640_DP_TH_SFT                       4
+
+/* Depop Mode Control 3 (0x90) */
+#define RT5640_CP_SYS_MASK                     (0x7 << 12)
+#define RT5640_CP_SYS_SFT                      12
+#define RT5640_CP_FQ1_MASK                     (0x7 << 8)
+#define RT5640_CP_FQ1_SFT                      8
+#define RT5640_CP_FQ2_MASK                     (0x7 << 4)
+#define RT5640_CP_FQ2_SFT                      4
+#define RT5640_CP_FQ3_MASK                     (0x7)
+#define RT5640_CP_FQ3_SFT                      0
+
+/* HPOUT charge pump (0x91) */
+#define RT5640_OSW_L_MASK                      (0x1 << 11)
+#define RT5640_OSW_L_SFT                       11
+#define RT5640_OSW_L_DIS                       (0x0 << 11)
+#define RT5640_OSW_L_EN                                (0x1 << 11)
+#define RT5640_OSW_R_MASK                      (0x1 << 10)
+#define RT5640_OSW_R_SFT                       10
+#define RT5640_OSW_R_DIS                       (0x0 << 10)
+#define RT5640_OSW_R_EN                                (0x1 << 10)
+#define RT5640_PM_HP_MASK                      (0x3 << 8)
+#define RT5640_PM_HP_SFT                       8
+#define RT5640_PM_HP_LV                                (0x0 << 8)
+#define RT5640_PM_HP_MV                                (0x1 << 8)
+#define RT5640_PM_HP_HV                                (0x2 << 8)
+#define RT5640_IB_HP_MASK                      (0x3 << 6)
+#define RT5640_IB_HP_SFT                       6
+#define RT5640_IB_HP_125IL                     (0x0 << 6)
+#define RT5640_IB_HP_25IL                      (0x1 << 6)
+#define RT5640_IB_HP_5IL                       (0x2 << 6)
+#define RT5640_IB_HP_1IL                       (0x3 << 6)
+
+/* PV detection and SPK gain control (0x92) */
+#define RT5640_PVDD_DET_MASK                   (0x1 << 15)
+#define RT5640_PVDD_DET_SFT                    15
+#define RT5640_PVDD_DET_DIS                    (0x0 << 15)
+#define RT5640_PVDD_DET_EN                     (0x1 << 15)
+#define RT5640_SPK_AG_MASK                     (0x1 << 14)
+#define RT5640_SPK_AG_SFT                      14
+#define RT5640_SPK_AG_DIS                      (0x0 << 14)
+#define RT5640_SPK_AG_EN                       (0x1 << 14)
+
+/* Micbias Control (0x93) */
+#define RT5640_MIC1_BS_MASK                    (0x1 << 15)
+#define RT5640_MIC1_BS_SFT                     15
+#define RT5640_MIC1_BS_9AV                     (0x0 << 15)
+#define RT5640_MIC1_BS_75AV                    (0x1 << 15)
+#define RT5640_MIC2_BS_MASK                    (0x1 << 14)
+#define RT5640_MIC2_BS_SFT                     14
+#define RT5640_MIC2_BS_9AV                     (0x0 << 14)
+#define RT5640_MIC2_BS_75AV                    (0x1 << 14)
+#define RT5640_MIC1_CLK_MASK                   (0x1 << 13)
+#define RT5640_MIC1_CLK_SFT                    13
+#define RT5640_MIC1_CLK_DIS                    (0x0 << 13)
+#define RT5640_MIC1_CLK_EN                     (0x1 << 13)
+#define RT5640_MIC2_CLK_MASK                   (0x1 << 12)
+#define RT5640_MIC2_CLK_SFT                    12
+#define RT5640_MIC2_CLK_DIS                    (0x0 << 12)
+#define RT5640_MIC2_CLK_EN                     (0x1 << 12)
+#define RT5640_MIC1_OVCD_MASK                  (0x1 << 11)
+#define RT5640_MIC1_OVCD_SFT                   11
+#define RT5640_MIC1_OVCD_DIS                   (0x0 << 11)
+#define RT5640_MIC1_OVCD_EN                    (0x1 << 11)
+#define RT5640_MIC1_OVTH_MASK                  (0x3 << 9)
+#define RT5640_MIC1_OVTH_SFT                   9
+#define RT5640_MIC1_OVTH_600UA                 (0x0 << 9)
+#define RT5640_MIC1_OVTH_1500UA                        (0x1 << 9)
+#define RT5640_MIC1_OVTH_2000UA                        (0x2 << 9)
+#define RT5640_MIC2_OVCD_MASK                  (0x1 << 8)
+#define RT5640_MIC2_OVCD_SFT                   8
+#define RT5640_MIC2_OVCD_DIS                   (0x0 << 8)
+#define RT5640_MIC2_OVCD_EN                    (0x1 << 8)
+#define RT5640_MIC2_OVTH_MASK                  (0x3 << 6)
+#define RT5640_MIC2_OVTH_SFT                   6
+#define RT5640_MIC2_OVTH_600UA                 (0x0 << 6)
+#define RT5640_MIC2_OVTH_1500UA                        (0x1 << 6)
+#define RT5640_MIC2_OVTH_2000UA                        (0x2 << 6)
+#define RT5640_PWR_MB_MASK                     (0x1 << 5)
+#define RT5640_PWR_MB_SFT                      5
+#define RT5640_PWR_MB_PD                       (0x0 << 5)
+#define RT5640_PWR_MB_PU                       (0x1 << 5)
+#define RT5640_PWR_CLK25M_MASK                 (0x1 << 4)
+#define RT5640_PWR_CLK25M_SFT                  4
+#define RT5640_PWR_CLK25M_PD                   (0x0 << 4)
+#define RT5640_PWR_CLK25M_PU                   (0x1 << 4)
+
+/* EQ Control 1 (0xb0) */
+#define RT5640_EQ_SRC_MASK                     (0x1 << 15)
+#define RT5640_EQ_SRC_SFT                      15
+#define RT5640_EQ_SRC_DAC                      (0x0 << 15)
+#define RT5640_EQ_SRC_ADC                      (0x1 << 15)
+#define RT5640_EQ_UPD                          (0x1 << 14)
+#define RT5640_EQ_UPD_BIT                      14
+#define RT5640_EQ_CD_MASK                      (0x1 << 13)
+#define RT5640_EQ_CD_SFT                       13
+#define RT5640_EQ_CD_DIS                       (0x0 << 13)
+#define RT5640_EQ_CD_EN                                (0x1 << 13)
+#define RT5640_EQ_DITH_MASK                    (0x3 << 8)
+#define RT5640_EQ_DITH_SFT                     8
+#define RT5640_EQ_DITH_NOR                     (0x0 << 8)
+#define RT5640_EQ_DITH_LSB                     (0x1 << 8)
+#define RT5640_EQ_DITH_LSB_1                   (0x2 << 8)
+#define RT5640_EQ_DITH_LSB_2                   (0x3 << 8)
+
+/* EQ Control 2 (0xb1) */
+#define RT5640_EQ_HPF1_M_MASK                  (0x1 << 8)
+#define RT5640_EQ_HPF1_M_SFT                   8
+#define RT5640_EQ_HPF1_M_HI                    (0x0 << 8)
+#define RT5640_EQ_HPF1_M_1ST                   (0x1 << 8)
+#define RT5640_EQ_LPF1_M_MASK                  (0x1 << 7)
+#define RT5640_EQ_LPF1_M_SFT                   7
+#define RT5640_EQ_LPF1_M_LO                    (0x0 << 7)
+#define RT5640_EQ_LPF1_M_1ST                   (0x1 << 7)
+#define RT5640_EQ_HPF2_MASK                    (0x1 << 6)
+#define RT5640_EQ_HPF2_SFT                     6
+#define RT5640_EQ_HPF2_DIS                     (0x0 << 6)
+#define RT5640_EQ_HPF2_EN                      (0x1 << 6)
+#define RT5640_EQ_HPF1_MASK                    (0x1 << 5)
+#define RT5640_EQ_HPF1_SFT                     5
+#define RT5640_EQ_HPF1_DIS                     (0x0 << 5)
+#define RT5640_EQ_HPF1_EN                      (0x1 << 5)
+#define RT5640_EQ_BPF4_MASK                    (0x1 << 4)
+#define RT5640_EQ_BPF4_SFT                     4
+#define RT5640_EQ_BPF4_DIS                     (0x0 << 4)
+#define RT5640_EQ_BPF4_EN                      (0x1 << 4)
+#define RT5640_EQ_BPF3_MASK                    (0x1 << 3)
+#define RT5640_EQ_BPF3_SFT                     3
+#define RT5640_EQ_BPF3_DIS                     (0x0 << 3)
+#define RT5640_EQ_BPF3_EN                      (0x1 << 3)
+#define RT5640_EQ_BPF2_MASK                    (0x1 << 2)
+#define RT5640_EQ_BPF2_SFT                     2
+#define RT5640_EQ_BPF2_DIS                     (0x0 << 2)
+#define RT5640_EQ_BPF2_EN                      (0x1 << 2)
+#define RT5640_EQ_BPF1_MASK                    (0x1 << 1)
+#define RT5640_EQ_BPF1_SFT                     1
+#define RT5640_EQ_BPF1_DIS                     (0x0 << 1)
+#define RT5640_EQ_BPF1_EN                      (0x1 << 1)
+#define RT5640_EQ_LPF_MASK                     (0x1)
+#define RT5640_EQ_LPF_SFT                      0
+#define RT5640_EQ_LPF_DIS                      (0x0)
+#define RT5640_EQ_LPF_EN                       (0x1)
+
+/* Memory Test (0xb2) */
+#define RT5640_MT_MASK                         (0x1 << 15)
+#define RT5640_MT_SFT                          15
+#define RT5640_MT_DIS                          (0x0 << 15)
+#define RT5640_MT_EN                           (0x1 << 15)
+
+/* DRC/AGC Control 1 (0xb4) */
+#define RT5640_DRC_AGC_P_MASK                  (0x1 << 15)
+#define RT5640_DRC_AGC_P_SFT                   15
+#define RT5640_DRC_AGC_P_DAC                   (0x0 << 15)
+#define RT5640_DRC_AGC_P_ADC                   (0x1 << 15)
+#define RT5640_DRC_AGC_MASK                    (0x1 << 14)
+#define RT5640_DRC_AGC_SFT                     14
+#define RT5640_DRC_AGC_DIS                     (0x0 << 14)
+#define RT5640_DRC_AGC_EN                      (0x1 << 14)
+#define RT5640_DRC_AGC_UPD                     (0x1 << 13)
+#define RT5640_DRC_AGC_UPD_BIT                 13
+#define RT5640_DRC_AGC_AR_MASK                 (0x1f << 8)
+#define RT5640_DRC_AGC_AR_SFT                  8
+#define RT5640_DRC_AGC_R_MASK                  (0x7 << 5)
+#define RT5640_DRC_AGC_R_SFT                   5
+#define RT5640_DRC_AGC_R_48K                   (0x1 << 5)
+#define RT5640_DRC_AGC_R_96K                   (0x2 << 5)
+#define RT5640_DRC_AGC_R_192K                  (0x3 << 5)
+#define RT5640_DRC_AGC_R_441K                  (0x5 << 5)
+#define RT5640_DRC_AGC_R_882K                  (0x6 << 5)
+#define RT5640_DRC_AGC_R_1764K                 (0x7 << 5)
+#define RT5640_DRC_AGC_RC_MASK                 (0x1f)
+#define RT5640_DRC_AGC_RC_SFT                  0
+
+/* DRC/AGC Control 2 (0xb5) */
+#define RT5640_DRC_AGC_POB_MASK                        (0x3f << 8)
+#define RT5640_DRC_AGC_POB_SFT                 8
+#define RT5640_DRC_AGC_CP_MASK                 (0x1 << 7)
+#define RT5640_DRC_AGC_CP_SFT                  7
+#define RT5640_DRC_AGC_CP_DIS                  (0x0 << 7)
+#define RT5640_DRC_AGC_CP_EN                   (0x1 << 7)
+#define RT5640_DRC_AGC_CPR_MASK                        (0x3 << 5)
+#define RT5640_DRC_AGC_CPR_SFT                 5
+#define RT5640_DRC_AGC_CPR_1_1                 (0x0 << 5)
+#define RT5640_DRC_AGC_CPR_1_2                 (0x1 << 5)
+#define RT5640_DRC_AGC_CPR_1_3                 (0x2 << 5)
+#define RT5640_DRC_AGC_CPR_1_4                 (0x3 << 5)
+#define RT5640_DRC_AGC_PRB_MASK                        (0x1f)
+#define RT5640_DRC_AGC_PRB_SFT                 0
+
+/* DRC/AGC Control 3 (0xb6) */
+#define RT5640_DRC_AGC_NGB_MASK                        (0xf << 12)
+#define RT5640_DRC_AGC_NGB_SFT                 12
+#define RT5640_DRC_AGC_TAR_MASK                        (0x1f << 7)
+#define RT5640_DRC_AGC_TAR_SFT                 7
+#define RT5640_DRC_AGC_NG_MASK                 (0x1 << 6)
+#define RT5640_DRC_AGC_NG_SFT                  6
+#define RT5640_DRC_AGC_NG_DIS                  (0x0 << 6)
+#define RT5640_DRC_AGC_NG_EN                   (0x1 << 6)
+#define RT5640_DRC_AGC_NGH_MASK                        (0x1 << 5)
+#define RT5640_DRC_AGC_NGH_SFT                 5
+#define RT5640_DRC_AGC_NGH_DIS                 (0x0 << 5)
+#define RT5640_DRC_AGC_NGH_EN                  (0x1 << 5)
+#define RT5640_DRC_AGC_NGT_MASK                        (0x1f)
+#define RT5640_DRC_AGC_NGT_SFT                 0
+
+/* ANC Control 1 (0xb8) */
+#define RT5640_ANC_M_MASK                      (0x1 << 15)
+#define RT5640_ANC_M_SFT                       15
+#define RT5640_ANC_M_NOR                       (0x0 << 15)
+#define RT5640_ANC_M_REV                       (0x1 << 15)
+#define RT5640_ANC_MASK                                (0x1 << 14)
+#define RT5640_ANC_SFT                         14
+#define RT5640_ANC_DIS                         (0x0 << 14)
+#define RT5640_ANC_EN                          (0x1 << 14)
+#define RT5640_ANC_MD_MASK                     (0x3 << 12)
+#define RT5640_ANC_MD_SFT                      12
+#define RT5640_ANC_MD_DIS                      (0x0 << 12)
+#define RT5640_ANC_MD_67MS                     (0x1 << 12)
+#define RT5640_ANC_MD_267MS                    (0x2 << 12)
+#define RT5640_ANC_MD_1067MS                   (0x3 << 12)
+#define RT5640_ANC_SN_MASK                     (0x1 << 11)
+#define RT5640_ANC_SN_SFT                      11
+#define RT5640_ANC_SN_DIS                      (0x0 << 11)
+#define RT5640_ANC_SN_EN                       (0x1 << 11)
+#define RT5640_ANC_CLK_MASK                    (0x1 << 10)
+#define RT5640_ANC_CLK_SFT                     10
+#define RT5640_ANC_CLK_ANC                     (0x0 << 10)
+#define RT5640_ANC_CLK_REG                     (0x1 << 10)
+#define RT5640_ANC_ZCD_MASK                    (0x3 << 8)
+#define RT5640_ANC_ZCD_SFT                     8
+#define RT5640_ANC_ZCD_DIS                     (0x0 << 8)
+#define RT5640_ANC_ZCD_T1                      (0x1 << 8)
+#define RT5640_ANC_ZCD_T2                      (0x2 << 8)
+#define RT5640_ANC_ZCD_WT                      (0x3 << 8)
+#define RT5640_ANC_CS_MASK                     (0x1 << 7)
+#define RT5640_ANC_CS_SFT                      7
+#define RT5640_ANC_CS_DIS                      (0x0 << 7)
+#define RT5640_ANC_CS_EN                       (0x1 << 7)
+#define RT5640_ANC_SW_MASK                     (0x1 << 6)
+#define RT5640_ANC_SW_SFT                      6
+#define RT5640_ANC_SW_NOR                      (0x0 << 6)
+#define RT5640_ANC_SW_AUTO                     (0x1 << 6)
+#define RT5640_ANC_CO_L_MASK                   (0x3f)
+#define RT5640_ANC_CO_L_SFT                    0
+
+/* ANC Control 2 (0xb6) */
+#define RT5640_ANC_FG_R_MASK                   (0xf << 12)
+#define RT5640_ANC_FG_R_SFT                    12
+#define RT5640_ANC_FG_L_MASK                   (0xf << 8)
+#define RT5640_ANC_FG_L_SFT                    8
+#define RT5640_ANC_CG_R_MASK                   (0xf << 4)
+#define RT5640_ANC_CG_R_SFT                    4
+#define RT5640_ANC_CG_L_MASK                   (0xf)
+#define RT5640_ANC_CG_L_SFT                    0
+
+/* ANC Control 3 (0xb6) */
+#define RT5640_ANC_CD_MASK                     (0x1 << 6)
+#define RT5640_ANC_CD_SFT                      6
+#define RT5640_ANC_CD_BOTH                     (0x0 << 6)
+#define RT5640_ANC_CD_IND                      (0x1 << 6)
+#define RT5640_ANC_CO_R_MASK                   (0x3f)
+#define RT5640_ANC_CO_R_SFT                    0
+
+/* Jack Detect Control (0xbb) */
+#define RT5640_JD_MASK                         (0x7 << 13)
+#define RT5640_JD_SFT                          13
+#define RT5640_JD_DIS                          (0x0 << 13)
+#define RT5640_JD_GPIO1                                (0x1 << 13)
+#define RT5640_JD_JD1_IN4P                     (0x2 << 13)
+#define RT5640_JD_JD2_IN4N                     (0x3 << 13)
+#define RT5640_JD_GPIO2                                (0x4 << 13)
+#define RT5640_JD_GPIO3                                (0x5 << 13)
+#define RT5640_JD_GPIO4                                (0x6 << 13)
+#define RT5640_JD_HP_MASK                      (0x1 << 11)
+#define RT5640_JD_HP_SFT                       11
+#define RT5640_JD_HP_DIS                       (0x0 << 11)
+#define RT5640_JD_HP_EN                                (0x1 << 11)
+#define RT5640_JD_HP_TRG_MASK                  (0x1 << 10)
+#define RT5640_JD_HP_TRG_SFT                   10
+#define RT5640_JD_HP_TRG_LO                    (0x0 << 10)
+#define RT5640_JD_HP_TRG_HI                    (0x1 << 10)
+#define RT5640_JD_SPL_MASK                     (0x1 << 9)
+#define RT5640_JD_SPL_SFT                      9
+#define RT5640_JD_SPL_DIS                      (0x0 << 9)
+#define RT5640_JD_SPL_EN                       (0x1 << 9)
+#define RT5640_JD_SPL_TRG_MASK                 (0x1 << 8)
+#define RT5640_JD_SPL_TRG_SFT                  8
+#define RT5640_JD_SPL_TRG_LO                   (0x0 << 8)
+#define RT5640_JD_SPL_TRG_HI                   (0x1 << 8)
+#define RT5640_JD_SPR_MASK                     (0x1 << 7)
+#define RT5640_JD_SPR_SFT                      7
+#define RT5640_JD_SPR_DIS                      (0x0 << 7)
+#define RT5640_JD_SPR_EN                       (0x1 << 7)
+#define RT5640_JD_SPR_TRG_MASK                 (0x1 << 6)
+#define RT5640_JD_SPR_TRG_SFT                  6
+#define RT5640_JD_SPR_TRG_LO                   (0x0 << 6)
+#define RT5640_JD_SPR_TRG_HI                   (0x1 << 6)
+#define RT5640_JD_MO_MASK                      (0x1 << 5)
+#define RT5640_JD_MO_SFT                       5
+#define RT5640_JD_MO_DIS                       (0x0 << 5)
+#define RT5640_JD_MO_EN                                (0x1 << 5)
+#define RT5640_JD_MO_TRG_MASK                  (0x1 << 4)
+#define RT5640_JD_MO_TRG_SFT                   4
+#define RT5640_JD_MO_TRG_LO                    (0x0 << 4)
+#define RT5640_JD_MO_TRG_HI                    (0x1 << 4)
+#define RT5640_JD_LO_MASK                      (0x1 << 3)
+#define RT5640_JD_LO_SFT                       3
+#define RT5640_JD_LO_DIS                       (0x0 << 3)
+#define RT5640_JD_LO_EN                                (0x1 << 3)
+#define RT5640_JD_LO_TRG_MASK                  (0x1 << 2)
+#define RT5640_JD_LO_TRG_SFT                   2
+#define RT5640_JD_LO_TRG_LO                    (0x0 << 2)
+#define RT5640_JD_LO_TRG_HI                    (0x1 << 2)
+#define RT5640_JD1_IN4P_MASK                   (0x1 << 1)
+#define RT5640_JD1_IN4P_SFT                    1
+#define RT5640_JD1_IN4P_DIS                    (0x0 << 1)
+#define RT5640_JD1_IN4P_EN                     (0x1 << 1)
+#define RT5640_JD2_IN4N_MASK                   (0x1)
+#define RT5640_JD2_IN4N_SFT                    0
+#define RT5640_JD2_IN4N_DIS                    (0x0)
+#define RT5640_JD2_IN4N_EN                     (0x1)
+
+/* Jack detect for ANC (0xbc) */
+#define RT5640_ANC_DET_MASK                    (0x3 << 4)
+#define RT5640_ANC_DET_SFT                     4
+#define RT5640_ANC_DET_DIS                     (0x0 << 4)
+#define RT5640_ANC_DET_MB1                     (0x1 << 4)
+#define RT5640_ANC_DET_MB2                     (0x2 << 4)
+#define RT5640_ANC_DET_JD                      (0x3 << 4)
+#define RT5640_AD_TRG_MASK                     (0x1 << 3)
+#define RT5640_AD_TRG_SFT                      3
+#define RT5640_AD_TRG_LO                       (0x0 << 3)
+#define RT5640_AD_TRG_HI                       (0x1 << 3)
+#define RT5640_ANCM_DET_MASK                   (0x3 << 4)
+#define RT5640_ANCM_DET_SFT                    4
+#define RT5640_ANCM_DET_DIS                    (0x0 << 4)
+#define RT5640_ANCM_DET_MB1                    (0x1 << 4)
+#define RT5640_ANCM_DET_MB2                    (0x2 << 4)
+#define RT5640_ANCM_DET_JD                     (0x3 << 4)
+#define RT5640_AMD_TRG_MASK                    (0x1 << 3)
+#define RT5640_AMD_TRG_SFT                     3
+#define RT5640_AMD_TRG_LO                      (0x0 << 3)
+#define RT5640_AMD_TRG_HI                      (0x1 << 3)
+
+/* IRQ Control 1 (0xbd) */
+#define RT5640_IRQ_JD_MASK                     (0x1 << 15)
+#define RT5640_IRQ_JD_SFT                      15
+#define RT5640_IRQ_JD_BP                       (0x0 << 15)
+#define RT5640_IRQ_JD_NOR                      (0x1 << 15)
+#define RT5640_IRQ_OT_MASK                     (0x1 << 14)
+#define RT5640_IRQ_OT_SFT                      14
+#define RT5640_IRQ_OT_BP                       (0x0 << 14)
+#define RT5640_IRQ_OT_NOR                      (0x1 << 14)
+#define RT5640_JD_STKY_MASK                    (0x1 << 13)
+#define RT5640_JD_STKY_SFT                     13
+#define RT5640_JD_STKY_DIS                     (0x0 << 13)
+#define RT5640_JD_STKY_EN                      (0x1 << 13)
+#define RT5640_OT_STKY_MASK                    (0x1 << 12)
+#define RT5640_OT_STKY_SFT                     12
+#define RT5640_OT_STKY_DIS                     (0x0 << 12)
+#define RT5640_OT_STKY_EN                      (0x1 << 12)
+#define RT5640_JD_P_MASK                       (0x1 << 11)
+#define RT5640_JD_P_SFT                                11
+#define RT5640_JD_P_NOR                                (0x0 << 11)
+#define RT5640_JD_P_INV                                (0x1 << 11)
+#define RT5640_OT_P_MASK                       (0x1 << 10)
+#define RT5640_OT_P_SFT                                10
+#define RT5640_OT_P_NOR                                (0x0 << 10)
+#define RT5640_OT_P_INV                                (0x1 << 10)
+
+/* IRQ Control 2 (0xbe) */
+#define RT5640_IRQ_MB1_OC_MASK                 (0x1 << 15)
+#define RT5640_IRQ_MB1_OC_SFT                  15
+#define RT5640_IRQ_MB1_OC_BP                   (0x0 << 15)
+#define RT5640_IRQ_MB1_OC_NOR                  (0x1 << 15)
+#define RT5640_IRQ_MB2_OC_MASK                 (0x1 << 14)
+#define RT5640_IRQ_MB2_OC_SFT                  14
+#define RT5640_IRQ_MB2_OC_BP                   (0x0 << 14)
+#define RT5640_IRQ_MB2_OC_NOR                  (0x1 << 14)
+#define RT5640_MB1_OC_STKY_MASK                        (0x1 << 11)
+#define RT5640_MB1_OC_STKY_SFT                 11
+#define RT5640_MB1_OC_STKY_DIS                 (0x0 << 11)
+#define RT5640_MB1_OC_STKY_EN                  (0x1 << 11)
+#define RT5640_MB2_OC_STKY_MASK                        (0x1 << 10)
+#define RT5640_MB2_OC_STKY_SFT                 10
+#define RT5640_MB2_OC_STKY_DIS                 (0x0 << 10)
+#define RT5640_MB2_OC_STKY_EN                  (0x1 << 10)
+#define RT5640_MB1_OC_P_MASK                   (0x1 << 7)
+#define RT5640_MB1_OC_P_SFT                    7
+#define RT5640_MB1_OC_P_NOR                    (0x0 << 7)
+#define RT5640_MB1_OC_P_INV                    (0x1 << 7)
+#define RT5640_MB2_OC_P_MASK                   (0x1 << 6)
+#define RT5640_MB2_OC_P_SFT                    6
+#define RT5640_MB2_OC_P_NOR                    (0x0 << 6)
+#define RT5640_MB2_OC_P_INV                    (0x1 << 6)
+#define RT5640_MB1_OC_CLR                      (0x1 << 3)
+#define RT5640_MB1_OC_CLR_SFT                  3
+#define RT5640_MB2_OC_CLR                      (0x1 << 2)
+#define RT5640_MB2_OC_CLR_SFT                  2
+
+/* GPIO Control 1 (0xc0) */
+#define RT5640_GP1_PIN_MASK                    (0x1 << 15)
+#define RT5640_GP1_PIN_SFT                     15
+#define RT5640_GP1_PIN_GPIO1                   (0x0 << 15)
+#define RT5640_GP1_PIN_IRQ                     (0x1 << 15)
+#define RT5640_GP2_PIN_MASK                    (0x1 << 14)
+#define RT5640_GP2_PIN_SFT                     14
+#define RT5640_GP2_PIN_GPIO2                   (0x0 << 14)
+#define RT5640_GP2_PIN_DMIC1_SCL               (0x1 << 14)
+#define RT5640_GP3_PIN_MASK                    (0x3 << 12)
+#define RT5640_GP3_PIN_SFT                     12
+#define RT5640_GP3_PIN_GPIO3                   (0x0 << 12)
+#define RT5640_GP3_PIN_DMIC1_SDA               (0x1 << 12)
+#define RT5640_GP3_PIN_IRQ                     (0x2 << 12)
+#define RT5640_GP4_PIN_MASK                    (0x1 << 11)
+#define RT5640_GP4_PIN_SFT                     11
+#define RT5640_GP4_PIN_GPIO4                   (0x0 << 11)
+#define RT5640_GP4_PIN_DMIC2_SDA               (0x1 << 11)
+#define RT5640_DP_SIG_MASK                     (0x1 << 10)
+#define RT5640_DP_SIG_SFT                      10
+#define RT5640_DP_SIG_TEST                     (0x0 << 10)
+#define RT5640_DP_SIG_AP                       (0x1 << 10)
+#define RT5640_GPIO_M_MASK                     (0x1 << 9)
+#define RT5640_GPIO_M_SFT                      9
+#define RT5640_GPIO_M_FLT                      (0x0 << 9)
+#define RT5640_GPIO_M_PH                       (0x1 << 9)
+
+/* GPIO Control 3 (0xc2) */
+#define RT5640_GP4_PF_MASK                     (0x1 << 11)
+#define RT5640_GP4_PF_SFT                      11
+#define RT5640_GP4_PF_IN                       (0x0 << 11)
+#define RT5640_GP4_PF_OUT                      (0x1 << 11)
+#define RT5640_GP4_OUT_MASK                    (0x1 << 10)
+#define RT5640_GP4_OUT_SFT                     10
+#define RT5640_GP4_OUT_LO                      (0x0 << 10)
+#define RT5640_GP4_OUT_HI                      (0x1 << 10)
+#define RT5640_GP4_P_MASK                      (0x1 << 9)
+#define RT5640_GP4_P_SFT                       9
+#define RT5640_GP4_P_NOR                       (0x0 << 9)
+#define RT5640_GP4_P_INV                       (0x1 << 9)
+#define RT5640_GP3_PF_MASK                     (0x1 << 8)
+#define RT5640_GP3_PF_SFT                      8
+#define RT5640_GP3_PF_IN                       (0x0 << 8)
+#define RT5640_GP3_PF_OUT                      (0x1 << 8)
+#define RT5640_GP3_OUT_MASK                    (0x1 << 7)
+#define RT5640_GP3_OUT_SFT                     7
+#define RT5640_GP3_OUT_LO                      (0x0 << 7)
+#define RT5640_GP3_OUT_HI                      (0x1 << 7)
+#define RT5640_GP3_P_MASK                      (0x1 << 6)
+#define RT5640_GP3_P_SFT                       6
+#define RT5640_GP3_P_NOR                       (0x0 << 6)
+#define RT5640_GP3_P_INV                       (0x1 << 6)
+#define RT5640_GP2_PF_MASK                     (0x1 << 5)
+#define RT5640_GP2_PF_SFT                      5
+#define RT5640_GP2_PF_IN                       (0x0 << 5)
+#define RT5640_GP2_PF_OUT                      (0x1 << 5)
+#define RT5640_GP2_OUT_MASK                    (0x1 << 4)
+#define RT5640_GP2_OUT_SFT                     4
+#define RT5640_GP2_OUT_LO                      (0x0 << 4)
+#define RT5640_GP2_OUT_HI                      (0x1 << 4)
+#define RT5640_GP2_P_MASK                      (0x1 << 3)
+#define RT5640_GP2_P_SFT                       3
+#define RT5640_GP2_P_NOR                       (0x0 << 3)
+#define RT5640_GP2_P_INV                       (0x1 << 3)
+#define RT5640_GP1_PF_MASK                     (0x1 << 2)
+#define RT5640_GP1_PF_SFT                      2
+#define RT5640_GP1_PF_IN                       (0x0 << 2)
+#define RT5640_GP1_PF_OUT                      (0x1 << 2)
+#define RT5640_GP1_OUT_MASK                    (0x1 << 1)
+#define RT5640_GP1_OUT_SFT                     1
+#define RT5640_GP1_OUT_LO                      (0x0 << 1)
+#define RT5640_GP1_OUT_HI                      (0x1 << 1)
+#define RT5640_GP1_P_MASK                      (0x1)
+#define RT5640_GP1_P_SFT                       0
+#define RT5640_GP1_P_NOR                       (0x0)
+#define RT5640_GP1_P_INV                       (0x1)
+
+/* FM34-500 Register Control 1 (0xc4) */
+#define RT5640_DSP_ADD_SFT                     0
+
+/* FM34-500 Register Control 2 (0xc5) */
+#define RT5640_DSP_DAT_SFT                     0
+
+/* FM34-500 Register Control 3 (0xc6) */
+#define RT5640_DSP_BUSY_MASK                   (0x1 << 15)
+#define RT5640_DSP_BUSY_BIT                    15
+#define RT5640_DSP_DS_MASK                     (0x1 << 14)
+#define RT5640_DSP_DS_SFT                      14
+#define RT5640_DSP_DS_FM3010                   (0x1 << 14)
+#define RT5640_DSP_DS_TEMP                     (0x1 << 14)
+#define RT5640_DSP_CLK_MASK                    (0x3 << 12)
+#define RT5640_DSP_CLK_SFT                     12
+#define RT5640_DSP_CLK_384K                    (0x0 << 12)
+#define RT5640_DSP_CLK_192K                    (0x1 << 12)
+#define RT5640_DSP_CLK_96K                     (0x2 << 12)
+#define RT5640_DSP_CLK_64K                     (0x3 << 12)
+#define RT5640_DSP_PD_PIN_MASK                 (0x1 << 11)
+#define RT5640_DSP_PD_PIN_SFT                  11
+#define RT5640_DSP_PD_PIN_LO                   (0x0 << 11)
+#define RT5640_DSP_PD_PIN_HI                   (0x1 << 11)
+#define RT5640_DSP_RST_PIN_MASK                        (0x1 << 10)
+#define RT5640_DSP_RST_PIN_SFT                 10
+#define RT5640_DSP_RST_PIN_LO                  (0x0 << 10)
+#define RT5640_DSP_RST_PIN_HI                  (0x1 << 10)
+#define RT5640_DSP_R_EN                                (0x1 << 9)
+#define RT5640_DSP_R_EN_BIT                    9
+#define RT5640_DSP_W_EN                                (0x1 << 8)
+#define RT5640_DSP_W_EN_BIT                    8
+#define RT5640_DSP_CMD_MASK                    (0xff)
+#define RT5640_DSP_CMD_SFT                     0
+#define RT5640_DSP_CMD_MW                      (0x3B)  /* Memory Write */
+#define RT5640_DSP_CMD_MR                      (0x37)  /* Memory Read */
+#define RT5640_DSP_CMD_RR                      (0x60)  /* Register Read */
+#define RT5640_DSP_CMD_RW                      (0x68)  /* Register Write */
+
+/* Programmable Register Array Control 1 (0xc8) */
+#define RT5640_REG_SEQ_MASK                    (0xf << 12)
+#define RT5640_REG_SEQ_SFT                     12
+#define RT5640_SEQ1_ST_MASK                    (0x1 << 11) /*RO*/
+#define RT5640_SEQ1_ST_SFT                     11
+#define RT5640_SEQ1_ST_RUN                     (0x0 << 11)
+#define RT5640_SEQ1_ST_FIN                     (0x1 << 11)
+#define RT5640_SEQ2_ST_MASK                    (0x1 << 10) /*RO*/
+#define RT5640_SEQ2_ST_SFT                     10
+#define RT5640_SEQ2_ST_RUN                     (0x0 << 10)
+#define RT5640_SEQ2_ST_FIN                     (0x1 << 10)
+#define RT5640_REG_LV_MASK                     (0x1 << 9)
+#define RT5640_REG_LV_SFT                      9
+#define RT5640_REG_LV_MX                       (0x0 << 9)
+#define RT5640_REG_LV_PR                       (0x1 << 9)
+#define RT5640_SEQ_2_PT_MASK                   (0x1 << 8)
+#define RT5640_SEQ_2_PT_BIT                    8
+#define RT5640_REG_IDX_MASK                    (0xff)
+#define RT5640_REG_IDX_SFT                     0
+
+/* Programmable Register Array Control 2 (0xc9) */
+#define RT5640_REG_DAT_MASK                    (0xffff)
+#define RT5640_REG_DAT_SFT                     0
+
+/* Programmable Register Array Control 3 (0xca) */
+#define RT5640_SEQ_DLY_MASK                    (0xff << 8)
+#define RT5640_SEQ_DLY_SFT                     8
+#define RT5640_PROG_MASK                       (0x1 << 7)
+#define RT5640_PROG_SFT                                7
+#define RT5640_PROG_DIS                                (0x0 << 7)
+#define RT5640_PROG_EN                         (0x1 << 7)
+#define RT5640_SEQ1_PT_RUN                     (0x1 << 6)
+#define RT5640_SEQ1_PT_RUN_BIT                 6
+#define RT5640_SEQ2_PT_RUN                     (0x1 << 5)
+#define RT5640_SEQ2_PT_RUN_BIT                 5
+
+/* Programmable Register Array Control 4 (0xcb) */
+#define RT5640_SEQ1_START_MASK                 (0xf << 8)
+#define RT5640_SEQ1_START_SFT                  8
+#define RT5640_SEQ1_END_MASK                   (0xf)
+#define RT5640_SEQ1_END_SFT                    0
+
+/* Programmable Register Array Control 5 (0xcc) */
+#define RT5640_SEQ2_START_MASK                 (0xf << 8)
+#define RT5640_SEQ2_START_SFT                  8
+#define RT5640_SEQ2_END_MASK                   (0xf)
+#define RT5640_SEQ2_END_SFT                    0
+
+/* Scramble Function (0xcd) */
+#define RT5640_SCB_KEY_MASK                    (0xff)
+#define RT5640_SCB_KEY_SFT                     0
+
+/* Scramble Control (0xce) */
+#define RT5640_SCB_SWAP_MASK                   (0x1 << 15)
+#define RT5640_SCB_SWAP_SFT                    15
+#define RT5640_SCB_SWAP_DIS                    (0x0 << 15)
+#define RT5640_SCB_SWAP_EN                     (0x1 << 15)
+#define RT5640_SCB_MASK                                (0x1 << 14)
+#define RT5640_SCB_SFT                         14
+#define RT5640_SCB_DIS                         (0x0 << 14)
+#define RT5640_SCB_EN                          (0x1 << 14)
+
+/* Baseback Control (0xcf) */
+#define RT5640_BB_MASK                         (0x1 << 15)
+#define RT5640_BB_SFT                          15
+#define RT5640_BB_DIS                          (0x0 << 15)
+#define RT5640_BB_EN                           (0x1 << 15)
+#define RT5640_BB_CT_MASK                      (0x7 << 12)
+#define RT5640_BB_CT_SFT                       12
+#define RT5640_BB_CT_A                         (0x0 << 12)
+#define RT5640_BB_CT_B                         (0x1 << 12)
+#define RT5640_BB_CT_C                         (0x2 << 12)
+#define RT5640_BB_CT_D                         (0x3 << 12)
+#define RT5640_M_BB_L_MASK                     (0x1 << 9)
+#define RT5640_M_BB_L_SFT                      9
+#define RT5640_M_BB_R_MASK                     (0x1 << 8)
+#define RT5640_M_BB_R_SFT                      8
+#define RT5640_M_BB_HPF_L_MASK                 (0x1 << 7)
+#define RT5640_M_BB_HPF_L_SFT                  7
+#define RT5640_M_BB_HPF_R_MASK                 (0x1 << 6)
+#define RT5640_M_BB_HPF_R_SFT                  6
+#define RT5640_G_BB_BST_MASK                   (0x3f)
+#define RT5640_G_BB_BST_SFT                    0
+
+/* MP3 Plus Control 1 (0xd0) */
+#define RT5640_M_MP3_L_MASK                    (0x1 << 15)
+#define RT5640_M_MP3_L_SFT                     15
+#define RT5640_M_MP3_R_MASK                    (0x1 << 14)
+#define RT5640_M_MP3_R_SFT                     14
+#define RT5640_M_MP3_MASK                      (0x1 << 13)
+#define RT5640_M_MP3_SFT                       13
+#define RT5640_M_MP3_DIS                       (0x0 << 13)
+#define RT5640_M_MP3_EN                                (0x1 << 13)
+#define RT5640_EG_MP3_MASK                     (0x1f << 8)
+#define RT5640_EG_MP3_SFT                      8
+#define RT5640_MP3_HLP_MASK                    (0x1 << 7)
+#define RT5640_MP3_HLP_SFT                     7
+#define RT5640_MP3_HLP_DIS                     (0x0 << 7)
+#define RT5640_MP3_HLP_EN                      (0x1 << 7)
+#define RT5640_M_MP3_ORG_L_MASK                        (0x1 << 6)
+#define RT5640_M_MP3_ORG_L_SFT                 6
+#define RT5640_M_MP3_ORG_R_MASK                        (0x1 << 5)
+#define RT5640_M_MP3_ORG_R_SFT                 5
+
+/* MP3 Plus Control 2 (0xd1) */
+#define RT5640_MP3_WT_MASK                     (0x1 << 13)
+#define RT5640_MP3_WT_SFT                      13
+#define RT5640_MP3_WT_1_4                      (0x0 << 13)
+#define RT5640_MP3_WT_1_2                      (0x1 << 13)
+#define RT5640_OG_MP3_MASK                     (0x1f << 8)
+#define RT5640_OG_MP3_SFT                      8
+#define RT5640_HG_MP3_MASK                     (0x3f)
+#define RT5640_HG_MP3_SFT                      0
+
+/* 3D HP Control 1 (0xd2) */
+#define RT5640_3D_CF_MASK                      (0x1 << 15)
+#define RT5640_3D_CF_SFT                       15
+#define RT5640_3D_CF_DIS                       (0x0 << 15)
+#define RT5640_3D_CF_EN                                (0x1 << 15)
+#define RT5640_3D_HP_MASK                      (0x1 << 14)
+#define RT5640_3D_HP_SFT                       14
+#define RT5640_3D_HP_DIS                       (0x0 << 14)
+#define RT5640_3D_HP_EN                                (0x1 << 14)
+#define RT5640_3D_BT_MASK                      (0x1 << 13)
+#define RT5640_3D_BT_SFT                       13
+#define RT5640_3D_BT_DIS                       (0x0 << 13)
+#define RT5640_3D_BT_EN                                (0x1 << 13)
+#define RT5640_3D_1F_MIX_MASK                  (0x3 << 11)
+#define RT5640_3D_1F_MIX_SFT                   11
+#define RT5640_3D_HP_M_MASK                    (0x1 << 10)
+#define RT5640_3D_HP_M_SFT                     10
+#define RT5640_3D_HP_M_SUR                     (0x0 << 10)
+#define RT5640_3D_HP_M_FRO                     (0x1 << 10)
+#define RT5640_M_3D_HRTF_MASK                  (0x1 << 9)
+#define RT5640_M_3D_HRTF_SFT                   9
+#define RT5640_M_3D_D2H_MASK                   (0x1 << 8)
+#define RT5640_M_3D_D2H_SFT                    8
+#define RT5640_M_3D_D2R_MASK                   (0x1 << 7)
+#define RT5640_M_3D_D2R_SFT                    7
+#define RT5640_M_3D_REVB_MASK                  (0x1 << 6)
+#define RT5640_M_3D_REVB_SFT                   6
+
+/* Adjustable high pass filter control 1 (0xd3) */
+#define RT5640_2ND_HPF_MASK                    (0x1 << 15)
+#define RT5640_2ND_HPF_SFT                     15
+#define RT5640_2ND_HPF_DIS                     (0x0 << 15)
+#define RT5640_2ND_HPF_EN                      (0x1 << 15)
+#define RT5640_HPF_CF_L_MASK                   (0x7 << 12)
+#define RT5640_HPF_CF_L_SFT                    12
+#define RT5640_1ST_HPF_MASK                    (0x1 << 11)
+#define RT5640_1ST_HPF_SFT                     11
+#define RT5640_1ST_HPF_DIS                     (0x0 << 11)
+#define RT5640_1ST_HPF_EN                      (0x1 << 11)
+#define RT5640_HPF_CF_R_MASK                   (0x7 << 8)
+#define RT5640_HPF_CF_R_SFT                    8
+#define RT5640_ZD_T_MASK                       (0x3 << 6)
+#define RT5640_ZD_T_SFT                                6
+#define RT5640_ZD_F_MASK                       (0x3 << 4)
+#define RT5640_ZD_F_SFT                                4
+#define RT5640_ZD_F_IM                         (0x0 << 4)
+#define RT5640_ZD_F_ZC_IM                      (0x1 << 4)
+#define RT5640_ZD_F_ZC_IOD                     (0x2 << 4)
+#define RT5640_ZD_F_UN                         (0x3 << 4)
+
+/* HP calibration control and Amp detection (0xd6) */
+#define RT5640_SI_DAC_MASK                     (0x1 << 11)
+#define RT5640_SI_DAC_SFT                      11
+#define RT5640_SI_DAC_AUTO                     (0x0 << 11)
+#define RT5640_SI_DAC_TEST                     (0x1 << 11)
+#define RT5640_DC_CAL_M_MASK                   (0x1 << 10)
+#define RT5640_DC_CAL_M_SFT                    10
+#define RT5640_DC_CAL_M_CAL                    (0x0 << 10)
+#define RT5640_DC_CAL_M_NOR                    (0x1 << 10)
+#define RT5640_DC_CAL_MASK                     (0x1 << 9)
+#define RT5640_DC_CAL_SFT                      9
+#define RT5640_DC_CAL_DIS                      (0x0 << 9)
+#define RT5640_DC_CAL_EN                       (0x1 << 9)
+#define RT5640_HPD_RCV_MASK                    (0x7 << 6)
+#define RT5640_HPD_RCV_SFT                     6
+#define RT5640_HPD_PS_MASK                     (0x1 << 5)
+#define RT5640_HPD_PS_SFT                      5
+#define RT5640_HPD_PS_DIS                      (0x0 << 5)
+#define RT5640_HPD_PS_EN                       (0x1 << 5)
+#define RT5640_CAL_M_MASK                      (0x1 << 4)
+#define RT5640_CAL_M_SFT                       4
+#define RT5640_CAL_M_DEP                       (0x0 << 4)
+#define RT5640_CAL_M_CAL                       (0x1 << 4)
+#define RT5640_CAL_MASK                                (0x1 << 3)
+#define RT5640_CAL_SFT                         3
+#define RT5640_CAL_DIS                         (0x0 << 3)
+#define RT5640_CAL_EN                          (0x1 << 3)
+#define RT5640_CAL_TEST_MASK                   (0x1 << 2)
+#define RT5640_CAL_TEST_SFT                    2
+#define RT5640_CAL_TEST_DIS                    (0x0 << 2)
+#define RT5640_CAL_TEST_EN                     (0x1 << 2)
+#define RT5640_CAL_P_MASK                      (0x3)
+#define RT5640_CAL_P_SFT                       0
+#define RT5640_CAL_P_NONE                      (0x0)
+#define RT5640_CAL_P_CAL                       (0x1)
+#define RT5640_CAL_P_DAC_CAL                   (0x2)
+
+/* Soft volume and zero cross control 1 (0xd9) */
+#define RT5640_SV_MASK                         (0x1 << 15)
+#define RT5640_SV_SFT                          15
+#define RT5640_SV_DIS                          (0x0 << 15)
+#define RT5640_SV_EN                           (0x1 << 15)
+#define RT5640_SPO_SV_MASK                     (0x1 << 14)
+#define RT5640_SPO_SV_SFT                      14
+#define RT5640_SPO_SV_DIS                      (0x0 << 14)
+#define RT5640_SPO_SV_EN                       (0x1 << 14)
+#define RT5640_OUT_SV_MASK                     (0x1 << 13)
+#define RT5640_OUT_SV_SFT                      13
+#define RT5640_OUT_SV_DIS                      (0x0 << 13)
+#define RT5640_OUT_SV_EN                       (0x1 << 13)
+#define RT5640_HP_SV_MASK                      (0x1 << 12)
+#define RT5640_HP_SV_SFT                       12
+#define RT5640_HP_SV_DIS                       (0x0 << 12)
+#define RT5640_HP_SV_EN                                (0x1 << 12)
+#define RT5640_ZCD_DIG_MASK                    (0x1 << 11)
+#define RT5640_ZCD_DIG_SFT                     11
+#define RT5640_ZCD_DIG_DIS                     (0x0 << 11)
+#define RT5640_ZCD_DIG_EN                      (0x1 << 11)
+#define RT5640_ZCD_MASK                                (0x1 << 10)
+#define RT5640_ZCD_SFT                         10
+#define RT5640_ZCD_PD                          (0x0 << 10)
+#define RT5640_ZCD_PU                          (0x1 << 10)
+#define RT5640_M_ZCD_MASK                      (0x3f << 4)
+#define RT5640_M_ZCD_SFT                       4
+#define RT5640_M_ZCD_RM_L                      (0x1 << 9)
+#define RT5640_M_ZCD_RM_R                      (0x1 << 8)
+#define RT5640_M_ZCD_SM_L                      (0x1 << 7)
+#define RT5640_M_ZCD_SM_R                      (0x1 << 6)
+#define RT5640_M_ZCD_OM_L                      (0x1 << 5)
+#define RT5640_M_ZCD_OM_R                      (0x1 << 4)
+#define RT5640_SV_DLY_MASK                     (0xf)
+#define RT5640_SV_DLY_SFT                      0
+
+/* Soft volume and zero cross control 2 (0xda) */
+#define RT5640_ZCD_HP_MASK                     (0x1 << 15)
+#define RT5640_ZCD_HP_SFT                      15
+#define RT5640_ZCD_HP_DIS                      (0x0 << 15)
+#define RT5640_ZCD_HP_EN                       (0x1 << 15)
+
+
+/* Codec Private Register definition */
+/* 3D Speaker Control (0x63) */
+#define RT5640_3D_SPK_MASK                     (0x1 << 15)
+#define RT5640_3D_SPK_SFT                      15
+#define RT5640_3D_SPK_DIS                      (0x0 << 15)
+#define RT5640_3D_SPK_EN                       (0x1 << 15)
+#define RT5640_3D_SPK_M_MASK                   (0x3 << 13)
+#define RT5640_3D_SPK_M_SFT                    13
+#define RT5640_3D_SPK_CG_MASK                  (0x1f << 8)
+#define RT5640_3D_SPK_CG_SFT                   8
+#define RT5640_3D_SPK_SG_MASK                  (0x1f)
+#define RT5640_3D_SPK_SG_SFT                   0
+
+/* Wind Noise Detection Control 1 (0x6c) */
+#define RT5640_WND_MASK                                (0x1 << 15)
+#define RT5640_WND_SFT                         15
+#define RT5640_WND_DIS                         (0x0 << 15)
+#define RT5640_WND_EN                          (0x1 << 15)
+
+/* Wind Noise Detection Control 2 (0x6d) */
+#define RT5640_WND_FC_NW_MASK                  (0x3f << 10)
+#define RT5640_WND_FC_NW_SFT                   10
+#define RT5640_WND_FC_WK_MASK                  (0x3f << 4)
+#define RT5640_WND_FC_WK_SFT                   4
+
+/* Wind Noise Detection Control 3 (0x6e) */
+#define RT5640_HPF_FC_MASK                     (0x3f << 6)
+#define RT5640_HPF_FC_SFT                      6
+#define RT5640_WND_FC_ST_MASK                  (0x3f)
+#define RT5640_WND_FC_ST_SFT                   0
+
+/* Wind Noise Detection Control 4 (0x6f) */
+#define RT5640_WND_TH_LO_MASK                  (0x3ff)
+#define RT5640_WND_TH_LO_SFT                   0
+
+/* Wind Noise Detection Control 5 (0x70) */
+#define RT5640_WND_TH_HI_MASK                  (0x3ff)
+#define RT5640_WND_TH_HI_SFT                   0
+
+/* Wind Noise Detection Control 8 (0x73) */
+#define RT5640_WND_WIND_MASK                   (0x1 << 13) /* Read-Only */
+#define RT5640_WND_WIND_SFT                    13
+#define RT5640_WND_STRONG_MASK                 (0x1 << 12) /* Read-Only */
+#define RT5640_WND_STRONG_SFT                  12
+enum {
+       RT5640_NO_WIND,
+       RT5640_BREEZE,
+       RT5640_STORM,
+};
+
+/* Dipole Speaker Interface (0x75) */
+#define RT5640_DP_ATT_MASK                     (0x3 << 14)
+#define RT5640_DP_ATT_SFT                      14
+#define RT5640_DP_SPK_MASK                     (0x1 << 10)
+#define RT5640_DP_SPK_SFT                      10
+#define RT5640_DP_SPK_DIS                      (0x0 << 10)
+#define RT5640_DP_SPK_EN                       (0x1 << 10)
+
+/* EQ Pre Volume Control (0xb3) */
+#define RT5640_EQ_PRE_VOL_MASK                 (0xffff)
+#define RT5640_EQ_PRE_VOL_SFT                  0
+
+/* EQ Post Volume Control (0xb4) */
+#define RT5640_EQ_PST_VOL_MASK                 (0xffff)
+#define RT5640_EQ_PST_VOL_SFT                  0
+
+#define RT5640_NO_JACK         BIT(0)
+#define RT5640_HEADSET_DET     BIT(1)
+#define RT5640_HEADPHO_DET     BIT(2)
+
+/* System Clock Source */
+#define RT5640_SCLK_S_MCLK     0
+#define RT5640_SCLK_S_PLL1     1
+#define RT5640_SCLK_S_PLL1_TK  2
+#define RT5640_SCLK_S_RCCLK    3
+
+/* PLL1 Source */
+#define RT5640_PLL1_S_MCLK     0
+#define RT5640_PLL1_S_BCLK1    1
+#define RT5640_PLL1_S_BCLK2    2
+#define RT5640_PLL1_S_BCLK3    3
+
+
+enum {
+       RT5640_AIF1,
+       RT5640_AIF2,
+       RT5640_AIF3,
+       RT5640_AIFS,
+};
+
+enum {
+       RT5640_U_IF1 = 0x1,
+       RT5640_U_IF2 = 0x2,
+       RT5640_U_IF3 = 0x4,
+};
+
+enum {
+       RT5640_IF_123,
+       RT5640_IF_132,
+       RT5640_IF_312,
+       RT5640_IF_321,
+       RT5640_IF_231,
+       RT5640_IF_213,
+       RT5640_IF_113,
+       RT5640_IF_223,
+       RT5640_IF_ALL,
+};
+
+enum {
+       RT5640_DMIC_DIS,
+       RT5640_DMIC1,
+       RT5640_DMIC2,
+};
+
+struct rt5640_pll_code {
+       bool m_bp; /* Indicates bypass m code or not. */
+       int m_code;
+       int n_code;
+       int k_code;
+};
+
+struct rt5640_priv {
+       struct snd_soc_codec *codec;
+       struct rt5640_platform_data pdata;
+       struct regmap *regmap;
+
+       int sysclk;
+       int sysclk_src;
+       int lrck[RT5640_AIFS];
+       int bclk[RT5640_AIFS];
+       int master[RT5640_AIFS];
+
+       struct rt5640_pll_code pll_code;
+       int pll_src;
+       int pll_in;
+       int pll_out;
+
+       int dmic_en;
+};
+
+#endif
index 92bbfec9b107a0ec5ee55205b9272ce9e67caa74..d441559dc92caaa5f38a847effeebb681531f5a1 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/clk.h>
+#include <linux/regmap.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/consumer.h>
 #define SGTL5000_MAX_REG_OFFSET        0x013A
 
 /* default value of sgtl5000 registers */
-static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET] =  {
-       [SGTL5000_CHIP_CLK_CTRL] = 0x0008,
-       [SGTL5000_CHIP_I2S_CTRL] = 0x0010,
-       [SGTL5000_CHIP_SSS_CTRL] = 0x0008,
-       [SGTL5000_CHIP_DAC_VOL] = 0x3c3c,
-       [SGTL5000_CHIP_PAD_STRENGTH] = 0x015f,
-       [SGTL5000_CHIP_ANA_HP_CTRL] = 0x1818,
-       [SGTL5000_CHIP_ANA_CTRL] = 0x0111,
-       [SGTL5000_CHIP_LINE_OUT_VOL] = 0x0404,
-       [SGTL5000_CHIP_ANA_POWER] = 0x7060,
-       [SGTL5000_CHIP_PLL_CTRL] = 0x5000,
-       [SGTL5000_DAP_BASS_ENHANCE] = 0x0040,
-       [SGTL5000_DAP_BASS_ENHANCE_CTRL] = 0x051f,
-       [SGTL5000_DAP_SURROUND] = 0x0040,
-       [SGTL5000_DAP_EQ_BASS_BAND0] = 0x002f,
-       [SGTL5000_DAP_EQ_BASS_BAND1] = 0x002f,
-       [SGTL5000_DAP_EQ_BASS_BAND2] = 0x002f,
-       [SGTL5000_DAP_EQ_BASS_BAND3] = 0x002f,
-       [SGTL5000_DAP_EQ_BASS_BAND4] = 0x002f,
-       [SGTL5000_DAP_MAIN_CHAN] = 0x8000,
-       [SGTL5000_DAP_AVC_CTRL] = 0x0510,
-       [SGTL5000_DAP_AVC_THRESHOLD] = 0x1473,
-       [SGTL5000_DAP_AVC_ATTACK] = 0x0028,
-       [SGTL5000_DAP_AVC_DECAY] = 0x0050,
+static const struct reg_default sgtl5000_reg_defaults[] = {
+       { SGTL5000_CHIP_CLK_CTRL,               0x0008 },
+       { SGTL5000_CHIP_I2S_CTRL,               0x0010 },
+       { SGTL5000_CHIP_SSS_CTRL,               0x0008 },
+       { SGTL5000_CHIP_DAC_VOL,                0x3c3c },
+       { SGTL5000_CHIP_PAD_STRENGTH,           0x015f },
+       { SGTL5000_CHIP_ANA_HP_CTRL,            0x1818 },
+       { SGTL5000_CHIP_ANA_CTRL,               0x0111 },
+       { SGTL5000_CHIP_LINE_OUT_VOL,           0x0404 },
+       { SGTL5000_CHIP_ANA_POWER,              0x7060 },
+       { SGTL5000_CHIP_PLL_CTRL,               0x5000 },
+       { SGTL5000_DAP_BASS_ENHANCE,            0x0040 },
+       { SGTL5000_DAP_BASS_ENHANCE_CTRL,       0x051f },
+       { SGTL5000_DAP_SURROUND,                0x0040 },
+       { SGTL5000_DAP_EQ_BASS_BAND0,           0x002f },
+       { SGTL5000_DAP_EQ_BASS_BAND1,           0x002f },
+       { SGTL5000_DAP_EQ_BASS_BAND2,           0x002f },
+       { SGTL5000_DAP_EQ_BASS_BAND3,           0x002f },
+       { SGTL5000_DAP_EQ_BASS_BAND4,           0x002f },
+       { SGTL5000_DAP_MAIN_CHAN,               0x8000 },
+       { SGTL5000_DAP_AVC_CTRL,                0x0510 },
+       { SGTL5000_DAP_AVC_THRESHOLD,           0x1473 },
+       { SGTL5000_DAP_AVC_ATTACK,              0x0028 },
+       { SGTL5000_DAP_AVC_DECAY,               0x0050 },
 };
 
 /* regulator supplies for sgtl5000, VDDD is an optional external supply */
@@ -112,6 +113,8 @@ struct sgtl5000_priv {
        int fmt;        /* i2s data format */
        struct regulator_bulk_data supplies[SGTL5000_SUPPLY_NUM];
        struct ldo_regulator *ldo;
+       struct regmap *regmap;
+       struct clk *mclk;
 };
 
 /*
@@ -151,12 +154,12 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
        switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
+       case SND_SOC_DAPM_POST_PMU:
                snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
                        SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
                break;
 
-       case SND_SOC_DAPM_POST_PMD:
+       case SND_SOC_DAPM_PRE_PMD:
                snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
                        SGTL5000_VAG_POWERUP, 0);
                msleep(400);
@@ -217,12 +220,11 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
                                0, SGTL5000_CHIP_DIG_POWER,
                                1, 0),
 
-       SND_SOC_DAPM_SUPPLY("VAG_POWER", SGTL5000_CHIP_ANA_POWER, 7, 0,
-                           power_vag_event,
-                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
        SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0),
        SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0),
+
+       SND_SOC_DAPM_PRE("VAG_POWER_PRE", power_vag_event),
+       SND_SOC_DAPM_POST("VAG_POWER_POST", power_vag_event),
 };
 
 /* routes for sgtl5000 */
@@ -230,16 +232,13 @@ static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = {
        {"Capture Mux", "LINE_IN", "LINE_IN"},  /* line_in --> adc_mux */
        {"Capture Mux", "MIC_IN", "MIC_IN"},    /* mic_in --> adc_mux */
 
-       {"ADC", NULL, "VAG_POWER"},
        {"ADC", NULL, "Capture Mux"},           /* adc_mux --> adc */
        {"AIFOUT", NULL, "ADC"},                /* adc --> i2s_out */
 
-       {"DAC", NULL, "VAG_POWER"},
        {"DAC", NULL, "AIFIN"},                 /* i2s-->dac,skip audio mux */
        {"Headphone Mux", "DAC", "DAC"},        /* dac --> hp_mux */
        {"LO", NULL, "DAC"},                    /* dac --> line_out */
 
-       {"LINE_IN", NULL, "VAG_POWER"},
        {"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */
        {"HP", NULL, "Headphone Mux"},          /* hp_mux --> hp */
 
@@ -909,10 +908,25 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
                        if (ret)
                                return ret;
                        udelay(10);
+
+                       regcache_cache_only(sgtl5000->regmap, false);
+
+                       ret = regcache_sync(sgtl5000->regmap);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to restore cache: %d\n", ret);
+
+                               regcache_cache_only(sgtl5000->regmap, true);
+                               regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
+                                                      sgtl5000->supplies);
+
+                               return ret;
+                       }
                }
 
                break;
        case SND_SOC_BIAS_OFF:
+               regcache_cache_only(sgtl5000->regmap, true);
                regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
                                        sgtl5000->supplies);
                break;
@@ -958,17 +972,76 @@ static struct snd_soc_dai_driver sgtl5000_dai = {
        .symmetric_rates = 1,
 };
 
-static int sgtl5000_volatile_register(struct snd_soc_codec *codec,
-                                       unsigned int reg)
+static bool sgtl5000_volatile(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case SGTL5000_CHIP_ID:
        case SGTL5000_CHIP_ADCDAC_CTRL:
        case SGTL5000_CHIP_ANA_STATUS:
-               return 1;
+               return true;
        }
 
-       return 0;
+       return false;
+}
+
+static bool sgtl5000_readable(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case SGTL5000_CHIP_ID:
+       case SGTL5000_CHIP_DIG_POWER:
+       case SGTL5000_CHIP_CLK_CTRL:
+       case SGTL5000_CHIP_I2S_CTRL:
+       case SGTL5000_CHIP_SSS_CTRL:
+       case SGTL5000_CHIP_ADCDAC_CTRL:
+       case SGTL5000_CHIP_DAC_VOL:
+       case SGTL5000_CHIP_PAD_STRENGTH:
+       case SGTL5000_CHIP_ANA_ADC_CTRL:
+       case SGTL5000_CHIP_ANA_HP_CTRL:
+       case SGTL5000_CHIP_ANA_CTRL:
+       case SGTL5000_CHIP_LINREG_CTRL:
+       case SGTL5000_CHIP_REF_CTRL:
+       case SGTL5000_CHIP_MIC_CTRL:
+       case SGTL5000_CHIP_LINE_OUT_CTRL:
+       case SGTL5000_CHIP_LINE_OUT_VOL:
+       case SGTL5000_CHIP_ANA_POWER:
+       case SGTL5000_CHIP_PLL_CTRL:
+       case SGTL5000_CHIP_CLK_TOP_CTRL:
+       case SGTL5000_CHIP_ANA_STATUS:
+       case SGTL5000_CHIP_SHORT_CTRL:
+       case SGTL5000_CHIP_ANA_TEST2:
+       case SGTL5000_DAP_CTRL:
+       case SGTL5000_DAP_PEQ:
+       case SGTL5000_DAP_BASS_ENHANCE:
+       case SGTL5000_DAP_BASS_ENHANCE_CTRL:
+       case SGTL5000_DAP_AUDIO_EQ:
+       case SGTL5000_DAP_SURROUND:
+       case SGTL5000_DAP_FLT_COEF_ACCESS:
+       case SGTL5000_DAP_COEF_WR_B0_MSB:
+       case SGTL5000_DAP_COEF_WR_B0_LSB:
+       case SGTL5000_DAP_EQ_BASS_BAND0:
+       case SGTL5000_DAP_EQ_BASS_BAND1:
+       case SGTL5000_DAP_EQ_BASS_BAND2:
+       case SGTL5000_DAP_EQ_BASS_BAND3:
+       case SGTL5000_DAP_EQ_BASS_BAND4:
+       case SGTL5000_DAP_MAIN_CHAN:
+       case SGTL5000_DAP_MIX_CHAN:
+       case SGTL5000_DAP_AVC_CTRL:
+       case SGTL5000_DAP_AVC_THRESHOLD:
+       case SGTL5000_DAP_AVC_ATTACK:
+       case SGTL5000_DAP_AVC_DECAY:
+       case SGTL5000_DAP_COEF_WR_B1_MSB:
+       case SGTL5000_DAP_COEF_WR_B1_LSB:
+       case SGTL5000_DAP_COEF_WR_B2_MSB:
+       case SGTL5000_DAP_COEF_WR_B2_LSB:
+       case SGTL5000_DAP_COEF_WR_A1_MSB:
+       case SGTL5000_DAP_COEF_WR_A1_LSB:
+       case SGTL5000_DAP_COEF_WR_A2_MSB:
+       case SGTL5000_DAP_COEF_WR_A2_LSB:
+               return true;
+
+       default:
+               return false;
+       }
 }
 
 #ifdef CONFIG_SUSPEND
@@ -1214,7 +1287,7 @@ static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec)
 
 static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
 {
-       u16 reg;
+       int reg;
        int ret;
        int rev;
        int i;
@@ -1242,23 +1315,17 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
        /* wait for all power rails bring up */
        udelay(10);
 
-       /* read chip information */
-       reg = snd_soc_read(codec, SGTL5000_CHIP_ID);
-       if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) !=
-           SGTL5000_PARTID_PART_ID) {
-               dev_err(codec->dev,
-                       "Device with ID register %x is not a sgtl5000\n", reg);
-               ret = -ENODEV;
-               goto err_regulator_disable;
-       }
-
-       rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
-       dev_info(codec->dev, "sgtl5000 revision 0x%x\n", rev);
-
        /*
         * workaround for revision 0x11 and later,
         * roll back to use internal LDO
         */
+
+       ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, &reg);
+       if (ret)
+               goto err_regulator_disable;
+
+       rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
+
        if (external_vddd && rev >= 0x11) {
                /* disable all regulator first */
                regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
@@ -1300,7 +1367,8 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
        struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
        /* setup i2c data ops */
-       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+       codec->control_data = sgtl5000->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
@@ -1391,11 +1459,6 @@ static struct snd_soc_codec_driver sgtl5000_driver = {
        .suspend = sgtl5000_suspend,
        .resume = sgtl5000_resume,
        .set_bias_level = sgtl5000_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(sgtl5000_regs),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_step = 2,
-       .reg_cache_default = sgtl5000_regs,
-       .volatile_register = sgtl5000_volatile_register,
        .controls = sgtl5000_snd_controls,
        .num_controls = ARRAY_SIZE(sgtl5000_snd_controls),
        .dapm_widgets = sgtl5000_dapm_widgets,
@@ -1404,28 +1467,114 @@ static struct snd_soc_codec_driver sgtl5000_driver = {
        .num_dapm_routes = ARRAY_SIZE(sgtl5000_dapm_routes),
 };
 
+static const struct regmap_config sgtl5000_regmap = {
+       .reg_bits = 16,
+       .val_bits = 16,
+
+       .max_register = SGTL5000_MAX_REG_OFFSET,
+       .volatile_reg = sgtl5000_volatile,
+       .readable_reg = sgtl5000_readable,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = sgtl5000_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(sgtl5000_reg_defaults),
+};
+
+/*
+ * Write all the default values from sgtl5000_reg_defaults[] array into the
+ * sgtl5000 registers, to make sure we always start with the sane registers
+ * values as stated in the datasheet.
+ *
+ * Since sgtl5000 does not have a reset line, nor a reset command in software,
+ * we follow this approach to guarantee we always start from the default values
+ * and avoid problems like, not being able to probe after an audio playback
+ * followed by a system reset or a 'reboot' command in Linux
+ */
+static int sgtl5000_fill_defaults(struct sgtl5000_priv *sgtl5000)
+{
+       int i, ret, val, index;
+
+       for (i = 0; i < ARRAY_SIZE(sgtl5000_reg_defaults); i++) {
+               val = sgtl5000_reg_defaults[i].def;
+               index = sgtl5000_reg_defaults[i].reg;
+               ret = regmap_write(sgtl5000->regmap, index, val);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int sgtl5000_i2c_probe(struct i2c_client *client,
                              const struct i2c_device_id *id)
 {
        struct sgtl5000_priv *sgtl5000;
-       int ret;
+       int ret, reg, rev;
 
        sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv),
                                                                GFP_KERNEL);
        if (!sgtl5000)
                return -ENOMEM;
 
+       sgtl5000->regmap = devm_regmap_init_i2c(client, &sgtl5000_regmap);
+       if (IS_ERR(sgtl5000->regmap)) {
+               ret = PTR_ERR(sgtl5000->regmap);
+               dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret);
+               return ret;
+       }
+
+       sgtl5000->mclk = devm_clk_get(&client->dev, NULL);
+       if (IS_ERR(sgtl5000->mclk)) {
+               ret = PTR_ERR(sgtl5000->mclk);
+               dev_err(&client->dev, "Failed to get mclock: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(sgtl5000->mclk);
+       if (ret)
+               return ret;
+
+       /* read chip information */
+       ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, &reg);
+       if (ret)
+               goto disable_clk;
+
+       if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) !=
+           SGTL5000_PARTID_PART_ID) {
+               dev_err(&client->dev,
+                       "Device with ID register %x is not a sgtl5000\n", reg);
+               ret = -ENODEV;
+               goto disable_clk;
+       }
+
+       rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
+       dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
+
        i2c_set_clientdata(client, sgtl5000);
 
+       /* Ensure sgtl5000 will start with sane register values */
+       ret = sgtl5000_fill_defaults(sgtl5000);
+       if (ret)
+               goto disable_clk;
+
        ret = snd_soc_register_codec(&client->dev,
                        &sgtl5000_driver, &sgtl5000_dai, 1);
+       if (ret)
+               goto disable_clk;
+
+       return 0;
+
+disable_clk:
+       clk_disable_unprepare(sgtl5000->mclk);
        return ret;
 }
 
 static int sgtl5000_i2c_remove(struct i2c_client *client)
 {
-       snd_soc_unregister_codec(&client->dev);
+       struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
 
+       snd_soc_unregister_codec(&client->dev);
+       clk_disable_unprepare(sgtl5000->mclk);
        return 0;
 }
 
index 8a9f43534b79569bb69c0ce0b012a74489ca815d..4b69229a9818a789222db312657e008470668392 100644 (file)
@@ -12,7 +12,7 @@
 #define _SGTL5000_H
 
 /*
- * Register values.
+ * Registers addresses
  */
 #define SGTL5000_CHIP_ID                       0x0000
 #define SGTL5000_CHIP_DIG_POWER                        0x0002
index 721587c9cd847ef6a75df55a8099687df939cea6..73e205c892a0d087b4cfc8a6cd0a7de5c26873f3 100644 (file)
@@ -38,9 +38,9 @@ enum si476x_digital_io_output_format {
        SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT     = 8,
 };
 
-#define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK    ((0b111 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \
-                                                 (0b111 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT))
-#define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK   (0b1111110)
+#define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK    ((0x7 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \
+                                                 (0x7 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT))
+#define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK   (0x7e)
 
 enum si476x_daudio_formats {
        SI476X_DAUDIO_MODE_I2S          = (0x0 << 1),
index d1ae869d3181b1ddfc40f6fc8c4be9c67272d583..dba26e63844ef901073531bcdb26b1e084bf0a3b 100644 (file)
@@ -883,7 +883,7 @@ static int sn95031_codec_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-struct snd_soc_codec_driver sn95031_codec = {
+static struct snd_soc_codec_driver sn95031_codec = {
        .probe          = sn95031_codec_probe,
        .remove         = sn95031_codec_remove,
        .read           = sn95031_read,
index dd8d856053fc7730d5ac4f7a7aef625731246486..e9d7881ed2c8272c2c64c7255e60728356aab009 100644 (file)
@@ -21,6 +21,7 @@
 #include <sound/soc.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
+#include <linux/of.h>
 
 #define STUB_RATES     SNDRV_PCM_RATE_8000_192000
 #define STUB_FORMATS   (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -51,12 +52,21 @@ static int spdif_dir_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id spdif_dir_dt_ids[] = {
+       { .compatible = "linux,spdif-dir", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, spdif_dir_dt_ids);
+#endif
+
 static struct platform_driver spdif_dir_driver = {
        .probe          = spdif_dir_probe,
        .remove         = spdif_dir_remove,
        .driver         = {
                .name   = "spdif-dir",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(spdif_dir_dt_ids),
        },
 };
 
similarity index 88%
rename from sound/soc/codecs/spdif_transciever.c
rename to sound/soc/codecs/spdif_transmitter.c
index 112a49d66e3967847517b495872baa606a967189..18280499fd554ee13ca7f9c17d86c8594a40d8bb 100644 (file)
@@ -20,6 +20,7 @@
 #include <sound/soc.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
+#include <linux/of.h>
 
 #define DRV_NAME "spdif-dit"
 
@@ -52,12 +53,21 @@ static int spdif_dit_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id spdif_dit_dt_ids[] = {
+       { .compatible = "linux,spdif-dit", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, spdif_dit_dt_ids);
+#endif
+
 static struct platform_driver spdif_dit_driver = {
        .probe          = spdif_dit_probe,
        .remove         = spdif_dit_remove,
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(spdif_dit_dt_ids),
        },
 };
 
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
new file mode 100644 (file)
index 0000000..95aed55
--- /dev/null
@@ -0,0 +1,856 @@
+/*
+ * SSM2518 amplifier audio driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_data/ssm2518.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "ssm2518.h"
+
+#define SSM2518_REG_POWER1             0x00
+#define SSM2518_REG_CLOCK              0x01
+#define SSM2518_REG_SAI_CTRL1          0x02
+#define SSM2518_REG_SAI_CTRL2          0x03
+#define SSM2518_REG_CHAN_MAP           0x04
+#define SSM2518_REG_LEFT_VOL           0x05
+#define SSM2518_REG_RIGHT_VOL          0x06
+#define SSM2518_REG_MUTE_CTRL          0x07
+#define SSM2518_REG_FAULT_CTRL         0x08
+#define SSM2518_REG_POWER2             0x09
+#define SSM2518_REG_DRC_1              0x0a
+#define SSM2518_REG_DRC_2              0x0b
+#define SSM2518_REG_DRC_3              0x0c
+#define SSM2518_REG_DRC_4              0x0d
+#define SSM2518_REG_DRC_5              0x0e
+#define SSM2518_REG_DRC_6              0x0f
+#define SSM2518_REG_DRC_7              0x10
+#define SSM2518_REG_DRC_8              0x11
+#define SSM2518_REG_DRC_9              0x12
+
+#define SSM2518_POWER1_RESET                   BIT(7)
+#define SSM2518_POWER1_NO_BCLK                 BIT(5)
+#define SSM2518_POWER1_MCS_MASK                        (0xf << 1)
+#define SSM2518_POWER1_MCS_64FS                        (0x0 << 1)
+#define SSM2518_POWER1_MCS_128FS               (0x1 << 1)
+#define SSM2518_POWER1_MCS_256FS               (0x2 << 1)
+#define SSM2518_POWER1_MCS_384FS               (0x3 << 1)
+#define SSM2518_POWER1_MCS_512FS               (0x4 << 1)
+#define SSM2518_POWER1_MCS_768FS               (0x5 << 1)
+#define SSM2518_POWER1_MCS_100FS               (0x6 << 1)
+#define SSM2518_POWER1_MCS_200FS               (0x7 << 1)
+#define SSM2518_POWER1_MCS_400FS               (0x8 << 1)
+#define SSM2518_POWER1_SPWDN                   BIT(0)
+
+#define SSM2518_CLOCK_ASR                      BIT(0)
+
+#define SSM2518_SAI_CTRL1_FMT_MASK             (0x3 << 5)
+#define SSM2518_SAI_CTRL1_FMT_I2S              (0x0 << 5)
+#define SSM2518_SAI_CTRL1_FMT_LJ               (0x1 << 5)
+#define SSM2518_SAI_CTRL1_FMT_RJ_24BIT         (0x2 << 5)
+#define SSM2518_SAI_CTRL1_FMT_RJ_16BIT         (0x3 << 5)
+
+#define SSM2518_SAI_CTRL1_SAI_MASK             (0x7 << 2)
+#define SSM2518_SAI_CTRL1_SAI_I2S              (0x0 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_2            (0x1 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_4            (0x2 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_8            (0x3 << 2)
+#define SSM2518_SAI_CTRL1_SAI_TDM_16           (0x4 << 2)
+#define SSM2518_SAI_CTRL1_SAI_MONO             (0x5 << 2)
+
+#define SSM2518_SAI_CTRL1_FS_MASK              (0x3)
+#define SSM2518_SAI_CTRL1_FS_8000_12000                (0x0)
+#define SSM2518_SAI_CTRL1_FS_16000_24000       (0x1)
+#define SSM2518_SAI_CTRL1_FS_32000_48000       (0x2)
+#define SSM2518_SAI_CTRL1_FS_64000_96000       (0x3)
+
+#define SSM2518_SAI_CTRL2_BCLK_INTERAL         BIT(7)
+#define SSM2518_SAI_CTRL2_LRCLK_PULSE          BIT(6)
+#define SSM2518_SAI_CTRL2_LRCLK_INVERT         BIT(5)
+#define SSM2518_SAI_CTRL2_MSB                  BIT(4)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_MASK      (0x3 << 2)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_32                (0x0 << 2)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_24                (0x1 << 2)
+#define SSM2518_SAI_CTRL2_SLOT_WIDTH_16                (0x2 << 2)
+#define SSM2518_SAI_CTRL2_BCLK_INVERT          BIT(1)
+
+#define SSM2518_CHAN_MAP_RIGHT_SLOT_OFFSET     4
+#define SSM2518_CHAN_MAP_RIGHT_SLOT_MASK       0xf0
+#define SSM2518_CHAN_MAP_LEFT_SLOT_OFFSET      0
+#define SSM2518_CHAN_MAP_LEFT_SLOT_MASK                0x0f
+
+#define SSM2518_MUTE_CTRL_ANA_GAIN             BIT(5)
+#define SSM2518_MUTE_CTRL_MUTE_MASTER          BIT(0)
+
+#define SSM2518_POWER2_APWDN                   BIT(0)
+
+#define SSM2518_DAC_MUTE                       BIT(6)
+#define SSM2518_DAC_FS_MASK                    0x07
+#define SSM2518_DAC_FS_8000                    0x00
+#define SSM2518_DAC_FS_16000                   0x01
+#define SSM2518_DAC_FS_32000                   0x02
+#define SSM2518_DAC_FS_64000                   0x03
+#define SSM2518_DAC_FS_128000                  0x04
+
+struct ssm2518 {
+       struct regmap *regmap;
+       bool right_j;
+
+       unsigned int sysclk;
+       const struct snd_pcm_hw_constraint_list *constraints;
+
+       int enable_gpio;
+};
+
+static const struct reg_default ssm2518_reg_defaults[] = {
+       { 0x00, 0x05 },
+       { 0x01, 0x00 },
+       { 0x02, 0x02 },
+       { 0x03, 0x00 },
+       { 0x04, 0x10 },
+       { 0x05, 0x40 },
+       { 0x06, 0x40 },
+       { 0x07, 0x81 },
+       { 0x08, 0x0c },
+       { 0x09, 0x99 },
+       { 0x0a, 0x7c },
+       { 0x0b, 0x5b },
+       { 0x0c, 0x57 },
+       { 0x0d, 0x89 },
+       { 0x0e, 0x8c },
+       { 0x0f, 0x77 },
+       { 0x10, 0x26 },
+       { 0x11, 0x1c },
+       { 0x12, 0x97 },
+};
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(ssm2518_vol_tlv, -7125, 2400);
+static const DECLARE_TLV_DB_SCALE(ssm2518_compressor_tlv, -3400, 200, 0);
+static const DECLARE_TLV_DB_SCALE(ssm2518_expander_tlv, -8100, 300, 0);
+static const DECLARE_TLV_DB_SCALE(ssm2518_noise_gate_tlv, -9600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(ssm2518_post_drc_tlv, -2400, 300, 0);
+
+static const DECLARE_TLV_DB_RANGE(ssm2518_limiter_tlv,
+       0, 7, TLV_DB_SCALE_ITEM(-2200, 200, 0),
+       7, 15, TLV_DB_SCALE_ITEM(-800, 100, 0),
+);
+
+static const char * const ssm2518_drc_peak_detector_attack_time_text[] = {
+       "0 ms", "0.1 ms", "0.19 ms", "0.37 ms", "0.75 ms", "1.5 ms", "3 ms",
+       "6 ms", "12 ms", "24 ms", "48 ms", "96 ms", "192 ms", "384 ms",
+       "768 ms", "1536 ms",
+};
+
+static const char * const ssm2518_drc_peak_detector_release_time_text[] = {
+       "0 ms", "1.5 ms", "3 ms", "6 ms", "12 ms", "24 ms", "48 ms", "96 ms",
+       "192 ms", "384 ms", "768 ms", "1536 ms", "3072 ms", "6144 ms",
+       "12288 ms", "24576 ms"
+};
+
+static const char * const ssm2518_drc_hold_time_text[] = {
+       "0 ms", "0.67 ms", "1.33 ms", "2.67 ms", "5.33 ms", "10.66 ms",
+       "21.32 ms", "42.64 ms", "85.28 ms", "170.56 ms", "341.12 ms",
+       "682.24 ms", "1364 ms",
+};
+
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum,
+       SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum,
+       SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum,
+       SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum,
+       SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum,
+       SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum,
+       SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text);
+static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum,
+       SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text);
+
+static const struct snd_kcontrol_new ssm2518_snd_controls[] = {
+       SOC_SINGLE("Playback De-emphasis Switch", SSM2518_REG_MUTE_CTRL,
+                       4, 1, 0),
+       SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2518_REG_LEFT_VOL,
+                       SSM2518_REG_RIGHT_VOL, 0, 0xff, 1, ssm2518_vol_tlv),
+       SOC_DOUBLE("Master Playback Switch", SSM2518_REG_MUTE_CTRL, 2, 1, 1, 1),
+
+       SOC_SINGLE("Amp Low Power Mode Switch", SSM2518_REG_POWER2, 4, 1, 0),
+       SOC_SINGLE("DAC Low Power Mode Switch", SSM2518_REG_POWER2, 3, 1, 0),
+
+       SOC_SINGLE("DRC Limiter Switch", SSM2518_REG_DRC_1, 5, 1, 0),
+       SOC_SINGLE("DRC Compressor Switch", SSM2518_REG_DRC_1, 4, 1, 0),
+       SOC_SINGLE("DRC Expander Switch", SSM2518_REG_DRC_1, 3, 1, 0),
+       SOC_SINGLE("DRC Noise Gate Switch", SSM2518_REG_DRC_1, 2, 1, 0),
+       SOC_DOUBLE("DRC Switch", SSM2518_REG_DRC_1, 0, 1, 1, 0),
+
+       SOC_SINGLE_TLV("DRC Limiter Threshold Volume",
+                       SSM2518_REG_DRC_3, 4, 15, 1, ssm2518_limiter_tlv),
+       SOC_SINGLE_TLV("DRC Compressor Lower Threshold Volume",
+                       SSM2518_REG_DRC_3, 0, 15, 1, ssm2518_compressor_tlv),
+       SOC_SINGLE_TLV("DRC Expander Upper Threshold Volume", SSM2518_REG_DRC_4,
+                       4, 15, 1, ssm2518_expander_tlv),
+       SOC_SINGLE_TLV("DRC Noise Gate Threshold Volume",
+                       SSM2518_REG_DRC_4, 0, 15, 1, ssm2518_noise_gate_tlv),
+       SOC_SINGLE_TLV("DRC Upper Output Threshold Volume",
+                       SSM2518_REG_DRC_5, 4, 15, 1, ssm2518_limiter_tlv),
+       SOC_SINGLE_TLV("DRC Lower Output Threshold Volume",
+                       SSM2518_REG_DRC_5, 0, 15, 1, ssm2518_noise_gate_tlv),
+       SOC_SINGLE_TLV("DRC Post Volume", SSM2518_REG_DRC_8,
+                       2, 15, 1, ssm2518_post_drc_tlv),
+
+       SOC_ENUM("DRC Peak Detector Attack Time",
+               ssm2518_drc_peak_detector_attack_time_enum),
+       SOC_ENUM("DRC Peak Detector Release Time",
+               ssm2518_drc_peak_detector_release_time_enum),
+       SOC_ENUM("DRC Attack Time", ssm2518_drc_attack_time_enum),
+       SOC_ENUM("DRC Decay Time", ssm2518_drc_decay_time_enum),
+       SOC_ENUM("DRC Hold Time", ssm2518_drc_hold_time_enum),
+       SOC_ENUM("DRC Noise Gate Hold Time",
+               ssm2518_drc_noise_gate_hold_time_enum),
+       SOC_ENUM("DRC RMS Averaging Time", ssm2518_drc_rms_averaging_time_enum),
+};
+
+static const struct snd_soc_dapm_widget ssm2518_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DACL", "HiFi Playback", SSM2518_REG_POWER2, 1, 1),
+       SND_SOC_DAPM_DAC("DACR", "HiFi Playback", SSM2518_REG_POWER2, 2, 1),
+
+       SND_SOC_DAPM_OUTPUT("OUTL"),
+       SND_SOC_DAPM_OUTPUT("OUTR"),
+};
+
+static const struct snd_soc_dapm_route ssm2518_routes[] = {
+       { "OUTL", NULL, "DACL" },
+       { "OUTR", NULL, "DACR" },
+};
+
+struct ssm2518_mcs_lut {
+       unsigned int rate;
+       const unsigned int *sysclks;
+};
+
+static const unsigned int ssm2518_sysclks_2048000[] = {
+       2048000, 4096000, 8192000, 12288000, 16384000, 24576000,
+       3200000, 6400000, 12800000, 0
+};
+
+static const unsigned int ssm2518_sysclks_2822000[] = {
+       2822000, 5644800, 11289600, 16934400, 22579200, 33868800,
+       4410000, 8820000, 17640000, 0
+};
+
+static const unsigned int ssm2518_sysclks_3072000[] = {
+       3072000, 6144000, 12288000, 16384000, 24576000, 38864000,
+       4800000, 9600000, 19200000, 0
+};
+
+static const struct ssm2518_mcs_lut ssm2518_mcs_lut[] = {
+       { 8000,  ssm2518_sysclks_2048000, },
+       { 11025, ssm2518_sysclks_2822000, },
+       { 12000, ssm2518_sysclks_3072000, },
+       { 16000, ssm2518_sysclks_2048000, },
+       { 24000, ssm2518_sysclks_3072000, },
+       { 22050, ssm2518_sysclks_2822000, },
+       { 32000, ssm2518_sysclks_2048000, },
+       { 44100, ssm2518_sysclks_2822000, },
+       { 48000, ssm2518_sysclks_3072000, },
+       { 96000, ssm2518_sysclks_3072000, },
+};
+
+static const unsigned int ssm2518_rates_2048000[] = {
+       8000, 16000, 32000,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_2048000 = {
+       .list = ssm2518_rates_2048000,
+       .count = ARRAY_SIZE(ssm2518_rates_2048000),
+};
+
+static const unsigned int ssm2518_rates_2822000[] = {
+       11025, 22050, 44100,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_2822000 = {
+       .list = ssm2518_rates_2822000,
+       .count = ARRAY_SIZE(ssm2518_rates_2822000),
+};
+
+static const unsigned int ssm2518_rates_3072000[] = {
+       12000, 24000, 48000, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_3072000 = {
+       .list = ssm2518_rates_3072000,
+       .count = ARRAY_SIZE(ssm2518_rates_3072000),
+};
+
+static const unsigned int ssm2518_rates_12288000[] = {
+       8000, 12000, 16000, 24000, 32000, 48000, 96000,
+};
+
+static const struct snd_pcm_hw_constraint_list ssm2518_constraints_12288000 = {
+       .list = ssm2518_rates_12288000,
+       .count = ARRAY_SIZE(ssm2518_rates_12288000),
+};
+
+static unsigned int ssm2518_lookup_mcs(struct ssm2518 *ssm2518,
+       unsigned int rate)
+{
+       const unsigned int *sysclks = NULL;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ssm2518_mcs_lut); i++) {
+               if (ssm2518_mcs_lut[i].rate == rate) {
+                       sysclks = ssm2518_mcs_lut[i].sysclks;
+                       break;
+               }
+       }
+
+       if (!sysclks)
+               return -EINVAL;
+
+       for (i = 0; sysclks[i]; i++) {
+               if (sysclks[i] == ssm2518->sysclk)
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+static int ssm2518_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+       unsigned int rate = params_rate(params);
+       unsigned int ctrl1, ctrl1_mask;
+       int mcs;
+       int ret;
+
+       mcs = ssm2518_lookup_mcs(ssm2518, rate);
+       if (mcs < 0)
+               return mcs;
+
+       ctrl1_mask = SSM2518_SAI_CTRL1_FS_MASK;
+
+       if (rate >= 8000 && rate <= 12000)
+               ctrl1 = SSM2518_SAI_CTRL1_FS_8000_12000;
+       else if (rate >= 16000 && rate <= 24000)
+               ctrl1 = SSM2518_SAI_CTRL1_FS_16000_24000;
+       else if (rate >= 32000 && rate <= 48000)
+               ctrl1 = SSM2518_SAI_CTRL1_FS_32000_48000;
+       else if (rate >= 64000 && rate <= 96000)
+               ctrl1 = SSM2518_SAI_CTRL1_FS_64000_96000;
+       else
+               return -EINVAL;
+
+       if (ssm2518->right_j) {
+               switch (params_format(params)) {
+               case SNDRV_PCM_FORMAT_S16_LE:
+                       ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_16BIT;
+                       break;
+               case SNDRV_PCM_FORMAT_S24_LE:
+                       ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_24BIT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               ctrl1_mask |= SSM2518_SAI_CTRL1_FMT_MASK;
+       }
+
+       /* Disable auto samplerate detection */
+       ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_CLOCK,
+                               SSM2518_CLOCK_ASR, SSM2518_CLOCK_ASR);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_SAI_CTRL1,
+                               ctrl1_mask, ctrl1);
+       if (ret < 0)
+               return ret;
+
+       return regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+                               SSM2518_POWER1_MCS_MASK, mcs << 1);
+}
+
+static int ssm2518_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int val;
+
+       if (mute)
+               val = SSM2518_MUTE_CTRL_MUTE_MASTER;
+       else
+               val = 0;
+
+       return regmap_update_bits(ssm2518->regmap, SSM2518_REG_MUTE_CTRL,
+                       SSM2518_MUTE_CTRL_MUTE_MASTER, val);
+}
+
+static int ssm2518_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int ctrl1 = 0, ctrl2 = 0;
+       bool invert_fclk;
+       int ret;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               invert_fclk = false;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               ctrl2 |= SSM2518_SAI_CTRL2_BCLK_INVERT;
+               invert_fclk = false;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               invert_fclk = true;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               ctrl2 |= SSM2518_SAI_CTRL2_BCLK_INVERT;
+               invert_fclk = true;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ssm2518->right_j = false;
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               ctrl1 |= SSM2518_SAI_CTRL1_FMT_I2S;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               ctrl1 |= SSM2518_SAI_CTRL1_FMT_LJ;
+               invert_fclk = !invert_fclk;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               ctrl1 |= SSM2518_SAI_CTRL1_FMT_RJ_24BIT;
+               ssm2518->right_j = true;
+               invert_fclk = !invert_fclk;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               ctrl2 |= SSM2518_SAI_CTRL2_LRCLK_PULSE;
+               ctrl1 |= SSM2518_SAI_CTRL1_FMT_I2S;
+               invert_fclk = false;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               ctrl2 |= SSM2518_SAI_CTRL2_LRCLK_PULSE;
+               ctrl1 |= SSM2518_SAI_CTRL1_FMT_LJ;
+               invert_fclk = false;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (invert_fclk)
+               ctrl2 |= SSM2518_SAI_CTRL2_LRCLK_INVERT;
+
+       ret = regmap_write(ssm2518->regmap, SSM2518_REG_SAI_CTRL1, ctrl1);
+       if (ret)
+               return ret;
+
+       return regmap_write(ssm2518->regmap, SSM2518_REG_SAI_CTRL2, ctrl2);
+}
+
+static int ssm2518_set_power(struct ssm2518 *ssm2518, bool enable)
+{
+       int ret = 0;
+
+       if (!enable) {
+               ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+                       SSM2518_POWER1_SPWDN, SSM2518_POWER1_SPWDN);
+               regcache_mark_dirty(ssm2518->regmap);
+       }
+
+       if (gpio_is_valid(ssm2518->enable_gpio))
+               gpio_set_value(ssm2518->enable_gpio, enable);
+
+       regcache_cache_only(ssm2518->regmap, !enable);
+
+       if (enable) {
+               ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+                       SSM2518_POWER1_SPWDN | SSM2518_POWER1_RESET, 0x00);
+               regcache_sync(ssm2518->regmap);
+       }
+
+       return ret;
+}
+
+static int ssm2518_set_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+                       ret = ssm2518_set_power(ssm2518, true);
+               break;
+       case SND_SOC_BIAS_OFF:
+               ret = ssm2518_set_power(ssm2518, false);
+               break;
+       }
+
+       if (ret)
+               return ret;
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+       unsigned int rx_mask, int slots, int width)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int ctrl1, ctrl2;
+       int left_slot, right_slot;
+       int ret;
+
+       if (slots == 0)
+               return regmap_update_bits(ssm2518->regmap,
+                       SSM2518_REG_SAI_CTRL1, SSM2518_SAI_CTRL1_SAI_MASK,
+                       SSM2518_SAI_CTRL1_SAI_I2S);
+
+       if (tx_mask == 0 || rx_mask != 0)
+               return -EINVAL;
+
+       if (slots == 1) {
+               if (tx_mask != 1)
+                       return -EINVAL;
+               left_slot = 0;
+               right_slot = 0;
+       } else {
+               /* We assume the left channel < right channel */
+               left_slot = ffs(tx_mask);
+               tx_mask &= ~(1 << tx_mask);
+               if (tx_mask == 0) {
+                       right_slot = left_slot;
+               } else {
+                       right_slot = ffs(tx_mask);
+                       tx_mask &= ~(1 << tx_mask);
+               }
+       }
+
+       if (tx_mask != 0 || left_slot >= slots || right_slot >= slots)
+               return -EINVAL;
+
+       switch (width) {
+       case 16:
+               ctrl2 = SSM2518_SAI_CTRL2_SLOT_WIDTH_16;
+               break;
+       case 24:
+               ctrl2 = SSM2518_SAI_CTRL2_SLOT_WIDTH_24;
+               break;
+       case 32:
+               ctrl2 = SSM2518_SAI_CTRL2_SLOT_WIDTH_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (slots) {
+       case 1:
+               ctrl1 = SSM2518_SAI_CTRL1_SAI_MONO;
+               break;
+       case 2:
+               ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_2;
+               break;
+       case 4:
+               ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_4;
+               break;
+       case 8:
+               ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_8;
+               break;
+       case 16:
+               ctrl1 = SSM2518_SAI_CTRL1_SAI_TDM_16;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_write(ssm2518->regmap, SSM2518_REG_CHAN_MAP,
+               (left_slot << SSM2518_CHAN_MAP_LEFT_SLOT_OFFSET) |
+               (right_slot << SSM2518_CHAN_MAP_RIGHT_SLOT_OFFSET));
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_SAI_CTRL1,
+               SSM2518_SAI_CTRL1_SAI_MASK, ctrl1);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(ssm2518->regmap, SSM2518_REG_SAI_CTRL2,
+               SSM2518_SAI_CTRL2_SLOT_WIDTH_MASK, ctrl2);
+}
+
+static int ssm2518_startup(struct snd_pcm_substream *substream,
+       struct snd_soc_dai *dai)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(dai->codec);
+
+       if (ssm2518->constraints)
+               snd_pcm_hw_constraint_list(substream->runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE, ssm2518->constraints);
+
+       return 0;
+}
+
+#define SSM2518_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32)
+
+static const struct snd_soc_dai_ops ssm2518_dai_ops = {
+       .startup = ssm2518_startup,
+       .hw_params      = ssm2518_hw_params,
+       .digital_mute   = ssm2518_mute,
+       .set_fmt        = ssm2518_set_dai_fmt,
+       .set_tdm_slot   = ssm2518_set_tdm_slot,
+};
+
+static struct snd_soc_dai_driver ssm2518_dai = {
+       .name = "ssm2518-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SSM2518_FORMATS,
+       },
+       .ops = &ssm2518_dai_ops,
+};
+
+static int ssm2518_probe(struct snd_soc_codec *codec)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       codec->control_data = ssm2518->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static int ssm2518_remove(struct snd_soc_codec *codec)
+{
+       ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+       int source, unsigned int freq, int dir)
+{
+       struct ssm2518 *ssm2518 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val;
+
+       if (clk_id != SSM2518_SYSCLK)
+               return -EINVAL;
+
+       switch (source) {
+       case SSM2518_SYSCLK_SRC_MCLK:
+               val = 0;
+               break;
+       case SSM2518_SYSCLK_SRC_BCLK:
+               /* In this case the bitclock is used as the system clock, and
+                * the bitclock signal needs to be connected to the MCLK pin and
+                * the BCLK pin is left unconnected */
+               val = SSM2518_POWER1_NO_BCLK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (freq) {
+       case 0:
+               ssm2518->constraints = NULL;
+               break;
+       case 2048000:
+       case 4096000:
+       case 8192000:
+       case 3200000:
+       case 6400000:
+       case 12800000:
+               ssm2518->constraints = &ssm2518_constraints_2048000;
+               break;
+       case 2822000:
+       case 5644800:
+       case 11289600:
+       case 16934400:
+       case 22579200:
+       case 33868800:
+       case 4410000:
+       case 8820000:
+       case 17640000:
+               ssm2518->constraints = &ssm2518_constraints_2822000;
+               break;
+       case 3072000:
+       case 6144000:
+       case 38864000:
+       case 4800000:
+       case 9600000:
+       case 19200000:
+               ssm2518->constraints = &ssm2518_constraints_3072000;
+               break;
+       case 12288000:
+       case 16384000:
+       case 24576000:
+               ssm2518->constraints = &ssm2518_constraints_12288000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ssm2518->sysclk = freq;
+
+       return regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER1,
+                       SSM2518_POWER1_NO_BCLK, val);
+}
+
+static struct snd_soc_codec_driver ssm2518_codec_driver = {
+       .probe = ssm2518_probe,
+       .remove = ssm2518_remove,
+       .set_bias_level = ssm2518_set_bias_level,
+       .set_sysclk = ssm2518_set_sysclk,
+       .idle_bias_off = true,
+
+       .controls = ssm2518_snd_controls,
+       .num_controls = ARRAY_SIZE(ssm2518_snd_controls),
+       .dapm_widgets = ssm2518_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ssm2518_dapm_widgets),
+       .dapm_routes = ssm2518_routes,
+       .num_dapm_routes = ARRAY_SIZE(ssm2518_routes),
+};
+
+static bool ssm2518_register_volatile(struct device *dev, unsigned int reg)
+{
+       return false;
+}
+
+static const struct regmap_config ssm2518_regmap_config = {
+       .val_bits = 8,
+       .reg_bits = 8,
+
+       .max_register = SSM2518_REG_DRC_9,
+       .volatile_reg = ssm2518_register_volatile,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = ssm2518_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(ssm2518_reg_defaults),
+};
+
+static int ssm2518_i2c_probe(struct i2c_client *i2c,
+       const struct i2c_device_id *id)
+{
+       struct ssm2518_platform_data *pdata = i2c->dev.platform_data;
+       struct ssm2518 *ssm2518;
+       int ret;
+
+       ssm2518 = devm_kzalloc(&i2c->dev, sizeof(*ssm2518), GFP_KERNEL);
+       if (ssm2518 == NULL)
+               return -ENOMEM;
+
+       if (pdata) {
+               ssm2518->enable_gpio = pdata->enable_gpio;
+       } else if (i2c->dev.of_node) {
+               ssm2518->enable_gpio = of_get_gpio(i2c->dev.of_node, 0);
+               if (ssm2518->enable_gpio < 0 && ssm2518->enable_gpio != -ENOENT)
+                       return ssm2518->enable_gpio;
+       } else {
+               ssm2518->enable_gpio = -1;
+       }
+
+       if (gpio_is_valid(ssm2518->enable_gpio)) {
+               ret = devm_gpio_request_one(&i2c->dev, ssm2518->enable_gpio,
+                               GPIOF_OUT_INIT_HIGH, "SSM2518 nSD");
+               if (ret)
+                       return ret;
+       }
+
+       i2c_set_clientdata(i2c, ssm2518);
+
+       ssm2518->regmap = devm_regmap_init_i2c(i2c, &ssm2518_regmap_config);
+       if (IS_ERR(ssm2518->regmap))
+               return PTR_ERR(ssm2518->regmap);
+
+       /*
+        * The reset bit is obviously volatile, but we need to be able to cache
+        * the other bits in the register, so we can't just mark the whole
+        * register as volatile. Since this is the only place where we'll ever
+        * touch the reset bit just bypass the cache for this operation.
+        */
+       regcache_cache_bypass(ssm2518->regmap, true);
+       ret = regmap_write(ssm2518->regmap, SSM2518_REG_POWER1,
+                       SSM2518_POWER1_RESET);
+       regcache_cache_bypass(ssm2518->regmap, false);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(ssm2518->regmap, SSM2518_REG_POWER2,
+                               SSM2518_POWER2_APWDN, 0x00);
+       if (ret)
+               return ret;
+
+       ret = ssm2518_set_power(ssm2518, false);
+       if (ret)
+               return ret;
+
+       return snd_soc_register_codec(&i2c->dev, &ssm2518_codec_driver,
+                       &ssm2518_dai, 1);
+}
+
+static int ssm2518_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id ssm2518_i2c_ids[] = {
+       { "ssm2518", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids);
+
+static struct i2c_driver ssm2518_driver = {
+       .driver = {
+               .name = "ssm2518",
+               .owner = THIS_MODULE,
+       },
+       .probe = ssm2518_i2c_probe,
+       .remove = ssm2518_i2c_remove,
+       .id_table = ssm2518_i2c_ids,
+};
+module_i2c_driver(ssm2518_driver);
+
+MODULE_DESCRIPTION("ASoC SSM2518 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ssm2518.h b/sound/soc/codecs/ssm2518.h
new file mode 100644 (file)
index 0000000..62511d8
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * SSM2518 amplifier audio driver
+ *
+ * Copyright 2013 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __SND_SOC_CODECS_SSM2518_H__
+#define __SND_SOC_CODECS_SSM2518_H__
+
+#define SSM2518_SYSCLK 0
+
+enum ssm2518_sysclk_src {
+       SSM2518_SYSCLK_SRC_MCLK = 0,
+       SSM2518_SYSCLK_SRC_BCLK = 1,
+};
+
+#endif
index 2eda85ba79acd2cdd442b78fa4631542f0caffdd..a5455c1aea421daee730c56b1c0e4b1a3d2ce575 100644 (file)
@@ -28,8 +28,6 @@
 
 #include "stac9766.h"
 
-#define STAC9766_VERSION "0.10"
-
 /*
  * STAC9766 register cache
  */
@@ -145,14 +143,14 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 
        if (reg > AC97_STAC_PAGE0) {
                stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
-               soc_ac97_ops.write(codec->ac97, reg, val);
+               soc_ac97_ops->write(codec->ac97, reg, val);
                stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
                return 0;
        }
        if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
                return -EIO;
 
-       soc_ac97_ops.write(codec->ac97, reg, val);
+       soc_ac97_ops->write(codec->ac97, reg, val);
        cache[reg / 2] = val;
        return 0;
 }
@@ -164,7 +162,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
 
        if (reg > AC97_STAC_PAGE0) {
                stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
-               val = soc_ac97_ops.read(codec->ac97, reg - AC97_STAC_PAGE0);
+               val = soc_ac97_ops->read(codec->ac97, reg - AC97_STAC_PAGE0);
                stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
                return val;
        }
@@ -175,7 +173,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
                reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 ||
                reg == AC97_VENDOR_ID2) {
 
-               val = soc_ac97_ops.read(codec->ac97, reg);
+               val = soc_ac97_ops->read(codec->ac97, reg);
                return val;
        }
        return cache[reg / 2];
@@ -242,15 +240,15 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
 
 static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
 {
-       if (try_warm && soc_ac97_ops.warm_reset) {
-               soc_ac97_ops.warm_reset(codec->ac97);
+       if (try_warm && soc_ac97_ops->warm_reset) {
+               soc_ac97_ops->warm_reset(codec->ac97);
                if (stac9766_ac97_read(codec, 0) == stac9766_reg[0])
                        return 1;
        }
 
-       soc_ac97_ops.reset(codec->ac97);
-       if (soc_ac97_ops.warm_reset)
-               soc_ac97_ops.warm_reset(codec->ac97);
+       soc_ac97_ops->reset(codec->ac97);
+       if (soc_ac97_ops->warm_reset)
+               soc_ac97_ops->warm_reset(codec->ac97);
        if (stac9766_ac97_read(codec, 0) != stac9766_reg[0])
                return -EIO;
        return 0;
@@ -274,7 +272,7 @@ reset:
                return -EIO;
        }
        codec->ac97->bus->ops->warm_reset(codec->ac97);
-       id = soc_ac97_ops.read(codec->ac97, AC97_VENDOR_ID2);
+       id = soc_ac97_ops->read(codec->ac97, AC97_VENDOR_ID2);
        if (id != 0x4c13) {
                stac9766_reset(codec, 0);
                reset++;
@@ -338,9 +336,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec)
 {
        int ret = 0;
 
-       printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
-
-       ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+       ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
        if (ret < 0)
                goto codec_err;
 
index d447c4aa1d5eb64bc06ee76f8d5c8aa2b752205a..6d31d88f72040098700a1b57ef3f4d118976a604 100644 (file)
 #define TAS5086_SPLIT_CAP_CHARGE       0x1a    /* Split cap charge period register */
 #define TAS5086_OSC_TRIM               0x1b    /* Oscillator trim register */
 #define TAS5086_BKNDERR                0x1c
+#define TAS5086_INPUT_MUX              0x20
+#define TAS5086_PWM_OUTPUT_MUX         0x25
+
+#define TAS5086_MAX_REGISTER           TAS5086_PWM_OUTPUT_MUX
+
+#define TAS5086_PWM_START_MIDZ_FOR_START_1     (1 << 7)
+#define TAS5086_PWM_START_MIDZ_FOR_START_2     (1 << 6)
+#define TAS5086_PWM_START_CHANNEL_MASK         (0x3f)
 
 /*
  * Default TAS5086 power-up configuration
@@ -119,9 +127,30 @@ static const struct reg_default tas5086_reg_defaults[] = {
        { 0x1c, 0x05 },
 };
 
+static int tas5086_register_size(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TAS5086_CLOCK_CONTROL ... TAS5086_BKNDERR:
+               return 1;
+       case TAS5086_INPUT_MUX:
+       case TAS5086_PWM_OUTPUT_MUX:
+               return 4;
+       }
+
+       dev_err(dev, "Unsupported register address: %d\n", reg);
+       return 0;
+}
+
 static bool tas5086_accessible_reg(struct device *dev, unsigned int reg)
 {
-       return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17));
+       switch (reg) {
+       case 0x0f:
+       case 0x11 ... 0x17:
+       case 0x1d ... 0x1f:
+               return false;
+       default:
+               return true;
+       }
 }
 
 static bool tas5086_volatile_reg(struct device *dev, unsigned int reg)
@@ -140,6 +169,76 @@ static bool tas5086_writeable_reg(struct device *dev, unsigned int reg)
        return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID);
 }
 
+static int tas5086_reg_write(void *context, unsigned int reg,
+                             unsigned int value)
+{
+       struct i2c_client *client = context;
+       unsigned int i, size;
+       uint8_t buf[5];
+       int ret;
+
+       size = tas5086_register_size(&client->dev, reg);
+       if (size == 0)
+               return -EINVAL;
+
+       buf[0] = reg;
+
+       for (i = size; i >= 1; --i) {
+               buf[i] = value;
+               value >>= 8;
+       }
+
+       ret = i2c_master_send(client, buf, size + 1);
+       if (ret == size + 1)
+               return 0;
+       else if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+
+static int tas5086_reg_read(void *context, unsigned int reg,
+                            unsigned int *value)
+{
+       struct i2c_client *client = context;
+       uint8_t send_buf, recv_buf[4];
+       struct i2c_msg msgs[2];
+       unsigned int size;
+       unsigned int i;
+       int ret;
+
+       size = tas5086_register_size(&client->dev, reg);
+       if (size == 0)
+               return -EINVAL;
+
+       send_buf = reg;
+
+       msgs[0].addr = client->addr;
+       msgs[0].len = sizeof(send_buf);
+       msgs[0].buf = &send_buf;
+       msgs[0].flags = 0;
+
+       msgs[1].addr = client->addr;
+       msgs[1].len = size;
+       msgs[1].buf = recv_buf;
+       msgs[1].flags = I2C_M_RD;
+
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret < 0)
+               return ret;
+       else if (ret != ARRAY_SIZE(msgs))
+               return -EIO;
+
+       *value = 0;
+
+       for (i = 0; i < size; i++) {
+               *value <<= 8;
+               *value |= recv_buf[i];
+       }
+
+       return 0;
+}
+
 struct tas5086_private {
        struct regmap   *regmap;
        unsigned int    mclk, sclk;
@@ -376,6 +475,202 @@ static const struct snd_kcontrol_new tas5086_controls[] = {
                            tas5086_get_deemph, tas5086_put_deemph),
 };
 
+/* Input mux controls */
+static const char *tas5086_dapm_sdin_texts[] =
+{
+       "SDIN1-L", "SDIN1-R", "SDIN2-L", "SDIN2-R",
+       "SDIN3-L", "SDIN3-R", "Ground (0)", "nc"
+};
+
+static const struct soc_enum tas5086_dapm_input_mux_enum[] = {
+       SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 20, 8, tas5086_dapm_sdin_texts),
+       SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 16, 8, tas5086_dapm_sdin_texts),
+       SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 12, 8, tas5086_dapm_sdin_texts),
+       SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 8,  8, tas5086_dapm_sdin_texts),
+       SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 4,  8, tas5086_dapm_sdin_texts),
+       SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 0,  8, tas5086_dapm_sdin_texts),
+};
+
+static const struct snd_kcontrol_new tas5086_dapm_input_mux_controls[] = {
+       SOC_DAPM_ENUM("Channel 1 input", tas5086_dapm_input_mux_enum[0]),
+       SOC_DAPM_ENUM("Channel 2 input", tas5086_dapm_input_mux_enum[1]),
+       SOC_DAPM_ENUM("Channel 3 input", tas5086_dapm_input_mux_enum[2]),
+       SOC_DAPM_ENUM("Channel 4 input", tas5086_dapm_input_mux_enum[3]),
+       SOC_DAPM_ENUM("Channel 5 input", tas5086_dapm_input_mux_enum[4]),
+       SOC_DAPM_ENUM("Channel 6 input", tas5086_dapm_input_mux_enum[5]),
+};
+
+/* Output mux controls */
+static const char *tas5086_dapm_channel_texts[] =
+       { "Channel 1 Mux", "Channel 2 Mux", "Channel 3 Mux",
+         "Channel 4 Mux", "Channel 5 Mux", "Channel 6 Mux" };
+
+static const struct soc_enum tas5086_dapm_output_mux_enum[] = {
+       SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 20, 6, tas5086_dapm_channel_texts),
+       SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 16, 6, tas5086_dapm_channel_texts),
+       SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 12, 6, tas5086_dapm_channel_texts),
+       SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 8,  6, tas5086_dapm_channel_texts),
+       SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 4,  6, tas5086_dapm_channel_texts),
+       SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 0,  6, tas5086_dapm_channel_texts),
+};
+
+static const struct snd_kcontrol_new tas5086_dapm_output_mux_controls[] = {
+       SOC_DAPM_ENUM("PWM1 Output", tas5086_dapm_output_mux_enum[0]),
+       SOC_DAPM_ENUM("PWM2 Output", tas5086_dapm_output_mux_enum[1]),
+       SOC_DAPM_ENUM("PWM3 Output", tas5086_dapm_output_mux_enum[2]),
+       SOC_DAPM_ENUM("PWM4 Output", tas5086_dapm_output_mux_enum[3]),
+       SOC_DAPM_ENUM("PWM5 Output", tas5086_dapm_output_mux_enum[4]),
+       SOC_DAPM_ENUM("PWM6 Output", tas5086_dapm_output_mux_enum[5]),
+};
+
+static const struct snd_soc_dapm_widget tas5086_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("SDIN1-L"),
+       SND_SOC_DAPM_INPUT("SDIN1-R"),
+       SND_SOC_DAPM_INPUT("SDIN2-L"),
+       SND_SOC_DAPM_INPUT("SDIN2-R"),
+       SND_SOC_DAPM_INPUT("SDIN3-L"),
+       SND_SOC_DAPM_INPUT("SDIN3-R"),
+       SND_SOC_DAPM_INPUT("SDIN4-L"),
+       SND_SOC_DAPM_INPUT("SDIN4-R"),
+
+       SND_SOC_DAPM_OUTPUT("PWM1"),
+       SND_SOC_DAPM_OUTPUT("PWM2"),
+       SND_SOC_DAPM_OUTPUT("PWM3"),
+       SND_SOC_DAPM_OUTPUT("PWM4"),
+       SND_SOC_DAPM_OUTPUT("PWM5"),
+       SND_SOC_DAPM_OUTPUT("PWM6"),
+
+       SND_SOC_DAPM_MUX("Channel 1 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_input_mux_controls[0]),
+       SND_SOC_DAPM_MUX("Channel 2 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_input_mux_controls[1]),
+       SND_SOC_DAPM_MUX("Channel 3 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_input_mux_controls[2]),
+       SND_SOC_DAPM_MUX("Channel 4 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_input_mux_controls[3]),
+       SND_SOC_DAPM_MUX("Channel 5 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_input_mux_controls[4]),
+       SND_SOC_DAPM_MUX("Channel 6 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_input_mux_controls[5]),
+
+       SND_SOC_DAPM_MUX("PWM1 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_output_mux_controls[0]),
+       SND_SOC_DAPM_MUX("PWM2 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_output_mux_controls[1]),
+       SND_SOC_DAPM_MUX("PWM3 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_output_mux_controls[2]),
+       SND_SOC_DAPM_MUX("PWM4 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_output_mux_controls[3]),
+       SND_SOC_DAPM_MUX("PWM5 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_output_mux_controls[4]),
+       SND_SOC_DAPM_MUX("PWM6 Mux", SND_SOC_NOPM, 0, 0,
+                        &tas5086_dapm_output_mux_controls[5]),
+};
+
+static const struct snd_soc_dapm_route tas5086_dapm_routes[] = {
+       /* SDIN inputs -> channel muxes */
+       { "Channel 1 Mux", "SDIN1-L", "SDIN1-L" },
+       { "Channel 1 Mux", "SDIN1-R", "SDIN1-R" },
+       { "Channel 1 Mux", "SDIN2-L", "SDIN2-L" },
+       { "Channel 1 Mux", "SDIN2-R", "SDIN2-R" },
+       { "Channel 1 Mux", "SDIN3-L", "SDIN3-L" },
+       { "Channel 1 Mux", "SDIN3-R", "SDIN3-R" },
+
+       { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" },
+       { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" },
+       { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" },
+       { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" },
+       { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" },
+       { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" },
+
+       { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" },
+       { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" },
+       { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" },
+       { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" },
+       { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" },
+       { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" },
+
+       { "Channel 3 Mux", "SDIN1-L", "SDIN1-L" },
+       { "Channel 3 Mux", "SDIN1-R", "SDIN1-R" },
+       { "Channel 3 Mux", "SDIN2-L", "SDIN2-L" },
+       { "Channel 3 Mux", "SDIN2-R", "SDIN2-R" },
+       { "Channel 3 Mux", "SDIN3-L", "SDIN3-L" },
+       { "Channel 3 Mux", "SDIN3-R", "SDIN3-R" },
+
+       { "Channel 4 Mux", "SDIN1-L", "SDIN1-L" },
+       { "Channel 4 Mux", "SDIN1-R", "SDIN1-R" },
+       { "Channel 4 Mux", "SDIN2-L", "SDIN2-L" },
+       { "Channel 4 Mux", "SDIN2-R", "SDIN2-R" },
+       { "Channel 4 Mux", "SDIN3-L", "SDIN3-L" },
+       { "Channel 4 Mux", "SDIN3-R", "SDIN3-R" },
+
+       { "Channel 5 Mux", "SDIN1-L", "SDIN1-L" },
+       { "Channel 5 Mux", "SDIN1-R", "SDIN1-R" },
+       { "Channel 5 Mux", "SDIN2-L", "SDIN2-L" },
+       { "Channel 5 Mux", "SDIN2-R", "SDIN2-R" },
+       { "Channel 5 Mux", "SDIN3-L", "SDIN3-L" },
+       { "Channel 5 Mux", "SDIN3-R", "SDIN3-R" },
+
+       { "Channel 6 Mux", "SDIN1-L", "SDIN1-L" },
+       { "Channel 6 Mux", "SDIN1-R", "SDIN1-R" },
+       { "Channel 6 Mux", "SDIN2-L", "SDIN2-L" },
+       { "Channel 6 Mux", "SDIN2-R", "SDIN2-R" },
+       { "Channel 6 Mux", "SDIN3-L", "SDIN3-L" },
+       { "Channel 6 Mux", "SDIN3-R", "SDIN3-R" },
+
+       /* Channel muxes -> PWM muxes */
+       { "PWM1 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+       { "PWM2 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+       { "PWM3 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+       { "PWM4 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+       { "PWM5 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+       { "PWM6 Mux", "Channel 1 Mux", "Channel 1 Mux" },
+
+       { "PWM1 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+       { "PWM2 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+       { "PWM3 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+       { "PWM4 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+       { "PWM5 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+       { "PWM6 Mux", "Channel 2 Mux", "Channel 2 Mux" },
+
+       { "PWM1 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+       { "PWM2 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+       { "PWM3 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+       { "PWM4 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+       { "PWM5 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+       { "PWM6 Mux", "Channel 3 Mux", "Channel 3 Mux" },
+
+       { "PWM1 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+       { "PWM2 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+       { "PWM3 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+       { "PWM4 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+       { "PWM5 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+       { "PWM6 Mux", "Channel 4 Mux", "Channel 4 Mux" },
+
+       { "PWM1 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+       { "PWM2 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+       { "PWM3 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+       { "PWM4 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+       { "PWM5 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+       { "PWM6 Mux", "Channel 5 Mux", "Channel 5 Mux" },
+
+       { "PWM1 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+       { "PWM2 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+       { "PWM3 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+       { "PWM4 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+       { "PWM5 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+       { "PWM6 Mux", "Channel 6 Mux", "Channel 6 Mux" },
+
+       /* The PWM muxes are directly connected to the PWM outputs */
+       { "PWM1", NULL, "PWM1 Mux" },
+       { "PWM2", NULL, "PWM2 Mux" },
+       { "PWM3", NULL, "PWM3 Mux" },
+       { "PWM4", NULL, "PWM4 Mux" },
+       { "PWM5", NULL, "PWM5 Mux" },
+       { "PWM6", NULL, "PWM6 Mux" },
+
+};
+
 static const struct snd_soc_dai_ops tas5086_dai_ops = {
        .hw_params      = tas5086_hw_params,
        .set_sysclk     = tas5086_set_dai_sysclk,
@@ -426,13 +721,34 @@ static int tas5086_probe(struct snd_soc_codec *codec)
 {
        struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
        int charge_period = 1300000; /* hardware default is 1300 ms */
+       u8 pwm_start_mid_z = 0;
        int i, ret;
 
        if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
                struct device_node *of_node = codec->dev->of_node;
                of_property_read_u32(of_node, "ti,charge-period", &charge_period);
+
+               for (i = 0; i < 6; i++) {
+                       char name[25];
+
+                       snprintf(name, sizeof(name),
+                                "ti,mid-z-channel-%d", i + 1);
+
+                       if (of_get_property(of_node, name, NULL) != NULL)
+                               pwm_start_mid_z |= 1 << i;
+               }
        }
 
+       /*
+        * If any of the channels is configured to start in Mid-Z mode,
+        * configure 'part 1' of the PWM starts to use Mid-Z, and tell
+        * all configured mid-z channels to start start under 'part 1'.
+        */
+       if (pwm_start_mid_z)
+               regmap_write(priv->regmap, TAS5086_PWM_START,
+                            TAS5086_PWM_START_MIDZ_FOR_START_1 |
+                               pwm_start_mid_z);
+
        /* lookup and set split-capacitor charge period */
        if (charge_period == 0) {
                regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
@@ -490,6 +806,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
        .resume                 = tas5086_soc_resume,
        .controls               = tas5086_controls,
        .num_controls           = ARRAY_SIZE(tas5086_controls),
+       .dapm_widgets           = tas5086_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(tas5086_dapm_widgets),
+       .dapm_routes            = tas5086_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(tas5086_dapm_routes),
 };
 
 static const struct i2c_device_id tas5086_i2c_id[] = {
@@ -500,14 +820,16 @@ MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id);
 
 static const struct regmap_config tas5086_regmap = {
        .reg_bits               = 8,
-       .val_bits               = 8,
-       .max_register           = ARRAY_SIZE(tas5086_reg_defaults),
+       .val_bits               = 32,
+       .max_register           = TAS5086_MAX_REGISTER,
        .reg_defaults           = tas5086_reg_defaults,
        .num_reg_defaults       = ARRAY_SIZE(tas5086_reg_defaults),
        .cache_type             = REGCACHE_RBTREE,
        .volatile_reg           = tas5086_volatile_reg,
        .writeable_reg          = tas5086_writeable_reg,
        .readable_reg           = tas5086_accessible_reg,
+       .reg_read               = tas5086_reg_read,
+       .reg_write              = tas5086_reg_write,
 };
 
 static int tas5086_i2c_probe(struct i2c_client *i2c,
@@ -522,7 +844,7 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,
        if (!priv)
                return -ENOMEM;
 
-       priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap);
+       priv->regmap = devm_regmap_init(dev, NULL, i2c, &tas5086_regmap);
        if (IS_ERR(priv->regmap)) {
                ret = PTR_ERR(priv->regmap);
                dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
index 1514bf845e4b1e6e5e8ab37b7400632d5d60f3ad..e5b926883131180c71cfe6239d1bca3be8fcf674 100644 (file)
@@ -128,10 +128,8 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
 };
 
 #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_volsw, \
-       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw_aic3x, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, mask, invert) }
+       SOC_SINGLE_EXT(xname, reg, shift, mask, invert, \
+               snd_soc_dapm_get_volsw, snd_soc_dapm_put_volsw_aic3x)
 
 /*
  * All input lines are connected when !0xf and disconnected with 0xf bit field,
index 9b9a6e587610540c310c39387791f588592e1a4c..44621ddc332d881b5e4b05a58507060259446e55 100644 (file)
 
 #include "twl6040.h"
 
+enum twl6040_dai_id {
+       TWL6040_DAI_LEGACY = 0,
+       TWL6040_DAI_UL,
+       TWL6040_DAI_DL1,
+       TWL6040_DAI_DL2,
+       TWL6040_DAI_VIB,
+};
+
 #define TWL6040_RATES          SNDRV_PCM_RATE_8000_96000
 #define TWL6040_FORMATS        (SNDRV_PCM_FMTBIT_S32_LE)
 
@@ -67,6 +75,8 @@ struct twl6040_data {
        int pll_power_mode;
        int hs_power_mode;
        int hs_power_mode_locked;
+       bool dl1_unmuted;
+       bool dl2_unmuted;
        unsigned int clk_in;
        unsigned int sysclk;
        struct twl6040_jack_data hs_jack;
@@ -220,6 +230,25 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
        return value;
 }
 
+static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+       switch (reg) {
+       case TWL6040_REG_HSLCTL:
+       case TWL6040_REG_HSRCTL:
+       case TWL6040_REG_EARCTL:
+               /* DL1 path */
+               return priv->dl1_unmuted;
+       case TWL6040_REG_HFLCTL:
+       case TWL6040_REG_HFRCTL:
+               return priv->dl2_unmuted;
+       default:
+               return 1;
+       };
+}
+
 /*
  * write to the twl6040 register space
  */
@@ -232,7 +261,8 @@ static int twl6040_write(struct snd_soc_codec *codec,
                return -EIO;
 
        twl6040_write_reg_cache(codec, reg, value);
-       if (likely(reg < TWL6040_REG_SW_SHADOW))
+       if (likely(reg < TWL6040_REG_SW_SHADOW) &&
+           twl6040_is_path_unmuted(codec, reg))
                return twl6040_reg_write(twl6040, reg, value);
        else
                return 0;
@@ -1026,16 +1056,84 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id id,
+                            int mute)
+{
+       struct twl6040 *twl6040 = codec->control_data;
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       int hslctl, hsrctl, earctl;
+       int hflctl, hfrctl;
+
+       switch (id) {
+       case TWL6040_DAI_DL1:
+               hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
+               hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
+               earctl = twl6040_read_reg_cache(codec, TWL6040_REG_EARCTL);
+
+               if (mute) {
+                       /* Power down drivers and DACs */
+                       earctl &= ~0x01;
+                       hslctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA);
+                       hsrctl &= ~(TWL6040_HSDRVENA | TWL6040_HSDACENA);
+
+               }
+
+               twl6040_reg_write(twl6040, TWL6040_REG_EARCTL, earctl);
+               twl6040_reg_write(twl6040, TWL6040_REG_HSLCTL, hslctl);
+               twl6040_reg_write(twl6040, TWL6040_REG_HSRCTL, hsrctl);
+               priv->dl1_unmuted = !mute;
+               break;
+       case TWL6040_DAI_DL2:
+               hflctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFLCTL);
+               hfrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFRCTL);
+
+               if (mute) {
+                       /* Power down drivers and DACs */
+                       hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
+                                   TWL6040_HFDRVENA);
+                       hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA |
+                                   TWL6040_HFDRVENA);
+               }
+
+               twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl);
+               twl6040_reg_write(twl6040, TWL6040_REG_HFRCTL, hfrctl);
+               priv->dl2_unmuted = !mute;
+               break;
+       default:
+               break;
+       };
+}
+
+static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       switch (dai->id) {
+       case TWL6040_DAI_LEGACY:
+               twl6040_mute_path(dai->codec, TWL6040_DAI_DL1, mute);
+               twl6040_mute_path(dai->codec, TWL6040_DAI_DL2, mute);
+               break;
+       case TWL6040_DAI_DL1:
+       case TWL6040_DAI_DL2:
+               twl6040_mute_path(dai->codec, dai->id, mute);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 static const struct snd_soc_dai_ops twl6040_dai_ops = {
        .startup        = twl6040_startup,
        .hw_params      = twl6040_hw_params,
        .prepare        = twl6040_prepare,
        .set_sysclk     = twl6040_set_dai_sysclk,
+       .digital_mute   = twl6040_digital_mute,
 };
 
 static struct snd_soc_dai_driver twl6040_dai[] = {
 {
        .name = "twl6040-legacy",
+       .id = TWL6040_DAI_LEGACY,
        .playback = {
                .stream_name = "Legacy Playback",
                .channels_min = 1,
@@ -1054,6 +1152,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
 },
 {
        .name = "twl6040-ul",
+       .id = TWL6040_DAI_UL,
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
@@ -1065,6 +1164,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
 },
 {
        .name = "twl6040-dl1",
+       .id = TWL6040_DAI_DL1,
        .playback = {
                .stream_name = "Headset Playback",
                .channels_min = 1,
@@ -1076,6 +1176,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
 },
 {
        .name = "twl6040-dl2",
+       .id = TWL6040_DAI_DL2,
        .playback = {
                .stream_name = "Handsfree Playback",
                .channels_min = 1,
@@ -1087,6 +1188,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
 },
 {
        .name = "twl6040-vib",
+       .id = TWL6040_DAI_VIB,
        .playback = {
                .stream_name = "Vibra Playback",
                .channels_min = 1,
@@ -1143,7 +1245,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
 
        mutex_init(&priv->mutex);
 
-       ret = devm_request_threaded_irq(codec->dev, priv->plug_irq, NULL,
+       ret = request_threaded_irq(priv->plug_irq, NULL,
                                        twl6040_audio_handler, IRQF_NO_SUSPEND,
                                        "twl6040_irq_plug", codec);
        if (ret) {
@@ -1159,6 +1261,9 @@ static int twl6040_probe(struct snd_soc_codec *codec)
 
 static int twl6040_remove(struct snd_soc_codec *codec)
 {
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+       free_irq(priv->plug_irq, codec);
        twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
index 370af0cbcc9a97393c695a55936fb22b6ec6e103..f5e835662cdca30477738e39ffe7d57f6305db78 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/interrupt.h>
 #include <linux/irqreturn.h>
 #include <linux/init.h>
 #include <linux/spi/spi.h>
@@ -972,6 +973,13 @@ static int wm0010_spi_probe(struct spi_device *spi)
        }
        wm0010->irq = irq;
 
+       ret = irq_set_irq_wake(irq, 1);
+       if (ret) {
+               dev_err(wm0010->dev, "Failed to set IRQ %d as wake source: %d\n",
+                       irq, ret);
+               return ret;
+       }
+
        if (spi->max_speed_hz)
                wm0010->board_max_spi_speed = spi->max_speed_hz;
        else
@@ -995,6 +1003,8 @@ static int wm0010_spi_remove(struct spi_device *spi)
        gpio_set_value_cansleep(wm0010->gpio_reset,
                                wm0010->gpio_reset_value);
 
+       irq_set_irq_wake(wm0010->irq, 0);
+
        if (wm0010->irq)
                free_irq(wm0010->irq, wm0010);
 
index 100fdadda56a7e99f6d98874da5c3a89a923815a..282fd232cdf7cf62ce6d836578e3c518cd839d59 100644 (file)
@@ -814,7 +814,20 @@ SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
 
 SOC_VALUE_ENUM("HPOUT1 OSR", wm5102_hpout_osr[0]),
 SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
-SOC_VALUE_ENUM("HPOUT3 OSR", wm5102_hpout_osr[2]),
+SOC_VALUE_ENUM("EPOUT OSR", wm5102_hpout_osr[2]),
+
+SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
+          ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0),
+SOC_DOUBLE("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
+          ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0),
+SOC_SINGLE("EPOUT DRE Switch", ARIZONA_DRE_ENABLE,
+          ARIZONA_DRE3L_ENA_SHIFT, 1, 0),
+
+SOC_SINGLE("DRE Threshold", ARIZONA_DRE_CONTROL_2,
+          ARIZONA_DRE_T_LOW_SHIFT, 63, 0),
+
+SOC_SINGLE("DRE Low Level ABS", ARIZONA_DRE_CONTROL_3,
+          ARIZONA_DRE_LOW_LEVEL_ABS_SHIFT, 15, 0),
 
 SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
 SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
@@ -852,6 +865,15 @@ ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
 
 ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
 };
 
 ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
@@ -898,6 +920,15 @@ ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
 
+ARIZONA_MIXER_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX7, ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX8, ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE);
+
 ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
 ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
 ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
@@ -1117,6 +1148,56 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
 SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
                    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
 
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX8_ENA_SHIFT, 0),
+
 ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
 
 SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
@@ -1189,6 +1270,15 @@ ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
 ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
 ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
 
+ARIZONA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"),
+ARIZONA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"),
+ARIZONA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"),
+
 ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
 ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
 ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
@@ -1249,6 +1339,14 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
        { name, "AIF2RX2", "AIF2RX2" }, \
        { name, "AIF3RX1", "AIF3RX1" }, \
        { name, "AIF3RX2", "AIF3RX2" }, \
+       { name, "SLIMRX1", "SLIMRX1" }, \
+       { name, "SLIMRX2", "SLIMRX2" }, \
+       { name, "SLIMRX3", "SLIMRX3" }, \
+       { name, "SLIMRX4", "SLIMRX4" }, \
+       { name, "SLIMRX5", "SLIMRX5" }, \
+       { name, "SLIMRX6", "SLIMRX6" }, \
+       { name, "SLIMRX7", "SLIMRX7" }, \
+       { name, "SLIMRX8", "SLIMRX8" }, \
        { name, "EQ1", "EQ1" }, \
        { name, "EQ2", "EQ2" }, \
        { name, "EQ3", "EQ3" }, \
@@ -1304,10 +1402,21 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "OUT5L", NULL, "SYSCLK" },
        { "OUT5R", NULL, "SYSCLK" },
 
+       { "IN1L", NULL, "SYSCLK" },
+       { "IN1R", NULL, "SYSCLK" },
+       { "IN2L", NULL, "SYSCLK" },
+       { "IN2R", NULL, "SYSCLK" },
+       { "IN3L", NULL, "SYSCLK" },
+       { "IN3R", NULL, "SYSCLK" },
+
        { "MICBIAS1", NULL, "MICVDD" },
        { "MICBIAS2", NULL, "MICVDD" },
        { "MICBIAS3", NULL, "MICVDD" },
 
+       { "Noise Generator", NULL, "SYSCLK" },
+       { "Tone Generator 1", NULL, "SYSCLK" },
+       { "Tone Generator 2", NULL, "SYSCLK" },
+
        { "Noise Generator", NULL, "NOISE" },
        { "Tone Generator 1", NULL, "TONE" },
        { "Tone Generator 2", NULL, "TONE" },
@@ -1345,13 +1454,41 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "AIF3RX1", NULL, "AIF3 Playback" },
        { "AIF3RX2", NULL, "AIF3 Playback" },
 
+       { "Slim1 Capture", NULL, "SLIMTX1" },
+       { "Slim1 Capture", NULL, "SLIMTX2" },
+       { "Slim1 Capture", NULL, "SLIMTX3" },
+       { "Slim1 Capture", NULL, "SLIMTX4" },
+
+       { "SLIMRX1", NULL, "Slim1 Playback" },
+       { "SLIMRX2", NULL, "Slim1 Playback" },
+       { "SLIMRX3", NULL, "Slim1 Playback" },
+       { "SLIMRX4", NULL, "Slim1 Playback" },
+
+       { "Slim2 Capture", NULL, "SLIMTX5" },
+       { "Slim2 Capture", NULL, "SLIMTX6" },
+
+       { "SLIMRX5", NULL, "Slim2 Playback" },
+       { "SLIMRX6", NULL, "Slim2 Playback" },
+
+       { "Slim3 Capture", NULL, "SLIMTX7" },
+       { "Slim3 Capture", NULL, "SLIMTX8" },
+
+       { "SLIMRX7", NULL, "Slim3 Playback" },
+       { "SLIMRX8", NULL, "Slim3 Playback" },
+
        { "AIF1 Playback", NULL, "SYSCLK" },
        { "AIF2 Playback", NULL, "SYSCLK" },
        { "AIF3 Playback", NULL, "SYSCLK" },
+       { "Slim1 Playback", NULL, "SYSCLK" },
+       { "Slim2 Playback", NULL, "SYSCLK" },
+       { "Slim3 Playback", NULL, "SYSCLK" },
 
        { "AIF1 Capture", NULL, "SYSCLK" },
        { "AIF2 Capture", NULL, "SYSCLK" },
        { "AIF3 Capture", NULL, "SYSCLK" },
+       { "Slim1 Capture", NULL, "SYSCLK" },
+       { "Slim2 Capture", NULL, "SYSCLK" },
+       { "Slim3 Capture", NULL, "SYSCLK" },
 
        { "IN1L PGA", NULL, "IN1L" },
        { "IN1R PGA", NULL, "IN1R" },
@@ -1408,6 +1545,15 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
        ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
 
+       ARIZONA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"),
+       ARIZONA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"),
+       ARIZONA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"),
+       ARIZONA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"),
+       ARIZONA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"),
+       ARIZONA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"),
+       ARIZONA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"),
+       ARIZONA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"),
+
        ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
        ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
        ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
@@ -1560,6 +1706,63 @@ static struct snd_soc_dai_driver wm5102_dai[] = {
                .ops = &arizona_dai_ops,
                .symmetric_rates = 1,
        },
+       {
+               .name = "wm5102-slim1",
+               .id = 4,
+               .playback = {
+                       .stream_name = "Slim1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = WM5102_RATES,
+                       .formats = WM5102_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 4,
+                        .rates = WM5102_RATES,
+                        .formats = WM5102_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm5102-slim2",
+               .id = 5,
+               .playback = {
+                       .stream_name = "Slim2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM5102_RATES,
+                       .formats = WM5102_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM5102_RATES,
+                        .formats = WM5102_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm5102-slim3",
+               .id = 6,
+               .playback = {
+                       .stream_name = "Slim3 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM5102_RATES,
+                       .formats = WM5102_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim3 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM5102_RATES,
+                        .formats = WM5102_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
 };
 
 static int wm5102_codec_probe(struct snd_soc_codec *codec)
index 88ad7db52ddeedf5b9934e9afe8f6561e189828f..2e7cb4ba161a5fa2a6980ec59eae33eb9c49ad18 100644 (file)
@@ -309,6 +309,15 @@ ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
 
 ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
 };
 
 ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
@@ -360,6 +369,15 @@ ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
 
+ARIZONA_MIXER_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX7, ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX8, ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE);
+
 ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE);
 ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
 ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
@@ -550,6 +568,56 @@ SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
 SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
                    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
 
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX8_ENA_SHIFT, 0),
+
 SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0,
                     ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0),
 SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0,
@@ -640,6 +708,15 @@ ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
 ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
 ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
 
+ARIZONA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"),
+ARIZONA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"),
+ARIZONA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"),
+
 ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"),
 ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
 ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
@@ -690,6 +767,14 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
        { name, "AIF2RX2", "AIF2RX2" }, \
        { name, "AIF3RX1", "AIF3RX1" }, \
        { name, "AIF3RX2", "AIF3RX2" }, \
+       { name, "SLIMRX1", "SLIMRX1" }, \
+       { name, "SLIMRX2", "SLIMRX2" }, \
+       { name, "SLIMRX3", "SLIMRX3" }, \
+       { name, "SLIMRX4", "SLIMRX4" }, \
+       { name, "SLIMRX5", "SLIMRX5" }, \
+       { name, "SLIMRX6", "SLIMRX6" }, \
+       { name, "SLIMRX7", "SLIMRX7" }, \
+       { name, "SLIMRX8", "SLIMRX8" }, \
        { name, "EQ1", "EQ1" }, \
        { name, "EQ2", "EQ2" }, \
        { name, "EQ3", "EQ3" }, \
@@ -736,10 +821,23 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "OUT6L", NULL, "SYSCLK" },
        { "OUT6R", NULL, "SYSCLK" },
 
+       { "IN1L", NULL, "SYSCLK" },
+       { "IN1R", NULL, "SYSCLK" },
+       { "IN2L", NULL, "SYSCLK" },
+       { "IN2R", NULL, "SYSCLK" },
+       { "IN3L", NULL, "SYSCLK" },
+       { "IN3R", NULL, "SYSCLK" },
+       { "IN4L", NULL, "SYSCLK" },
+       { "IN4R", NULL, "SYSCLK" },
+
        { "MICBIAS1", NULL, "MICVDD" },
        { "MICBIAS2", NULL, "MICVDD" },
        { "MICBIAS3", NULL, "MICVDD" },
 
+       { "Noise Generator", NULL, "SYSCLK" },
+       { "Tone Generator 1", NULL, "SYSCLK" },
+       { "Tone Generator 2", NULL, "SYSCLK" },
+
        { "Noise Generator", NULL, "NOISE" },
        { "Tone Generator 1", NULL, "TONE" },
        { "Tone Generator 2", NULL, "TONE" },
@@ -777,13 +875,41 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "AIF3RX1", NULL, "AIF3 Playback" },
        { "AIF3RX2", NULL, "AIF3 Playback" },
 
+       { "Slim1 Capture", NULL, "SLIMTX1" },
+       { "Slim1 Capture", NULL, "SLIMTX2" },
+       { "Slim1 Capture", NULL, "SLIMTX3" },
+       { "Slim1 Capture", NULL, "SLIMTX4" },
+
+       { "SLIMRX1", NULL, "Slim1 Playback" },
+       { "SLIMRX2", NULL, "Slim1 Playback" },
+       { "SLIMRX3", NULL, "Slim1 Playback" },
+       { "SLIMRX4", NULL, "Slim1 Playback" },
+
+       { "Slim2 Capture", NULL, "SLIMTX5" },
+       { "Slim2 Capture", NULL, "SLIMTX6" },
+
+       { "SLIMRX5", NULL, "Slim2 Playback" },
+       { "SLIMRX6", NULL, "Slim2 Playback" },
+
+       { "Slim3 Capture", NULL, "SLIMTX7" },
+       { "Slim3 Capture", NULL, "SLIMTX8" },
+
+       { "SLIMRX7", NULL, "Slim3 Playback" },
+       { "SLIMRX8", NULL, "Slim3 Playback" },
+
        { "AIF1 Playback", NULL, "SYSCLK" },
        { "AIF2 Playback", NULL, "SYSCLK" },
        { "AIF3 Playback", NULL, "SYSCLK" },
+       { "Slim1 Playback", NULL, "SYSCLK" },
+       { "Slim2 Playback", NULL, "SYSCLK" },
+       { "Slim3 Playback", NULL, "SYSCLK" },
 
        { "AIF1 Capture", NULL, "SYSCLK" },
        { "AIF2 Capture", NULL, "SYSCLK" },
        { "AIF3 Capture", NULL, "SYSCLK" },
+       { "Slim1 Capture", NULL, "SYSCLK" },
+       { "Slim2 Capture", NULL, "SYSCLK" },
+       { "Slim3 Capture", NULL, "SYSCLK" },
 
        { "IN1L PGA", NULL, "IN1L" },
        { "IN1R PGA", NULL, "IN1R" },
@@ -829,6 +955,15 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
        ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
 
+       ARIZONA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"),
+       ARIZONA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"),
+       ARIZONA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"),
+       ARIZONA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"),
+       ARIZONA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"),
+       ARIZONA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"),
+       ARIZONA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"),
+       ARIZONA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"),
+
        ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
        ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
        ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
@@ -963,6 +1098,63 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
                .ops = &arizona_dai_ops,
                .symmetric_rates = 1,
        },
+       {
+               .name = "wm5110-slim1",
+               .id = 4,
+               .playback = {
+                       .stream_name = "Slim1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = WM5110_RATES,
+                       .formats = WM5110_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 4,
+                        .rates = WM5110_RATES,
+                        .formats = WM5110_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm5110-slim2",
+               .id = 5,
+               .playback = {
+                       .stream_name = "Slim2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM5110_RATES,
+                       .formats = WM5110_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM5110_RATES,
+                        .formats = WM5110_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm5110-slim3",
+               .id = 6,
+               .playback = {
+                       .stream_name = "Slim3 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM5110_RATES,
+                       .formats = WM5110_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "Slim3 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM5110_RATES,
+                        .formats = WM5110_FORMATS,
+                },
+               .ops = &arizona_simple_dai_ops,
+       },
 };
 
 static int wm5110_codec_probe(struct snd_soc_codec *codec)
index af6d227e67be02f72da11eaefa12a97d2fcd8c80..d2a092850283f36ed035f20e4e6cd0c51a20412b 100644 (file)
@@ -143,13 +143,8 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
 }
 
 #define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
-               SNDRV_CTL_ELEM_ACCESS_READWRITE,\
-       .tlv.p = (tlv_array), \
-       .info = snd_soc_info_volsw, \
-       .get = snd_soc_get_volsw, .put = wm8400_outpga_put_volsw_vu, \
-       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+       SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+               snd_soc_get_volsw, wm8400_outpga_put_volsw_vu, tlv_array)
 
 
 static const char *wm8400_digital_sidetone[] =
index 9d88437cdcd1db314b444022f25ce91e11466cb5..fa24cedee68769f2b723e2fb8b25c03869ee286a 100644 (file)
@@ -403,10 +403,8 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
 }
 
 #define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_volsw, \
-       .get = snd_soc_dapm_get_volsw, .put = wm8903_class_w_put, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+       SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+               snd_soc_dapm_get_volsw, wm8903_class_w_put)
 
 
 static int wm8903_deemph[] = { 0, 32000, 44100, 48000 };
index 3ff195c541dbf839e946e036f1f314aa27662f38..4c9fb142cb2d21d18ac90dd1b6e0272bf48c7e24 100644 (file)
@@ -603,13 +603,8 @@ SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0,
 
 SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0),
 SOC_ENUM("High Pass Filter Mode", hpf_mode),
-
-{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "ADC 128x OSR Switch",
-       .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,
-       .put = wm8904_adc_osr_put,
-       .private_value = SOC_SINGLE_VALUE(WM8904_ANALOGUE_ADC_0, 0, 1, 0),
-},
+SOC_SINGLE_EXT("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0,
+       snd_soc_get_volsw, wm8904_adc_osr_put),
 };
 
 static const char *drc_path_text[] = {
index e9710280e5e18b882242f8d5b4cb61a2492e8eae..b1dc7d4264385f9f67ca9df57d15f33c88b09add 100644 (file)
@@ -51,6 +51,7 @@ static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8962_priv {
+       struct wm8962_pdata pdata;
        struct regmap *regmap;
        struct snd_soc_codec *codec;
 
@@ -1600,7 +1601,6 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       u16 *reg_cache = codec->reg_cache;
        int ret;
 
        /* Apply the update (if any) */
@@ -1609,16 +1609,19 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
                return 0;
 
        /* If the left PGA is enabled hit that VU bit... */
-       if (snd_soc_read(codec, WM8962_PWR_MGMT_2) & WM8962_HPOUTL_PGA_ENA)
-               return snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
-                                    reg_cache[WM8962_HPOUTL_VOLUME]);
+       ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
+       if (ret & WM8962_HPOUTL_PGA_ENA) {
+               snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
+                             snd_soc_read(codec, WM8962_HPOUTL_VOLUME));
+               return 1;
+       }
 
        /* ...otherwise the right.  The VU is stereo. */
-       if (snd_soc_read(codec, WM8962_PWR_MGMT_2) & WM8962_HPOUTR_PGA_ENA)
-               return snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
-                                    reg_cache[WM8962_HPOUTR_VOLUME]);
+       if (ret & WM8962_HPOUTR_PGA_ENA)
+               snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
+                             snd_soc_read(codec, WM8962_HPOUTR_VOLUME));
 
-       return 0;
+       return 1;
 }
 
 /* The VU bits for the speakers are in a different register to the mute
@@ -2345,12 +2348,13 @@ static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
 
 static int wm8962_add_widgets(struct snd_soc_codec *codec)
 {
-       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct wm8962_pdata *pdata = &wm8962->pdata;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        snd_soc_add_codec_controls(codec, wm8962_snd_controls,
                             ARRAY_SIZE(wm8962_snd_controls));
-       if (pdata && pdata->spk_mono)
+       if (pdata->spk_mono)
                snd_soc_add_codec_controls(codec, wm8962_spk_mono_controls,
                                     ARRAY_SIZE(wm8962_spk_mono_controls));
        else
@@ -2360,7 +2364,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_new_controls(dapm, wm8962_dapm_widgets,
                                  ARRAY_SIZE(wm8962_dapm_widgets));
-       if (pdata && pdata->spk_mono)
+       if (pdata->spk_mono)
                snd_soc_dapm_new_controls(dapm, wm8962_dapm_spk_mono_widgets,
                                          ARRAY_SIZE(wm8962_dapm_spk_mono_widgets));
        else
@@ -2369,7 +2373,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(dapm, wm8962_intercon,
                                ARRAY_SIZE(wm8962_intercon));
-       if (pdata && pdata->spk_mono)
+       if (pdata->spk_mono)
                snd_soc_dapm_add_routes(dapm, wm8962_spk_mono_intercon,
                                        ARRAY_SIZE(wm8962_spk_mono_intercon));
        else
@@ -3333,14 +3337,14 @@ static struct gpio_chip wm8962_template_chip = {
 static void wm8962_init_gpio(struct snd_soc_codec *codec)
 {
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       struct wm8962_pdata *pdata = &wm8962->pdata;
        int ret;
 
        wm8962->gpio_chip = wm8962_template_chip;
        wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
        wm8962->gpio_chip.dev = codec->dev;
 
-       if (pdata && pdata->gpio_base)
+       if (pdata->gpio_base)
                wm8962->gpio_chip.base = pdata->gpio_base;
        else
                wm8962->gpio_chip.base = -1;
@@ -3374,7 +3378,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        int ret;
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
        struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
-       u16 *reg_cache = codec->reg_cache;
        int i, trigger, irq_pol;
        bool dmicclk, dmicdat;
 
@@ -3421,30 +3424,29 @@ static int wm8962_probe(struct snd_soc_codec *codec)
                            WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
                            0);
 
-       if (pdata) {
-               /* Apply static configuration for GPIOs */
-               for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
-                       if (pdata->gpio_init[i]) {
-                               wm8962_set_gpio_mode(codec, i + 1);
-                               snd_soc_write(codec, 0x200 + i,
-                                             pdata->gpio_init[i] & 0xffff);
-                       }
+       /* Apply static configuration for GPIOs */
+       for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
+               if (pdata->gpio_init[i]) {
+                       wm8962_set_gpio_mode(codec, i + 1);
+                       snd_soc_write(codec, 0x200 + i,
+                                       pdata->gpio_init[i] & 0xffff);
+               }
 
-               /* Put the speakers into mono mode? */
-               if (pdata->spk_mono)
-                       reg_cache[WM8962_CLASS_D_CONTROL_2]
-                               |= WM8962_SPK_MONO;
 
-               /* Micbias setup, detection enable and detection
-                * threasholds. */
-               if (pdata->mic_cfg)
-                       snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
-                                           WM8962_MICDET_ENA |
-                                           WM8962_MICDET_THR_MASK |
-                                           WM8962_MICSHORT_THR_MASK |
-                                           WM8962_MICBIAS_LVL,
-                                           pdata->mic_cfg);
-       }
+       /* Put the speakers into mono mode? */
+       if (pdata->spk_mono)
+               snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_2,
+                               WM8962_SPK_MONO_MASK, WM8962_SPK_MONO);
+
+       /* Micbias setup, detection enable and detection
+        * threasholds. */
+       if (pdata->mic_cfg)
+               snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+                                   WM8962_MICDET_ENA |
+                                   WM8962_MICDET_THR_MASK |
+                                   WM8962_MICSHORT_THR_MASK |
+                                   WM8962_MICBIAS_LVL,
+                                   pdata->mic_cfg);
 
        /* Latch volume update bits */
        snd_soc_update_bits(codec, WM8962_LEFT_INPUT_VOLUME,
@@ -3506,7 +3508,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        wm8962_init_gpio(codec);
 
        if (wm8962->irq) {
-               if (pdata && pdata->irq_active_low) {
+               if (pdata->irq_active_low) {
                        trigger = IRQF_TRIGGER_LOW;
                        irq_pol = WM8962_IRQ_POL;
                } else {
@@ -3584,6 +3586,34 @@ static const struct regmap_config wm8962_regmap = {
        .cache_type = REGCACHE_RBTREE,
 };
 
+static int wm8962_set_pdata_from_of(struct i2c_client *i2c,
+                                   struct wm8962_pdata *pdata)
+{
+       const struct device_node *np = i2c->dev.of_node;
+       u32 val32;
+       int i;
+
+       if (of_property_read_bool(np, "spk-mono"))
+               pdata->spk_mono = true;
+
+       if (of_property_read_u32(np, "mic-cfg", &val32) >= 0)
+               pdata->mic_cfg = val32;
+
+       if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_init,
+                                      ARRAY_SIZE(pdata->gpio_init)) >= 0)
+               for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) {
+                       /*
+                        * The range of GPIO register value is [0x0, 0xffff]
+                        * While the default value of each register is 0x0
+                        * Any other value will be regarded as default value
+                        */
+                       if (pdata->gpio_init[i] > 0xffff)
+                               pdata->gpio_init[i] = 0x0;
+               }
+
+       return 0;
+}
+
 static int wm8962_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -3603,6 +3633,15 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
        init_completion(&wm8962->fll_lock);
        wm8962->irq = i2c->irq;
 
+       /* If platform data was supplied, update the default data in priv */
+       if (pdata) {
+               memcpy(&wm8962->pdata, pdata, sizeof(struct wm8962_pdata));
+       } else if (i2c->dev.of_node) {
+               ret = wm8962_set_pdata_from_of(i2c, &wm8962->pdata);
+               if (ret != 0)
+                       return ret;
+       }
+
        for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
                wm8962->supplies[i].supply = wm8962_supply_names[i];
 
@@ -3666,7 +3705,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
                goto err_enable;
        }
 
-       if (pdata && pdata->in4_dc_measure) {
+       if (wm8962->pdata.in4_dc_measure) {
                ret = regmap_register_patch(wm8962->regmap,
                                            wm8962_dc_measure,
                                            ARRAY_SIZE(wm8962_dc_measure));
@@ -3719,8 +3758,34 @@ static int wm8962_runtime_resume(struct device *dev)
 
        wm8962_reset(wm8962);
 
+       /* SYSCLK defaults to on; make sure it is off so we can safely
+        * write to registers if the device is declocked.
+        */
+       regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+                          WM8962_SYSCLK_ENA, 0);
+
+       /* Ensure we have soft control over all registers */
+       regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+                          WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
+
+       /* Ensure that the oscillator and PLLs are disabled */
+       regmap_update_bits(wm8962->regmap, WM8962_PLL2,
+                          WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
+                          0);
+
        regcache_sync(wm8962->regmap);
 
+       regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
+                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
+                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA);
+
+       /* Bias enable at 2*5k (fast start-up) */
+       regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+                          WM8962_BIAS_ENA | WM8962_VMID_SEL_MASK,
+                          WM8962_BIAS_ENA | 0x180);
+
+       msleep(5);
+
        return 0;
 }
 
index 837978e16e9dc85150b96ed5b8671cd569138e38..253c88bb7a4cbdb06d3d1df2862f10e80095aaa8 100644 (file)
@@ -151,14 +151,9 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
 }
 
 #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
-        tlv_array) {\
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
-                 SNDRV_CTL_ELEM_ACCESS_READWRITE,\
-       .tlv.p = (tlv_array), \
-       .info = snd_soc_info_volsw, \
-       .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \
-       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+       tlv_array) \
+       SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+               snd_soc_get_volsw, wm899x_outpga_put_volsw_vu, tlv_array)
 
 
 static const char *wm8990_digital_sidetone[] =
index 8a942efd18a50d318ca2da224334b2ef7d09f0a1..07707d8d7e20e8ef2625f4986c3b24f70285bc5a 100644 (file)
 
 #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
                                         tlv_array) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
-                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
-       .tlv.p = (tlv_array), \
-       .info = snd_soc_info_volsw, \
-       .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \
-       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+       SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+               snd_soc_get_volsw, wm899x_outpga_put_volsw_vu, tlv_array)
 
 #endif /* _WM8991_H */
index 29e95f93d482201a91cd0523c008bb2ca2b01bd3..1d4b1ec66e367f93bfcc43bb6eb5f47fcfe33fce 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/gcd.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -289,10 +290,8 @@ static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
 static const DECLARE_TLV_DB_SCALE(mixin_boost_tlv, 0, 900, 0);
 
 #define WM8994_DRC_SWITCH(xname, reg, shift) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
-       .put = wm8994_put_drc_sw, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, 1, 0) }
+       SOC_SINGLE_EXT(xname, reg, shift, 1, 0, \
+               snd_soc_get_volsw, wm8994_put_drc_sw)
 
 static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
                             struct snd_ctl_elem_value *ucontrol)
@@ -1432,10 +1431,8 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
 };
 
 #define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_volsw, \
-       .get = snd_soc_dapm_get_volsw, .put = wm8994_put_class_w, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+       SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+               snd_soc_get_volsw, wm8994_put_class_w)
 
 static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
@@ -1498,6 +1495,24 @@ static const char *aif1dac_text[] = {
        "AIF1DACDAT", "AIF3DACDAT",
 };
 
+static const char *loopback_text[] = {
+       "None", "ADCDAT",
+};
+
+static const struct soc_enum aif1_loopback_enum =
+       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2,
+                       loopback_text);
+
+static const struct snd_kcontrol_new aif1_loopback =
+       SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum);
+
+static const struct soc_enum aif2_loopback_enum =
+       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2,
+                       loopback_text);
+
+static const struct snd_kcontrol_new aif2_loopback =
+       SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum);
+
 static const struct soc_enum aif1dac_enum =
        SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text);
 
@@ -1744,6 +1759,9 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0),
 SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
 
+SND_SOC_DAPM_MUX("AIF1 Loopback", SND_SOC_NOPM, 0, 0, &aif1_loopback),
+SND_SOC_DAPM_MUX("AIF2 Loopback", SND_SOC_NOPM, 0, 0, &aif2_loopback),
+
 SND_SOC_DAPM_POST("Debug log", post_ev),
 };
 
@@ -1875,9 +1893,9 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "AIF1DAC2L", NULL, "AIF1DAC Mux" },
        { "AIF1DAC2R", NULL, "AIF1DAC Mux" },
 
-       { "AIF1DAC Mux", "AIF1DACDAT", "AIF1DACDAT" },
+       { "AIF1DAC Mux", "AIF1DACDAT", "AIF1 Loopback" },
        { "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
-       { "AIF2DAC Mux", "AIF2DACDAT", "AIF2DACDAT" },
+       { "AIF2DAC Mux", "AIF2DACDAT", "AIF2 Loopback" },
        { "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
        { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" },
        { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" },
@@ -1928,6 +1946,12 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" },
        { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" },
 
+       /* Loopback */
+       { "AIF1 Loopback", "ADCDAT", "AIF1ADCDAT" },
+       { "AIF1 Loopback", "None", "AIF1DACDAT" },
+       { "AIF2 Loopback", "ADCDAT", "AIF2ADCDAT" },
+       { "AIF2 Loopback", "None", "AIF2DACDAT" },
+
        /* Sidetone */
        { "Left Sidetone", "ADC/DMIC1", "ADCL Mux" },
        { "Left Sidetone", "DMIC2", "DMIC2L" },
@@ -2010,15 +2034,16 @@ struct fll_div {
        u16 outdiv;
        u16 n;
        u16 k;
+       u16 lambda;
        u16 clk_ref_div;
        u16 fll_fratio;
 };
 
-static int wm8994_get_fll_config(struct fll_div *fll,
+static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll,
                                 int freq_in, int freq_out)
 {
        u64 Kpart;
-       unsigned int K, Ndiv, Nmod;
+       unsigned int K, Ndiv, Nmod, gcd_fll;
 
        pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out);
 
@@ -2067,20 +2092,32 @@ static int wm8994_get_fll_config(struct fll_div *fll,
        Nmod = freq_out % freq_in;
        pr_debug("Nmod=%d\n", Nmod);
 
-       /* Calculate fractional part - scale up so we can round. */
-       Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+       switch (control->type) {
+       case WM8994:
+               /* Calculate fractional part - scale up so we can round. */
+               Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+               do_div(Kpart, freq_in);
+
+               K = Kpart & 0xFFFFFFFF;
 
-       do_div(Kpart, freq_in);
+               if ((K % 10) >= 5)
+                       K += 5;
 
-       K = Kpart & 0xFFFFFFFF;
+               /* Move down to proper range now rounding is done */
+               fll->k = K / 10;
+               fll->lambda = 0;
 
-       if ((K % 10) >= 5)
-               K += 5;
+               pr_debug("N=%x K=%x\n", fll->n, fll->k);
+               break;
 
-       /* Move down to proper range now rounding is done */
-       fll->k = K / 10;
+       default:
+               gcd_fll = gcd(freq_out, freq_in);
 
-       pr_debug("N=%x K=%x\n", fll->n, fll->k);
+               fll->k = (freq_out - (freq_in * fll->n)) / gcd_fll;
+               fll->lambda = freq_in / gcd_fll;
+               
+       }
 
        return 0;
 }
@@ -2144,9 +2181,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
         * analysis bugs spewing warnings.
         */
        if (freq_out)
-               ret = wm8994_get_fll_config(&fll, freq_in, freq_out);
+               ret = wm8994_get_fll_config(control, &fll, freq_in, freq_out);
        else
-               ret = wm8994_get_fll_config(&fll, wm8994->fll[id].in,
+               ret = wm8994_get_fll_config(control, &fll, wm8994->fll[id].in,
                                            wm8994->fll[id].out);
        if (ret < 0)
                return ret;
@@ -2191,6 +2228,17 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                            WM8994_FLL1_N_MASK,
                            fll.n << WM8994_FLL1_N_SHIFT);
 
+       if (fll.lambda) {
+               snd_soc_update_bits(codec, WM8958_FLL1_EFS_1 + reg_offset,
+                                   WM8958_FLL1_LAMBDA_MASK,
+                                   fll.lambda);
+               snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset,
+                                   WM8958_FLL1_EFS_ENA, WM8958_FLL1_EFS_ENA);
+       } else {
+               snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset,
+                                   WM8958_FLL1_EFS_ENA, 0);
+       }
+
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
                            WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
                            WM8994_FLL1_REFCLK_DIV_MASK |
@@ -2555,17 +2603,24 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct wm8994 *control = wm8994->wm8994;
        int ms_reg;
        int aif1_reg;
+       int dac_reg;
+       int adc_reg;
        int ms = 0;
        int aif1 = 0;
+       int lrclk = 0;
 
        switch (dai->id) {
        case 1:
                ms_reg = WM8994_AIF1_MASTER_SLAVE;
                aif1_reg = WM8994_AIF1_CONTROL_1;
+               dac_reg = WM8994_AIF1DAC_LRCLK;
+               adc_reg = WM8994_AIF1ADC_LRCLK;
                break;
        case 2:
                ms_reg = WM8994_AIF2_MASTER_SLAVE;
                aif1_reg = WM8994_AIF2_CONTROL_1;
+               dac_reg = WM8994_AIF1DAC_LRCLK;
+               adc_reg = WM8994_AIF1ADC_LRCLK;
                break;
        default:
                return -EINVAL;
@@ -2584,6 +2639,7 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_B:
                aif1 |= WM8994_AIF1_LRCLK_INV;
+               lrclk |= WM8958_AIF1_LRCLK_INV;
        case SND_SOC_DAIFMT_DSP_A:
                aif1 |= 0x18;
                break;
@@ -2622,12 +2678,14 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                        break;
                case SND_SOC_DAIFMT_IB_IF:
                        aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV;
+                       lrclk |= WM8958_AIF1_LRCLK_INV;
                        break;
                case SND_SOC_DAIFMT_IB_NF:
                        aif1 |= WM8994_AIF1_BCLK_INV;
                        break;
                case SND_SOC_DAIFMT_NB_IF:
                        aif1 |= WM8994_AIF1_LRCLK_INV;
+                       lrclk |= WM8958_AIF1_LRCLK_INV;
                        break;
                default:
                        return -EINVAL;
@@ -2658,6 +2716,10 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                            aif1);
        snd_soc_update_bits(codec, ms_reg, WM8994_AIF1_MSTR,
                            ms);
+       snd_soc_update_bits(codec, dac_reg,
+                           WM8958_AIF1_LRCLK_INV, lrclk);
+       snd_soc_update_bits(codec, adc_reg,
+                           WM8958_AIF1_LRCLK_INV, lrclk);
 
        return 0;
 }
@@ -3096,24 +3158,7 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec)
 static int wm8994_codec_resume(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994 *control = wm8994->wm8994;
        int i, ret;
-       unsigned int val, mask;
-
-       if (control->revision < 4) {
-               /* force a HW read */
-               ret = regmap_read(control->regmap,
-                                 WM8994_POWER_MANAGEMENT_5, &val);
-
-               /* modify the cache only */
-               codec->cache_only = 1;
-               mask =  WM8994_DAC1R_ENA | WM8994_DAC1L_ENA |
-                       WM8994_DAC2R_ENA | WM8994_DAC2L_ENA;
-               val &= mask;
-               snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
-                                   mask, val);
-               codec->cache_only = 0;
-       }
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
                if (!wm8994->fll_suspend[i].out)
@@ -3495,6 +3540,31 @@ static void wm8958_button_det(struct snd_soc_codec *codec, u16 status)
                            wm8994->btn_mask);
 }
 
+static void wm8958_open_circuit_work(struct work_struct *work)
+{
+       struct wm8994_priv *wm8994 = container_of(work,
+                                                 struct wm8994_priv,
+                                                 open_circuit_work.work);
+       struct device *dev = wm8994->wm8994->dev;
+
+       wm1811_micd_stop(wm8994->hubs.codec);
+
+       mutex_lock(&wm8994->accdet_lock);
+
+       dev_dbg(dev, "Reporting open circuit\n");
+
+       wm8994->jack_mic = false;
+       wm8994->mic_detecting = true;
+
+       wm8958_micd_set_rate(wm8994->hubs.codec);
+
+       snd_soc_jack_report(wm8994->micdet[0].jack, 0,
+                           wm8994->btn_mask |
+                           SND_JACK_HEADSET);
+
+       mutex_unlock(&wm8994->accdet_lock);
+}
+
 static void wm8958_mic_id(void *data, u16 status)
 {
        struct snd_soc_codec *codec = data;
@@ -3504,16 +3574,9 @@ static void wm8958_mic_id(void *data, u16 status)
        if (!(status & WM8958_MICD_STS)) {
                /* If nothing present then clear our statuses */
                dev_dbg(codec->dev, "Detected open circuit\n");
-               wm8994->jack_mic = false;
-               wm8994->mic_detecting = true;
-
-               wm1811_micd_stop(codec);
-
-               wm8958_micd_set_rate(codec);
 
-               snd_soc_jack_report(wm8994->micdet[0].jack, 0,
-                                   wm8994->btn_mask |
-                                   SND_JACK_HEADSET);
+               schedule_delayed_work(&wm8994->open_circuit_work,
+                                     msecs_to_jiffies(2500));
                return;
        }
 
@@ -3598,6 +3661,8 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 
        pm_runtime_get_sync(codec->dev);
 
+       cancel_delayed_work_sync(&wm8994->mic_complete_work);
+
        mutex_lock(&wm8994->accdet_lock);
 
        reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
@@ -3780,11 +3845,33 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 }
 EXPORT_SYMBOL_GPL(wm8958_mic_detect);
 
+static void wm8958_mic_work(struct work_struct *work)
+{
+       struct wm8994_priv *wm8994 = container_of(work,
+                                                 struct wm8994_priv,
+                                                 mic_complete_work.work);
+       struct snd_soc_codec *codec = wm8994->hubs.codec;
+
+       dev_crit(codec->dev, "MIC WORK %x\n", wm8994->mic_status);
+
+       pm_runtime_get_sync(codec->dev);
+
+       mutex_lock(&wm8994->accdet_lock);
+
+       wm8994->mic_id_cb(wm8994->mic_id_cb_data, wm8994->mic_status);
+
+       mutex_unlock(&wm8994->accdet_lock);
+
+       pm_runtime_put(codec->dev);
+
+       dev_crit(codec->dev, "MIC WORK %x DONE\n", wm8994->mic_status);
+}
+
 static irqreturn_t wm8958_mic_irq(int irq, void *data)
 {
        struct wm8994_priv *wm8994 = data;
        struct snd_soc_codec *codec = wm8994->hubs.codec;
-       int reg, count, ret;
+       int reg, count, ret, id_delay;
 
        /*
         * Jack detection may have detected a removal simulataneously
@@ -3794,6 +3881,9 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
        if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
                return IRQ_HANDLED;
 
+       cancel_delayed_work_sync(&wm8994->mic_complete_work);
+       cancel_delayed_work_sync(&wm8994->open_circuit_work);
+
        pm_runtime_get_sync(codec->dev);
 
        /* We may occasionally read a detection without an impedence
@@ -3846,8 +3936,12 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
                goto out;
        }
 
+       wm8994->mic_status = reg;
+       id_delay = wm8994->wm8994->pdata.mic_id_delay;
+
        if (wm8994->mic_detecting)
-               wm8994->mic_id_cb(wm8994->mic_id_cb_data, reg);
+               schedule_delayed_work(&wm8994->mic_complete_work,
+                                     msecs_to_jiffies(id_delay));
        else
                wm8958_button_det(codec, reg);
 
@@ -3899,6 +3993,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        mutex_init(&wm8994->accdet_lock);
        INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
                          wm1811_jackdet_bootstrap);
+       INIT_DELAYED_WORK(&wm8994->open_circuit_work,
+                         wm8958_open_circuit_work);
 
        switch (control->type) {
        case WM8994:
@@ -3911,6 +4007,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                break;
        }
 
+       INIT_DELAYED_WORK(&wm8994->mic_complete_work, wm8958_mic_work);
+
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
                init_completion(&wm8994->fll_locked[i]);
 
index 55ddf4d57d9b5a0adc5f9ba13ae4011f3807e93b..6536f8d45ac6bb0c4a13409582e299020bf0245d 100644 (file)
@@ -134,6 +134,9 @@ struct wm8994_priv {
        struct mutex accdet_lock;
        struct wm8994_micdet micdet[2];
        struct delayed_work mic_work;
+       struct delayed_work open_circuit_work;
+       struct delayed_work mic_complete_work;
+       u16 mic_status;
        bool mic_detecting;
        bool jack_mic;
        int btn_mask;
index 5642121c4977481e9abd25e74925983f361309e2..508ad27fe2bb1a84b08bfb267f89f9c53e4558cf 100644 (file)
 #define WM8995_SPK2_MUTE_SEQ1_WIDTH                  8 /* SPK2_MUTE_SEQ1 - [7:0] */
 
 #define WM8995_CLASS_W_SWITCH(xname, reg, shift, max, invert) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_volsw, \
-       .get = snd_soc_dapm_get_volsw, .put = wm8995_put_class_w, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) \
-}
+       SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+               snd_soc_dapm_get_volsw, wm8995_put_class_w)
 
 struct wm8995_reg_access {
        u16 read;
index 05b1f346695bce8d10c7e406ed6413a744117102..70ce6793c5bd51cc8f32c893d28932e2db6358da 100644 (file)
@@ -209,7 +209,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
        case AC97_RESET:
        case AC97_VENDOR_ID1:
        case AC97_VENDOR_ID2:
-               return soc_ac97_ops.read(codec->ac97, reg);
+               return soc_ac97_ops->read(codec->ac97, reg);
        default:
                reg = reg >> 1;
 
@@ -225,7 +225,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 {
        u16 *cache = codec->reg_cache;
 
-       soc_ac97_ops.write(codec->ac97, reg, val);
+       soc_ac97_ops->write(codec->ac97, reg, val);
        reg = reg >> 1;
        if (reg < (ARRAY_SIZE(wm9705_reg)))
                cache[reg] = val;
@@ -294,8 +294,8 @@ static struct snd_soc_dai_driver wm9705_dai[] = {
 
 static int wm9705_reset(struct snd_soc_codec *codec)
 {
-       if (soc_ac97_ops.reset) {
-               soc_ac97_ops.reset(codec->ac97);
+       if (soc_ac97_ops->reset) {
+               soc_ac97_ops->reset(codec->ac97);
                if (ac97_read(codec, 0) == wm9705_reg[0])
                        return 0; /* Success */
        }
@@ -306,7 +306,7 @@ static int wm9705_reset(struct snd_soc_codec *codec)
 #ifdef CONFIG_PM
 static int wm9705_soc_suspend(struct snd_soc_codec *codec)
 {
-       soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff);
+       soc_ac97_ops->write(codec->ac97, AC97_POWERDOWN, 0xffff);
 
        return 0;
 }
@@ -323,7 +323,7 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)
        }
 
        for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) {
-               soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
+               soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
        }
 
        return 0;
@@ -337,9 +337,7 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
 {
        int ret = 0;
 
-       printk(KERN_INFO "WM9705 SoC Audio Codec\n");
-
-       ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+       ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
                return ret;
index 8e9a6a3eeb1a257886415be532a186a1900de1e7..c5eb746087b4103394420fbdf42fff6602399297 100644 (file)
@@ -455,7 +455,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
        if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
                reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
                reg == AC97_REC_GAIN)
-               return soc_ac97_ops.read(codec->ac97, reg);
+               return soc_ac97_ops->read(codec->ac97, reg);
        else {
                reg = reg >> 1;
 
@@ -472,7 +472,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
        u16 *cache = codec->reg_cache;
 
        if (reg < 0x7c)
-               soc_ac97_ops.write(codec->ac97, reg, val);
+               soc_ac97_ops->write(codec->ac97, reg, val);
        reg = reg >> 1;
        if (reg < (ARRAY_SIZE(wm9712_reg)))
                cache[reg] = val;
@@ -581,15 +581,15 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,
 
 static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
 {
-       if (try_warm && soc_ac97_ops.warm_reset) {
-               soc_ac97_ops.warm_reset(codec->ac97);
+       if (try_warm && soc_ac97_ops->warm_reset) {
+               soc_ac97_ops->warm_reset(codec->ac97);
                if (ac97_read(codec, 0) == wm9712_reg[0])
                        return 1;
        }
 
-       soc_ac97_ops.reset(codec->ac97);
-       if (soc_ac97_ops.warm_reset)
-               soc_ac97_ops.warm_reset(codec->ac97);
+       soc_ac97_ops->reset(codec->ac97);
+       if (soc_ac97_ops->warm_reset)
+               soc_ac97_ops->warm_reset(codec->ac97);
        if (ac97_read(codec, 0) != wm9712_reg[0])
                goto err;
        return 0;
@@ -624,7 +624,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)
                        if (i == AC97_INT_PAGING || i == AC97_POWERDOWN ||
                            (i > 0x58 && i != 0x5c))
                                continue;
-                       soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
+                       soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
                }
        }
 
@@ -635,7 +635,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
 {
        int ret = 0;
 
-       ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+       ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
                return ret;
index f7afa68d8c7fce0a119eb98810e969609e28e225..a53e175c015ad54d60ff6ce085680613ee19d28d 100644 (file)
@@ -652,7 +652,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
        if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
                reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
                reg == AC97_CD)
-               return soc_ac97_ops.read(codec->ac97, reg);
+               return soc_ac97_ops->read(codec->ac97, reg);
        else {
                reg = reg >> 1;
 
@@ -668,7 +668,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 {
        u16 *cache = codec->reg_cache;
        if (reg < 0x7c)
-               soc_ac97_ops.write(codec->ac97, reg, val);
+               soc_ac97_ops->write(codec->ac97, reg, val);
        reg = reg >> 1;
        if (reg < (ARRAY_SIZE(wm9713_reg)))
                cache[reg] = val;
@@ -1095,15 +1095,15 @@ static struct snd_soc_dai_driver wm9713_dai[] = {
 
 int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
 {
-       if (try_warm && soc_ac97_ops.warm_reset) {
-               soc_ac97_ops.warm_reset(codec->ac97);
+       if (try_warm && soc_ac97_ops->warm_reset) {
+               soc_ac97_ops->warm_reset(codec->ac97);
                if (ac97_read(codec, 0) == wm9713_reg[0])
                        return 1;
        }
 
-       soc_ac97_ops.reset(codec->ac97);
-       if (soc_ac97_ops.warm_reset)
-               soc_ac97_ops.warm_reset(codec->ac97);
+       soc_ac97_ops->reset(codec->ac97);
+       if (soc_ac97_ops->warm_reset)
+               soc_ac97_ops->warm_reset(codec->ac97);
        if (ac97_read(codec, 0) != wm9713_reg[0])
                return -EIO;
        return 0;
@@ -1180,7 +1180,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
                        if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID ||
                                i == AC97_EXTENDED_MSTATUS || i > 0x66)
                                continue;
-                       soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
+                       soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
                }
        }
 
@@ -1197,7 +1197,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, wm9713);
 
-       ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+       ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
        if (ret < 0)
                goto codec_err;
 
index 3470b649c0b26b6479ea89c9a1ecd799cbc6ce7c..05252ac936a369cb210a9043105d9d95cb614679 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -215,6 +216,36 @@ static struct {
        [WM_ADSP_FW_RX_ANC] =  { .file = "rx-anc" },
 };
 
+struct wm_coeff_ctl_ops {
+       int (*xget)(struct snd_kcontrol *kcontrol,
+                   struct snd_ctl_elem_value *ucontrol);
+       int (*xput)(struct snd_kcontrol *kcontrol,
+                   struct snd_ctl_elem_value *ucontrol);
+       int (*xinfo)(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_info *uinfo);
+};
+
+struct wm_coeff {
+       struct device *dev;
+       struct list_head ctl_list;
+       struct regmap *regmap;
+};
+
+struct wm_coeff_ctl {
+       const char *name;
+       struct snd_card *card;
+       struct wm_adsp_alg_region region;
+       struct wm_coeff_ctl_ops ops;
+       struct wm_adsp *adsp;
+       void *private;
+       unsigned int enabled:1;
+       struct list_head list;
+       void *cache;
+       size_t len;
+       unsigned int set:1;
+       struct snd_kcontrol *kcontrol;
+};
+
 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_value *ucontrol)
 {
@@ -279,7 +310,7 @@ static const struct soc_enum wm_adsp2_rate_enum[] = {
                              ARIZONA_DSP1_RATE_SHIFT, 0xf,
                              ARIZONA_RATE_ENUM_SIZE,
                              arizona_rate_text, arizona_rate_val),
-       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
                              ARIZONA_DSP1_RATE_SHIFT, 0xf,
                              ARIZONA_RATE_ENUM_SIZE,
                              arizona_rate_text, arizona_rate_val),
@@ -334,6 +365,181 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
        }
 }
 
+static int wm_coeff_info(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_info *uinfo)
+{
+       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = ctl->len;
+       return 0;
+}
+
+static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,
+                                 const void *buf, size_t len)
+{
+       struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol);
+       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+       struct wm_adsp_alg_region *region = &ctl->region;
+       const struct wm_adsp_region *mem;
+       struct wm_adsp *adsp = ctl->adsp;
+       void *scratch;
+       int ret;
+       unsigned int reg;
+
+       mem = wm_adsp_find_region(adsp, region->type);
+       if (!mem) {
+               adsp_err(adsp, "No base for region %x\n",
+                        region->type);
+               return -EINVAL;
+       }
+
+       reg = ctl->region.base;
+       reg = wm_adsp_region_to_reg(mem, reg);
+
+       scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA);
+       if (!scratch)
+               return -ENOMEM;
+
+       ret = regmap_raw_write(wm_coeff->regmap, reg, scratch,
+                              ctl->len);
+       if (ret) {
+               adsp_err(adsp, "Failed to write %zu bytes to %x\n",
+                        ctl->len, reg);
+               kfree(scratch);
+               return ret;
+       }
+
+       kfree(scratch);
+
+       return 0;
+}
+
+static int wm_coeff_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+       char *p = ucontrol->value.bytes.data;
+
+       memcpy(ctl->cache, p, ctl->len);
+
+       if (!ctl->enabled) {
+               ctl->set = 1;
+               return 0;
+       }
+
+       return wm_coeff_write_control(kcontrol, p, ctl->len);
+}
+
+static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,
+                                void *buf, size_t len)
+{
+       struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol);
+       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+       struct wm_adsp_alg_region *region = &ctl->region;
+       const struct wm_adsp_region *mem;
+       struct wm_adsp *adsp = ctl->adsp;
+       void *scratch;
+       int ret;
+       unsigned int reg;
+
+       mem = wm_adsp_find_region(adsp, region->type);
+       if (!mem) {
+               adsp_err(adsp, "No base for region %x\n",
+                        region->type);
+               return -EINVAL;
+       }
+
+       reg = ctl->region.base;
+       reg = wm_adsp_region_to_reg(mem, reg);
+
+       scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA);
+       if (!scratch)
+               return -ENOMEM;
+
+       ret = regmap_raw_read(wm_coeff->regmap, reg, scratch, ctl->len);
+       if (ret) {
+               adsp_err(adsp, "Failed to read %zu bytes from %x\n",
+                        ctl->len, reg);
+               kfree(scratch);
+               return ret;
+       }
+
+       memcpy(buf, scratch, ctl->len);
+       kfree(scratch);
+
+       return 0;
+}
+
+static int wm_coeff_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
+       char *p = ucontrol->value.bytes.data;
+
+       memcpy(p, ctl->cache, ctl->len);
+       return 0;
+}
+
+static int wm_coeff_add_kcontrol(struct wm_coeff *wm_coeff,
+                                struct wm_coeff_ctl *ctl,
+                                const struct snd_kcontrol_new *kctl)
+{
+       int ret;
+       struct snd_kcontrol *kcontrol;
+
+       kcontrol = snd_ctl_new1(kctl, wm_coeff);
+       ret = snd_ctl_add(ctl->card, kcontrol);
+       if (ret < 0) {
+               dev_err(wm_coeff->dev, "Failed to add %s: %d\n",
+                       kctl->name, ret);
+               return ret;
+       }
+       ctl->kcontrol = kcontrol;
+       return 0;
+}
+
+struct wmfw_ctl_work {
+       struct wm_coeff *wm_coeff;
+       struct wm_coeff_ctl *ctl;
+       struct work_struct work;
+};
+
+static int wmfw_add_ctl(struct wm_coeff *wm_coeff,
+                       struct wm_coeff_ctl *ctl)
+{
+       struct snd_kcontrol_new *kcontrol;
+       int ret;
+
+       if (!wm_coeff || !ctl || !ctl->name || !ctl->card)
+               return -EINVAL;
+
+       kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
+       if (!kcontrol)
+               return -ENOMEM;
+       kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+
+       kcontrol->name = ctl->name;
+       kcontrol->info = wm_coeff_info;
+       kcontrol->get = wm_coeff_get;
+       kcontrol->put = wm_coeff_put;
+       kcontrol->private_value = (unsigned long)ctl;
+
+       ret = wm_coeff_add_kcontrol(wm_coeff,
+                                   ctl, kcontrol);
+       if (ret < 0)
+               goto err_kcontrol;
+
+       kfree(kcontrol);
+
+       list_add(&ctl->list, &wm_coeff->ctl_list);
+       return 0;
+
+err_kcontrol:
+       kfree(kcontrol);
+       return ret;
+}
+
 static int wm_adsp_load(struct wm_adsp *dsp)
 {
        LIST_HEAD(buf_list);
@@ -547,7 +753,157 @@ out:
        return ret;
 }
 
-static int wm_adsp_setup_algs(struct wm_adsp *dsp)
+static int wm_coeff_init_control_caches(struct wm_coeff *wm_coeff)
+{
+       struct wm_coeff_ctl *ctl;
+       int ret;
+
+       list_for_each_entry(ctl, &wm_coeff->ctl_list,
+                           list) {
+               if (!ctl->enabled || ctl->set)
+                       continue;
+               ret = wm_coeff_read_control(ctl->kcontrol,
+                                           ctl->cache,
+                                           ctl->len);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int wm_coeff_sync_controls(struct wm_coeff *wm_coeff)
+{
+       struct wm_coeff_ctl *ctl;
+       int ret;
+
+       list_for_each_entry(ctl, &wm_coeff->ctl_list,
+                           list) {
+               if (!ctl->enabled)
+                       continue;
+               if (ctl->set) {
+                       ret = wm_coeff_write_control(ctl->kcontrol,
+                                                    ctl->cache,
+                                                    ctl->len);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void wm_adsp_ctl_work(struct work_struct *work)
+{
+       struct wmfw_ctl_work *ctl_work = container_of(work,
+                                                     struct wmfw_ctl_work,
+                                                     work);
+
+       wmfw_add_ctl(ctl_work->wm_coeff, ctl_work->ctl);
+       kfree(ctl_work);
+}
+
+static int wm_adsp_create_control(struct snd_soc_codec *codec,
+                                 const struct wm_adsp_alg_region *region)
+
+{
+       struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
+       struct wm_coeff_ctl *ctl;
+       struct wmfw_ctl_work *ctl_work;
+       char *name;
+       char *region_name;
+       int ret;
+
+       name = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
+       switch (region->type) {
+       case WMFW_ADSP1_PM:
+               region_name = "PM";
+               break;
+       case WMFW_ADSP1_DM:
+               region_name = "DM";
+               break;
+       case WMFW_ADSP2_XM:
+               region_name = "XM";
+               break;
+       case WMFW_ADSP2_YM:
+               region_name = "YM";
+               break;
+       case WMFW_ADSP1_ZM:
+               region_name = "ZM";
+               break;
+       default:
+               ret = -EINVAL;
+               goto err_name;
+       }
+
+       snprintf(name, PAGE_SIZE, "DSP%d %s %x",
+                dsp->num, region_name, region->alg);
+
+       list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
+                           list) {
+               if (!strcmp(ctl->name, name)) {
+                       if (!ctl->enabled)
+                               ctl->enabled = 1;
+                       goto found;
+               }
+       }
+
+       ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
+       if (!ctl) {
+               ret = -ENOMEM;
+               goto err_name;
+       }
+       ctl->region = *region;
+       ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL);
+       if (!ctl->name) {
+               ret = -ENOMEM;
+               goto err_ctl;
+       }
+       ctl->enabled = 1;
+       ctl->set = 0;
+       ctl->ops.xget = wm_coeff_get;
+       ctl->ops.xput = wm_coeff_put;
+       ctl->card = codec->card->snd_card;
+       ctl->adsp = dsp;
+
+       ctl->len = region->len;
+       ctl->cache = kzalloc(ctl->len, GFP_KERNEL);
+       if (!ctl->cache) {
+               ret = -ENOMEM;
+               goto err_ctl_name;
+       }
+
+       ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL);
+       if (!ctl_work) {
+               ret = -ENOMEM;
+               goto err_ctl_cache;
+       }
+
+       ctl_work->wm_coeff = dsp->wm_coeff;
+       ctl_work->ctl = ctl;
+       INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
+       schedule_work(&ctl_work->work);
+
+found:
+       kfree(name);
+
+       return 0;
+
+err_ctl_cache:
+       kfree(ctl->cache);
+err_ctl_name:
+       kfree(ctl->name);
+err_ctl:
+       kfree(ctl);
+err_name:
+       kfree(name);
+       return ret;
+}
+
+static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
 {
        struct regmap *regmap = dsp->regmap;
        struct wmfw_adsp1_id_hdr adsp1_id;
@@ -730,7 +1086,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                        region->type = WMFW_ADSP1_DM;
                        region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
                        region->base = be32_to_cpu(adsp1_alg[i].dm);
+                       region->len = 0;
                        list_add_tail(&region->list, &dsp->alg_regions);
+                       if (i + 1 < algs) {
+                               region->len = be32_to_cpu(adsp1_alg[i + 1].dm);
+                               region->len -= be32_to_cpu(adsp1_alg[i].dm);
+                               wm_adsp_create_control(codec, region);
+                       } else {
+                               adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
+                                         be32_to_cpu(adsp1_alg[i].alg.id));
+                       }
 
                        region = kzalloc(sizeof(*region), GFP_KERNEL);
                        if (!region)
@@ -738,7 +1103,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                        region->type = WMFW_ADSP1_ZM;
                        region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
                        region->base = be32_to_cpu(adsp1_alg[i].zm);
+                       region->len = 0;
                        list_add_tail(&region->list, &dsp->alg_regions);
+                       if (i + 1 < algs) {
+                               region->len = be32_to_cpu(adsp1_alg[i + 1].zm);
+                               region->len -= be32_to_cpu(adsp1_alg[i].zm);
+                               wm_adsp_create_control(codec, region);
+                       } else {
+                               adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
+                                         be32_to_cpu(adsp1_alg[i].alg.id));
+                       }
                        break;
 
                case WMFW_ADSP2:
@@ -758,7 +1132,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                        region->type = WMFW_ADSP2_XM;
                        region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
                        region->base = be32_to_cpu(adsp2_alg[i].xm);
+                       region->len = 0;
                        list_add_tail(&region->list, &dsp->alg_regions);
+                       if (i + 1 < algs) {
+                               region->len = be32_to_cpu(adsp2_alg[i + 1].xm);
+                               region->len -= be32_to_cpu(adsp2_alg[i].xm);
+                               wm_adsp_create_control(codec, region);
+                       } else {
+                               adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
+                                         be32_to_cpu(adsp2_alg[i].alg.id));
+                       }
 
                        region = kzalloc(sizeof(*region), GFP_KERNEL);
                        if (!region)
@@ -766,7 +1149,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                        region->type = WMFW_ADSP2_YM;
                        region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
                        region->base = be32_to_cpu(adsp2_alg[i].ym);
+                       region->len = 0;
                        list_add_tail(&region->list, &dsp->alg_regions);
+                       if (i + 1 < algs) {
+                               region->len = be32_to_cpu(adsp2_alg[i + 1].ym);
+                               region->len -= be32_to_cpu(adsp2_alg[i].ym);
+                               wm_adsp_create_control(codec, region);
+                       } else {
+                               adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
+                                         be32_to_cpu(adsp2_alg[i].alg.id));
+                       }
 
                        region = kzalloc(sizeof(*region), GFP_KERNEL);
                        if (!region)
@@ -774,7 +1166,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                        region->type = WMFW_ADSP2_ZM;
                        region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
                        region->base = be32_to_cpu(adsp2_alg[i].zm);
+                       region->len = 0;
                        list_add_tail(&region->list, &dsp->alg_regions);
+                       if (i + 1 < algs) {
+                               region->len = be32_to_cpu(adsp2_alg[i + 1].zm);
+                               region->len -= be32_to_cpu(adsp2_alg[i].zm);
+                               wm_adsp_create_control(codec, region);
+                       } else {
+                               adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
+                                         be32_to_cpu(adsp2_alg[i].alg.id));
+                       }
                        break;
                }
        }
@@ -986,6 +1387,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
        struct snd_soc_codec *codec = w->codec;
        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
        struct wm_adsp *dsp = &dsps[w->shift];
+       struct wm_coeff_ctl *ctl;
        int ret;
        int val;
 
@@ -1023,7 +1425,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                if (ret != 0)
                        goto err;
 
-               ret = wm_adsp_setup_algs(dsp);
+               ret = wm_adsp_setup_algs(dsp, codec);
                if (ret != 0)
                        goto err;
 
@@ -1031,6 +1433,16 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                if (ret != 0)
                        goto err;
 
+               /* Initialize caches for enabled and unset controls */
+               ret = wm_coeff_init_control_caches(dsp->wm_coeff);
+               if (ret != 0)
+                       goto err;
+
+               /* Sync set controls */
+               ret = wm_coeff_sync_controls(dsp->wm_coeff);
+               if (ret != 0)
+                       goto err;
+
                /* Start the core running */
                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
                                   ADSP1_CORE_ENA | ADSP1_START,
@@ -1047,6 +1459,11 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
 
                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
                                   ADSP1_SYS_ENA, 0);
+
+               list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
+                                   list) {
+                       ctl->enabled = 0;
+               }
                break;
 
        default:
@@ -1099,6 +1516,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
        struct wm_adsp *dsp = &dsps[w->shift];
        struct wm_adsp_alg_region *alg_region;
+       struct wm_coeff_ctl *ctl;
        unsigned int val;
        int ret;
 
@@ -1164,7 +1582,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                if (ret != 0)
                        goto err;
 
-               ret = wm_adsp_setup_algs(dsp);
+               ret = wm_adsp_setup_algs(dsp, codec);
                if (ret != 0)
                        goto err;
 
@@ -1172,6 +1590,16 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                if (ret != 0)
                        goto err;
 
+               /* Initialize caches for enabled and unset controls */
+               ret = wm_coeff_init_control_caches(dsp->wm_coeff);
+               if (ret != 0)
+                       goto err;
+
+               /* Sync set controls */
+               ret = wm_coeff_sync_controls(dsp->wm_coeff);
+               if (ret != 0)
+                       goto err;
+
                ret = regmap_update_bits(dsp->regmap,
                                         dsp->base + ADSP2_CONTROL,
                                         ADSP2_CORE_ENA | ADSP2_START,
@@ -1209,6 +1637,11 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                                        ret);
                }
 
+               list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
+                                   list) {
+                       ctl->enabled = 0;
+               }
+
                while (!list_empty(&dsp->alg_regions)) {
                        alg_region = list_first_entry(&dsp->alg_regions,
                                                      struct wm_adsp_alg_region,
@@ -1247,36 +1680,48 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
 
        INIT_LIST_HEAD(&adsp->alg_regions);
 
+       adsp->wm_coeff = kzalloc(sizeof(*adsp->wm_coeff),
+                                GFP_KERNEL);
+       if (!adsp->wm_coeff)
+               return -ENOMEM;
+       adsp->wm_coeff->regmap = adsp->regmap;
+       adsp->wm_coeff->dev = adsp->dev;
+       INIT_LIST_HEAD(&adsp->wm_coeff->ctl_list);
+
        if (dvfs) {
                adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
                if (IS_ERR(adsp->dvfs)) {
                        ret = PTR_ERR(adsp->dvfs);
                        dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
-                       return ret;
+                       goto out_coeff;
                }
 
                ret = regulator_enable(adsp->dvfs);
                if (ret != 0) {
                        dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
                                ret);
-                       return ret;
+                       goto out_coeff;
                }
 
                ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
                if (ret != 0) {
                        dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
                                ret);
-                       return ret;
+                       goto out_coeff;
                }
 
                ret = regulator_disable(adsp->dvfs);
                if (ret != 0) {
                        dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
                                ret);
-                       return ret;
+                       goto out_coeff;
                }
        }
 
        return 0;
+
+out_coeff:
+       kfree(adsp->wm_coeff);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_init);
index fea514627526b18e3556a94137967da7371f0ec1..9f922c82536c52f8939db5834bbcfda80e1c5b59 100644 (file)
@@ -30,6 +30,7 @@ struct wm_adsp_alg_region {
        unsigned int alg;
        int type;
        unsigned int base;
+       size_t len;
 };
 
 struct wm_adsp {
@@ -55,17 +56,17 @@ struct wm_adsp {
        bool running;
 
        struct regulator *dvfs;
+
+       struct wm_coeff *wm_coeff;
 };
 
 #define WM_ADSP1(wname, num) \
-       { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
-       .shift = num, .event = wm_adsp1_event, \
-       .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
+       SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
+               wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
 
 #define WM_ADSP2(wname, num) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
-       .shift = num, .event = wm_adsp2_event, \
-       .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
+       SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
+               wm_adsp2_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
 
 extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
 extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
index f5d81b9487598753e3f0ce4c93b766d7d3347f54..2d9e099415a58cbe353c99f32f6f089a200db2de 100644 (file)
@@ -693,10 +693,8 @@ void wm_hubs_update_class_w(struct snd_soc_codec *codec)
 EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
 
 #define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_volsw, \
-       .get = snd_soc_dapm_get_volsw, .put = class_w_put_volsw, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+       SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
+               snd_soc_dapm_get_volsw, class_w_put_volsw)
 
 static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
index 9e11a14d1b4579dbb032abdf21ca8931ad59df9d..c82f89c9475b2f7301ecd1d753c65d85431f3cc6 100644 (file)
@@ -54,16 +54,6 @@ config  SND_DM6467_SOC_EVM
        help
          Say Y if you want to add support for SoC audio on TI
 
-config SND_DAVINCI_SOC_SFFSDR
-       tristate "SoC Audio support for SFFSDR"
-       depends on SND_DAVINCI_SOC && MACH_SFFSDR
-       select SND_DAVINCI_SOC_I2S
-       select SND_SOC_PCM3008
-       select SFFSDR_FPGA
-       help
-         Say Y if you want to add support for SoC audio on
-         Lyrtech SFFSDR board.
-
 config  SND_DA830_SOC_EVM
        tristate "SoC Audio support for DA830/OMAP-L137 EVM"
        depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM
index a93679d618cd812fa9e891582dd435e061c23f04..a396ab6d6d5efaa6f11ec5d1da6716cb4a1db0ac 100644 (file)
@@ -11,10 +11,8 @@ obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
 
 # DAVINCI Machine Support
 snd-soc-evm-objs := davinci-evm.o
-snd-soc-sffsdr-objs := davinci-sffsdr.o
 
 obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o
 obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o
 obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o
 obj-$(CONFIG_SND_DA850_SOC_EVM) += snd-soc-evm.o
-obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o
index 81490febac6dc108decb890ac318ffbec9c2ab8b..32ddb7fe5034865a7f13dc7243f1f8161482c7f2 100644 (file)
@@ -1024,7 +1024,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
        struct device_node *np = pdev->dev.of_node;
        struct snd_platform_data *pdata = NULL;
        const struct of_device_id *match =
-                       of_match_device(of_match_ptr(mcasp_dt_ids), &pdev->dev);
+                       of_match_device(mcasp_dt_ids, &pdev->dev);
 
        const u32 *of_serial_dir32;
        u8 *of_serial_dir;
@@ -1257,7 +1257,7 @@ static struct platform_driver davinci_mcasp_driver = {
        .driver         = {
                .name   = "davinci-mcasp",
                .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(mcasp_dt_ids),
+               .of_match_table = mcasp_dt_ids,
        },
 };
 
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c
deleted file mode 100644 (file)
index 5be65aa..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * ASoC driver for Lyrtech SFFSDR board.
- *
- * Author:     Hugo Villeneuve
- * Copyright (C) 2008 Lyrtech inc
- *
- * Based on ASoC driver for TI DAVINCI EVM platform, original copyright follow:
- * Copyright:   (C) 2007 MontaVista Software, Inc., <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-#include <asm/mach-types.h>
-#ifdef CONFIG_SFFSDR_FPGA
-#include <asm/plat-sffsdr/sffsdr-fpga.h>
-#endif
-
-#include <mach/edma.h>
-
-#include "../codecs/pcm3008.h"
-#include "davinci-pcm.h"
-#include "davinci-i2s.h"
-
-/*
- * CLKX and CLKR are the inputs for the Sample Rate Generator.
- * FSX and FSR are outputs, driven by the sample Rate Generator.
- */
-#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B |   \
-                     SND_SOC_DAIFMT_CBM_CFS |  \
-                     SND_SOC_DAIFMT_IB_NF)
-
-static int sffsdr_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int fs;
-       int ret = 0;
-
-       /* Fsref can be 32000, 44100 or 48000. */
-       fs = params_rate(params);
-
-#ifndef CONFIG_SFFSDR_FPGA
-       /* Without the FPGA module, the Fs is fixed at 44100 Hz */
-       if (fs != 44100) {
-               pr_debug("warning: only 44.1 kHz is supported without SFFSDR FPGA module\n");
-               return -EINVAL;
-       }
-#endif
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
-       if (ret < 0)
-               return ret;
-
-       pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs);
-
-#ifndef CONFIG_SFFSDR_FPGA
-       return 0;
-#else
-       return sffsdr_fpga_set_codec_fs(fs);
-#endif
-}
-
-static struct snd_soc_ops sffsdr_ops = {
-       .hw_params = sffsdr_hw_params,
-};
-
-/* davinci-sffsdr digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link sffsdr_dai = {
-       .name = "PCM3008", /* Codec name */
-       .stream_name = "PCM3008 HiFi",
-       .cpu_dai_name = "davinci-mcbsp",
-       .codec_dai_name = "pcm3008-hifi",
-       .codec_name = "pcm3008-codec",
-       .platform_name = "davinci-mcbsp",
-       .ops = &sffsdr_ops,
-};
-
-/* davinci-sffsdr audio machine driver */
-static struct snd_soc_card snd_soc_sffsdr = {
-       .name = "DaVinci SFFSDR",
-       .owner = THIS_MODULE,
-       .dai_link = &sffsdr_dai,
-       .num_links = 1,
-};
-
-/* sffsdr audio private data */
-static struct pcm3008_setup_data sffsdr_pcm3008_setup = {
-       .dem0_pin = GPIO(45),
-       .dem1_pin = GPIO(46),
-       .pdad_pin = GPIO(47),
-       .pdda_pin = GPIO(38),
-};
-
-struct platform_device pcm3008_codec = {
-               .name = "pcm3008-codec",
-               .id = 0,
-               .dev = {
-                               .platform_data = &sffsdr_pcm3008_setup,
-               },
-};
-
-static struct resource sffsdr_snd_resources[] = {
-       {
-               .start = DAVINCI_MCBSP_BASE,
-               .end = DAVINCI_MCBSP_BASE + SZ_8K - 1,
-               .flags = IORESOURCE_MEM,
-       },
-};
-
-static struct evm_snd_platform_data sffsdr_snd_data = {
-       .tx_dma_ch      = DAVINCI_DMA_MCBSP_TX,
-       .rx_dma_ch      = DAVINCI_DMA_MCBSP_RX,
-};
-
-static struct platform_device *sffsdr_snd_device;
-
-static int __init sffsdr_init(void)
-{
-       int ret;
-
-       if (!machine_is_sffsdr())
-               return -EINVAL;
-
-       platform_device_register(&pcm3008_codec);
-
-       sffsdr_snd_device = platform_device_alloc("soc-audio", 0);
-       if (!sffsdr_snd_device) {
-               printk(KERN_ERR "platform device allocation failed\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(sffsdr_snd_device, &snd_soc_sffsdr);
-       platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data,
-                                sizeof(sffsdr_snd_data));
-
-       ret = platform_device_add_resources(sffsdr_snd_device,
-                                           sffsdr_snd_resources,
-                                           ARRAY_SIZE(sffsdr_snd_resources));
-       if (ret) {
-               printk(KERN_ERR "platform device add resources failed\n");
-               goto error;
-       }
-
-       ret = platform_device_add(sffsdr_snd_device);
-       if (ret)
-               goto error;
-
-       return ret;
-
-error:
-       platform_device_put(sffsdr_snd_device);
-       return ret;
-}
-
-static void __exit sffsdr_exit(void)
-{
-       platform_device_unregister(sffsdr_snd_device);
-       platform_device_unregister(&pcm3008_codec);
-}
-
-module_init(sffsdr_init);
-module_exit(sffsdr_exit);
-
-MODULE_AUTHOR("Hugo Villeneuve");
-MODULE_DESCRIPTION("Lyrtech SFFSDR ASoC driver");
-MODULE_LICENSE("GPL");
index 593a3ea12d4c3cca61caa6976d94847478a0c6dc..70eb37a5dd16337614abd50462521706b6f7f9b3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ALSA SoC Synopsys I2S Audio Layer
  *
- * sound/soc/spear/designware_i2s.c
+ * sound/soc/dwc/designware_i2s.c
  *
  * Copyright (C) 2010 ST Microelectronics
  * Rajeev Kumar <rajeev-dlh.kumar@st.com>
@@ -396,7 +396,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
        }
 
        if (cap & DWC_I2S_PLAY) {
-               dev_dbg(&pdev->dev, " SPEAr: play supported\n");
+               dev_dbg(&pdev->dev, " designware: play supported\n");
                dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
                dw_i2s_dai->playback.channels_max = pdata->channel;
                dw_i2s_dai->playback.formats = pdata->snd_fmts;
@@ -404,7 +404,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
        }
 
        if (cap & DWC_I2S_RECORD) {
-               dev_dbg(&pdev->dev, "SPEAr: record supported\n");
+               dev_dbg(&pdev->dev, "designware: record supported\n");
                dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
                dw_i2s_dai->capture.channels_max = pdata->channel;
                dw_i2s_dai->capture.formats = pdata->snd_fmts;
index 3843a18d4e567afbb64b9fde3a2b5e1b85bc2a0d..aa438546c91271f69c26beb1646b85f4b34357cf 100644 (file)
@@ -108,18 +108,13 @@ if SND_IMX_SOC
 config SND_SOC_IMX_SSI
        tristate
 
-config SND_SOC_IMX_PCM
-       tristate
-
 config SND_SOC_IMX_PCM_FIQ
        bool
        select FIQ
-       select SND_SOC_IMX_PCM
 
 config SND_SOC_IMX_PCM_DMA
        bool
        select SND_SOC_GENERIC_DMAENGINE_PCM
-       select SND_SOC_IMX_PCM
 
 config SND_SOC_IMX_AUDMUX
        tristate
@@ -173,6 +168,18 @@ config SND_SOC_EUKREA_TLV320
          Enable I2S based access to the TLV320AIC23B codec attached
          to the SSI interface
 
+config SND_SOC_IMX_WM8962
+       tristate "SoC Audio support for i.MX boards with wm8962"
+       depends on OF && I2C
+       select SND_SOC_WM8962
+       select SND_SOC_IMX_PCM_DMA
+       select SND_SOC_IMX_AUDMUX
+       select SND_SOC_FSL_SSI
+       select SND_SOC_FSL_UTILS
+       help
+         Say Y if you want to add support for SoC audio on an i.MX board with
+         a wm8962 codec.
+
 config SND_SOC_IMX_SGTL5000
        tristate "SoC Audio support for i.MX boards with sgtl5000"
        depends on OF && I2C
index afd34794db539a0f5de4154a5a635a69f40913e1..d4b4aa8b5649d3ccefdedc6a51852dafacf2286f 100644 (file)
@@ -30,18 +30,11 @@ obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 # i.MX Platform Support
 snd-soc-imx-ssi-objs := imx-ssi.o
 snd-soc-imx-audmux-objs := imx-audmux.o
-snd-soc-imx-pcm-objs := imx-pcm.o
-ifneq ($(CONFIG_SND_SOC_IMX_PCM_FIQ),)
-       snd-soc-imx-pcm-objs += imx-pcm-fiq.o
-endif
-ifneq ($(CONFIG_SND_SOC_IMX_PCM_DMA),)
-       snd-soc-imx-pcm-objs += imx-pcm-dma.o
-endif
-
 obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
 obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
 
-obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
+obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
+obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
 
 # i.MX Machine Support
 snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
@@ -49,6 +42,7 @@ snd-soc-phycore-ac97-objs := phycore-ac97.o
 snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
 snd-soc-wm1133-ev1-objs := wm1133-ev1.o
 snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
+snd-soc-imx-wm8962-objs := imx-wm8962.o
 snd-soc-imx-mc13783-objs := imx-mc13783.o
 
 obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
@@ -56,4 +50,5 @@ obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
 obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
 obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
 obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
+obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
 obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
index 75ffdf0e2aada7dc3a75d1d481014b8e7f94d160..9a4a0ca2c1def78c2a1f5566c168dd2c0ccb04ba 100644 (file)
@@ -80,7 +80,7 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
        .codec_dai_name = "tlv320aic23-hifi",
-       .platform_name  = "imx-fiq-pcm-audio.0",
+       .platform_name  = "imx-ssi.0",
        .codec_name     = "tlv320aic23-codec.0-001a",
        .cpu_dai_name   = "imx-ssi.0",
        .ops            = &eukrea_tlv320_snd_ops,
index 0f0bed6def9ed5b370dfb4887b0359bb7fbe47a5..2f2d837df07f078e5b60da38308cbdb8d53b9969 100644 (file)
@@ -122,7 +122,6 @@ struct fsl_ssi_private {
        bool new_binding;
        bool ssi_on_imx;
        struct clk *clk;
-       struct platform_device *imx_pcm_pdev;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct imx_dma_data filter_data_tx;
@@ -809,13 +808,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        }
 
        if (ssi_private->ssi_on_imx) {
-               ssi_private->imx_pcm_pdev =
-                       platform_device_register_simple("imx-pcm-audio",
-                                                       -1, NULL, 0);
-               if (IS_ERR(ssi_private->imx_pcm_pdev)) {
-                       ret = PTR_ERR(ssi_private->imx_pcm_pdev);
+               ret = imx_pcm_dma_init(pdev);
+               if (ret)
                        goto error_dev;
-               }
        }
 
        /*
@@ -854,7 +849,7 @@ done:
 
 error_dai:
        if (ssi_private->ssi_on_imx)
-               platform_device_unregister(ssi_private->imx_pcm_pdev);
+               imx_pcm_dma_exit(pdev);
        snd_soc_unregister_component(&pdev->dev);
 
 error_dev:
@@ -889,7 +884,7 @@ static int fsl_ssi_remove(struct platform_device *pdev)
        if (!ssi_private->new_binding)
                platform_device_unregister(ssi_private->pdev);
        if (ssi_private->ssi_on_imx) {
-               platform_device_unregister(ssi_private->imx_pcm_pdev);
+               imx_pcm_dma_exit(pdev);
                clk_disable_unprepare(ssi_private->clk);
                clk_put(ssi_private->clk);
        }
index 47f046a8fdab8240d7e47756e532151aabee969d..e260f1f899dbb132135cb6745376f5dad8891fb9 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/pinctrl/consumer.h>
 
 #include "imx-audmux.h"
 
@@ -247,7 +246,6 @@ EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port);
 static int imx_audmux_probe(struct platform_device *pdev)
 {
        struct resource *res;
-       struct pinctrl *pinctrl;
        const struct of_device_id *of_id =
                        of_match_device(imx_audmux_dt_ids, &pdev->dev);
 
@@ -256,12 +254,6 @@ static int imx_audmux_probe(struct platform_device *pdev)
        if (IS_ERR(audmux_base))
                return PTR_ERR(audmux_base);
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               dev_err(&pdev->dev, "setup pinctrl failed!");
-               return PTR_ERR(pinctrl);
-       }
-
        audmux_clk = devm_clk_get(&pdev->dev, "audmux");
        if (IS_ERR(audmux_clk)) {
                dev_dbg(&pdev->dev, "cannot get clock: %ld\n",
index 4ae30f21fdb5385c003553e31c60bcaaa60d23cb..9df173c091a66b4fbb676036b9a66cacfe2eff17 100644 (file)
@@ -64,7 +64,7 @@ static struct snd_soc_dai_link imx_mc13783_dai_mc13783[] = {
                .codec_dai_name  = "mc13783-hifi",
                .codec_name      = "mc13783-codec",
                .cpu_dai_name    = "imx-ssi.0",
-               .platform_name   = "imx-pcm-audio.0",
+               .platform_name   = "imx-ssi.0",
                .ops             = &imx_mc13783_hifi_ops,
                .symmetric_rates = 1,
                .dai_fmt         = FMT_SSI,
index c246fb514930b718a509bbf699b2914feefd956e..fde4d2ea68c88afb32275963ae0b51e81be9112a 100644 (file)
@@ -67,8 +67,10 @@ int imx_pcm_dma_init(struct platform_device *pdev)
                SND_DMAENGINE_PCM_FLAG_NO_DT |
                SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
+EXPORT_SYMBOL_GPL(imx_pcm_dma_init);
 
 void imx_pcm_dma_exit(struct platform_device *pdev)
 {
        snd_dmaengine_pcm_unregister(&pdev->dev);
 }
+EXPORT_SYMBOL_GPL(imx_pcm_dma_exit);
index 670b96b0ce2f50e417a9860fd3a73e3ad701c119..310d90290320c751b572f2a409f8c4800f6c60b2 100644 (file)
@@ -225,6 +225,22 @@ static int snd_imx_close(struct snd_pcm_substream *substream)
        return 0;
 }
 
+static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
+               struct vm_area_struct *vma)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret;
+
+       ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
+               runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
+
+       pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
+                       runtime->dma_area,
+                       runtime->dma_addr,
+                       runtime->dma_bytes);
+       return ret;
+}
+
 static struct snd_pcm_ops imx_pcm_ops = {
        .open           = snd_imx_open,
        .close          = snd_imx_close,
@@ -236,6 +252,54 @@ static struct snd_pcm_ops imx_pcm_ops = {
        .mmap           = snd_imx_pcm_mmap,
 };
 
+static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+       size_t size = IMX_SSI_DMABUF_SIZE;
+
+       buf->dev.type = SNDRV_DMA_TYPE_DEV;
+       buf->dev.dev = pcm->card->dev;
+       buf->private_data = NULL;
+       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+                                          &buf->addr, GFP_KERNEL);
+       if (!buf->area)
+               return -ENOMEM;
+       buf->bytes = size;
+
+       return 0;
+}
+
+static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
+
+static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_pcm *pcm = rtd->pcm;
+       int ret = 0;
+
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &imx_pcm_dmamask;
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+               ret = imx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_PLAYBACK);
+               if (ret)
+                       goto out;
+       }
+
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+               ret = imx_pcm_preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_CAPTURE);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       return ret;
+}
+
 static int ssi_irq = 0;
 
 static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd)
@@ -268,6 +332,27 @@ static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
+static void imx_pcm_free(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+       int stream;
+
+       for (stream = 0; stream < 2; stream++) {
+               substream = pcm->streams[stream].substream;
+               if (!substream)
+                       continue;
+
+               buf = &substream->dma_buffer;
+               if (!buf->area)
+                       continue;
+
+               dma_free_writecombine(pcm->card->dev, buf->bytes,
+                                     buf->area, buf->addr);
+               buf->area = NULL;
+       }
+}
+
 static void imx_pcm_fiq_free(struct snd_pcm *pcm)
 {
        mxc_set_irq_fiq(ssi_irq, 0);
@@ -314,3 +399,10 @@ failed_register:
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(imx_pcm_fiq_init);
+
+void imx_pcm_fiq_exit(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+}
+EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit);
diff --git a/sound/soc/fsl/imx-pcm.c b/sound/soc/fsl/imx-pcm.c
deleted file mode 100644 (file)
index c498964..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
- *
- * This code is based on code copyrighted by Freescale,
- * Liam Girdwood, Javier Martin and probably others.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the 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/dma-mapping.h>
-#include <linux/module.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include "imx-pcm.h"
-
-int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
-               struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int ret;
-
-       ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
-               runtime->dma_area, runtime->dma_addr, runtime->dma_bytes);
-
-       pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
-                       runtime->dma_area,
-                       runtime->dma_addr,
-                       runtime->dma_bytes);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
-
-static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-       size_t size = IMX_SSI_DMABUF_SIZE;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                                          &buf->addr, GFP_KERNEL);
-       if (!buf->area)
-               return -ENOMEM;
-       buf->bytes = size;
-
-       return 0;
-}
-
-static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
-
-int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       struct snd_pcm *pcm = rtd->pcm;
-       int ret = 0;
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &imx_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
-               ret = imx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
-
-       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
-               ret = imx_pcm_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
-
-out:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(imx_pcm_new);
-
-void imx_pcm_free(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes,
-                                     buf->area, buf->addr);
-               buf->area = NULL;
-       }
-}
-EXPORT_SYMBOL_GPL(imx_pcm_free);
-
-static int imx_pcm_probe(struct platform_device *pdev)
-{
-       if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0)
-               return imx_pcm_fiq_init(pdev);
-
-       return imx_pcm_dma_init(pdev);
-}
-
-static int imx_pcm_remove(struct platform_device *pdev)
-{
-       if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0)
-               snd_soc_unregister_platform(&pdev->dev);
-       else
-               imx_pcm_dma_exit(pdev);
-
-       return 0;
-}
-
-static struct platform_device_id imx_pcm_devtype[] = {
-       { .name = "imx-pcm-audio", },
-       { .name = "imx-fiq-pcm-audio", },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, imx_pcm_devtype);
-
-static struct platform_driver imx_pcm_driver = {
-       .driver = {
-                       .name = "imx-pcm",
-                       .owner = THIS_MODULE,
-       },
-       .id_table = imx_pcm_devtype,
-       .probe = imx_pcm_probe,
-       .remove = imx_pcm_remove,
-};
-module_platform_driver(imx_pcm_driver);
-
-MODULE_DESCRIPTION("Freescale i.MX PCM driver");
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_LICENSE("GPL");
index b7fa0d75c687ecc4e3dc0033d5286856bd8ddaac..67f656c7c320744334d4ca5d8233d36eacbe6d4d 100644 (file)
@@ -32,11 +32,6 @@ imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
                dma_data->peripheral_type = IMX_DMATYPE_SSI;
 }
 
-int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
-                    struct vm_area_struct *vma);
-int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
-void imx_pcm_free(struct snd_pcm *pcm);
-
 #ifdef CONFIG_SND_SOC_IMX_PCM_DMA
 int imx_pcm_dma_init(struct platform_device *pdev);
 void imx_pcm_dma_exit(struct platform_device *pdev);
@@ -53,11 +48,16 @@ static inline void imx_pcm_dma_exit(struct platform_device *pdev)
 
 #ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
 int imx_pcm_fiq_init(struct platform_device *pdev);
+void imx_pcm_fiq_exit(struct platform_device *pdev);
 #else
 static inline int imx_pcm_fiq_init(struct platform_device *pdev)
 {
        return -ENODEV;
 }
+
+static inline void imx_pcm_fiq_exit(struct platform_device *pdev)
+{
+}
 #endif
 
 #endif /* _IMX_PCM_H */
index 9584e78858df0a7a407ce9d07b3f9f159002cc10..7a8bc1220b2e52ace3eec9a6e928184c27546cdb 100644 (file)
@@ -128,28 +128,18 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
                goto fail;
        }
 
-       data->codec_clk = clk_get(&codec_dev->dev, NULL);
-       if (IS_ERR(data->codec_clk)) {
-               /* assuming clock enabled by default */
-               data->codec_clk = NULL;
-               ret = of_property_read_u32(codec_np, "clock-frequency",
-                                       &data->clk_frequency);
-               if (ret) {
-                       dev_err(&codec_dev->dev,
-                               "clock-frequency missing or invalid\n");
-                       goto fail;
-               }
-       } else {
-               data->clk_frequency = clk_get_rate(data->codec_clk);
-               clk_prepare_enable(data->codec_clk);
-       }
+       data->codec_clk = devm_clk_get(&codec_dev->dev, NULL);
+       if (IS_ERR(data->codec_clk))
+               goto fail;
+
+       data->clk_frequency = clk_get_rate(data->codec_clk);
 
        data->dai.name = "HiFi";
        data->dai.stream_name = "HiFi";
        data->dai.codec_dai_name = "sgtl5000";
        data->dai.codec_of_node = codec_np;
        data->dai.cpu_of_node = ssi_np;
-       data->dai.platform_name = "imx-pcm-audio";
+       data->dai.platform_of_node = ssi_np;
        data->dai.init = &imx_sgtl5000_dai_init;
        data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                            SND_SOC_DAIFMT_CBM_CFM;
@@ -157,10 +147,10 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        data->card.dev = &pdev->dev;
        ret = snd_soc_of_parse_card_name(&data->card, "model");
        if (ret)
-               goto clk_fail;
+               goto fail;
        ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
        if (ret)
-               goto clk_fail;
+               goto fail;
        data->card.num_links = 1;
        data->card.owner = THIS_MODULE;
        data->card.dai_link = &data->dai;
@@ -170,12 +160,15 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        ret = snd_soc_register_card(&data->card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
-               goto clk_fail;
+               goto fail;
        }
 
        platform_set_drvdata(pdev, data);
-clk_fail:
-       clk_put(data->codec_clk);
+       of_node_put(ssi_np);
+       of_node_put(codec_np);
+
+       return 0;
+
 fail:
        if (ssi_np)
                of_node_put(ssi_np);
@@ -189,10 +182,6 @@ static int imx_sgtl5000_remove(struct platform_device *pdev)
 {
        struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
 
-       if (data->codec_clk) {
-               clk_disable_unprepare(data->codec_clk);
-               clk_put(data->codec_clk);
-       }
        snd_soc_unregister_card(&data->card);
 
        return 0;
index c6fa03e2114ab985186cb8f86a3ee6f4317dc4bc..51be3772cba901bc17d245ab0077ec744fcf64b2 100644 (file)
@@ -501,13 +501,12 @@ static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
        imx_ssi_ac97_read(ac97, 0);
 }
 
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops imx_ssi_ac97_ops = {
        .read           = imx_ssi_ac97_read,
        .write          = imx_ssi_ac97_write,
        .reset          = imx_ssi_ac97_reset,
        .warm_reset     = imx_ssi_ac97_warm_reset
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static int imx_ssi_probe(struct platform_device *pdev)
 {
@@ -583,6 +582,12 @@ static int imx_ssi_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ssi);
 
+       ret = snd_soc_set_ac97_ops(&imx_ssi_ac97_ops);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
+               goto failed_register;
+       }
+
        ret = snd_soc_register_component(&pdev->dev, &imx_component,
                                         dai, 1);
        if (ret) {
@@ -590,46 +595,25 @@ static int imx_ssi_probe(struct platform_device *pdev)
                goto failed_register;
        }
 
-       ssi->soc_platform_pdev_fiq = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
-       if (!ssi->soc_platform_pdev_fiq) {
-               ret = -ENOMEM;
-               goto failed_pdev_fiq_alloc;
-       }
+       ret = imx_pcm_fiq_init(pdev);
+       if (ret)
+               goto failed_pcm_fiq;
 
-       platform_set_drvdata(ssi->soc_platform_pdev_fiq, ssi);
-       ret = platform_device_add(ssi->soc_platform_pdev_fiq);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add platform device\n");
-               goto failed_pdev_fiq_add;
-       }
-
-       ssi->soc_platform_pdev = platform_device_alloc("imx-pcm-audio", pdev->id);
-       if (!ssi->soc_platform_pdev) {
-               ret = -ENOMEM;
-               goto failed_pdev_alloc;
-       }
-
-       platform_set_drvdata(ssi->soc_platform_pdev, ssi);
-       ret = platform_device_add(ssi->soc_platform_pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add platform device\n");
-               goto failed_pdev_add;
-       }
+       ret = imx_pcm_dma_init(pdev);
+       if (ret)
+               goto failed_pcm_dma;
 
        return 0;
 
-failed_pdev_add:
-       platform_device_put(ssi->soc_platform_pdev);
-failed_pdev_alloc:
-       platform_device_del(ssi->soc_platform_pdev_fiq);
-failed_pdev_fiq_add:
-       platform_device_put(ssi->soc_platform_pdev_fiq);
-failed_pdev_fiq_alloc:
+failed_pcm_dma:
+       imx_pcm_fiq_exit(pdev);
+failed_pcm_fiq:
        snd_soc_unregister_component(&pdev->dev);
 failed_register:
        release_mem_region(res->start, resource_size(res));
        clk_disable_unprepare(ssi->clk);
 failed_clk:
+       snd_soc_set_ac97_ops(NULL);
 
        return ret;
 }
@@ -639,8 +623,8 @@ static int imx_ssi_remove(struct platform_device *pdev)
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct imx_ssi *ssi = platform_get_drvdata(pdev);
 
-       platform_device_unregister(ssi->soc_platform_pdev);
-       platform_device_unregister(ssi->soc_platform_pdev_fiq);
+       imx_pcm_dma_exit(pdev);
+       imx_pcm_fiq_exit(pdev);
 
        snd_soc_unregister_component(&pdev->dev);
 
@@ -649,6 +633,7 @@ static int imx_ssi_remove(struct platform_device *pdev)
 
        release_mem_region(res->start, resource_size(res));
        clk_disable_unprepare(ssi->clk);
+       snd_soc_set_ac97_ops(NULL);
 
        return 0;
 }
index bb6b3dbb13fdce8b3f81ea27a069395fd0ab3904..d5003cefca8decee028d937a9a9a975bb703102d 100644 (file)
@@ -211,9 +211,6 @@ struct imx_ssi {
        struct imx_dma_data filter_data_rx;
 
        int enabled;
-
-       struct platform_device *soc_platform_pdev;
-       struct platform_device *soc_platform_pdev_fiq;
 };
 
 #endif /* _IMX_SSI_H */
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c
new file mode 100644 (file)
index 0000000..52a36a9
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * Based on imx-sgtl5000.c
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "../codecs/wm8962.h"
+#include "imx-audmux.h"
+
+#define DAI_NAME_SIZE  32
+
+struct imx_wm8962_data {
+       struct snd_soc_dai_link dai;
+       struct snd_soc_card card;
+       char codec_dai_name[DAI_NAME_SIZE];
+       char platform_name[DAI_NAME_SIZE];
+       struct clk *codec_clk;
+       unsigned int clk_frequency;
+};
+
+struct imx_priv {
+       struct platform_device *pdev;
+};
+static struct imx_priv card_priv;
+
+static const struct snd_soc_dapm_widget imx_wm8962_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_MIC("AMIC", NULL),
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
+static int sample_rate = 44100;
+static snd_pcm_format_t sample_format = SNDRV_PCM_FORMAT_S16_LE;
+
+static int imx_hifi_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       sample_rate = params_rate(params);
+       sample_format = params_format(params);
+
+       return 0;
+}
+
+static struct snd_soc_ops imx_hifi_ops = {
+       .hw_params = imx_hifi_hw_params,
+};
+
+static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
+                                       struct snd_soc_dapm_context *dapm,
+                                       enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct imx_priv *priv = &card_priv;
+       struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+       struct device *dev = &priv->pdev->dev;
+       unsigned int pll_out;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+                       if (sample_format == SNDRV_PCM_FORMAT_S24_LE)
+                               pll_out = sample_rate * 384;
+                       else
+                               pll_out = sample_rate * 256;
+
+                       ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
+                                       WM8962_FLL_MCLK, data->clk_frequency,
+                                       pll_out);
+                       if (ret < 0) {
+                               dev_err(dev, "failed to start FLL: %d\n", ret);
+                               return ret;
+                       }
+
+                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                       WM8962_SYSCLK_FLL, pll_out,
+                                       SND_SOC_CLOCK_IN);
+                       if (ret < 0) {
+                               dev_err(dev, "failed to set SYSCLK: %d\n", ret);
+                               return ret;
+                       }
+               }
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (dapm->bias_level == SND_SOC_BIAS_PREPARE) {
+                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                       WM8962_SYSCLK_MCLK, data->clk_frequency,
+                                       SND_SOC_CLOCK_IN);
+                       if (ret < 0) {
+                               dev_err(dev,
+                                       "failed to switch away from FLL: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
+                                       0, 0, 0);
+                       if (ret < 0) {
+                               dev_err(dev, "failed to stop FLL: %d\n", ret);
+                               return ret;
+                       }
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       dapm->bias_level = level;
+
+       return 0;
+}
+
+static int imx_wm8962_late_probe(struct snd_soc_card *card)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct imx_priv *priv = &card_priv;
+       struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+       struct device *dev = &priv->pdev->dev;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
+                       data->clk_frequency, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               dev_err(dev, "failed to set sysclk in %s\n", __func__);
+
+       return ret;
+}
+
+static int imx_wm8962_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *ssi_np, *codec_np;
+       struct platform_device *ssi_pdev;
+       struct imx_priv *priv = &card_priv;
+       struct i2c_client *codec_dev;
+       struct imx_wm8962_data *data;
+       int int_port, ext_port;
+       int ret;
+
+       priv->pdev = pdev;
+
+       ret = of_property_read_u32(np, "mux-int-port", &int_port);
+       if (ret) {
+               dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
+               return ret;
+       }
+       ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
+       if (ret) {
+               dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
+               return ret;
+       }
+
+       /*
+        * The port numbering in the hardware manual starts at 1, while
+        * the audmux API expects it starts at 0.
+        */
+       int_port--;
+       ext_port--;
+       ret = imx_audmux_v2_configure_port(int_port,
+                       IMX_AUDMUX_V2_PTCR_SYN |
+                       IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+                       IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+                       IMX_AUDMUX_V2_PTCR_TFSDIR |
+                       IMX_AUDMUX_V2_PTCR_TCLKDIR,
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+       if (ret) {
+               dev_err(&pdev->dev, "audmux internal port setup failed\n");
+               return ret;
+       }
+       imx_audmux_v2_configure_port(ext_port,
+                       IMX_AUDMUX_V2_PTCR_SYN,
+                       IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+       if (ret) {
+               dev_err(&pdev->dev, "audmux external port setup failed\n");
+               return ret;
+       }
+
+       ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
+       codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
+       if (!ssi_np || !codec_np) {
+               dev_err(&pdev->dev, "phandle missing or invalid\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       ssi_pdev = of_find_device_by_node(ssi_np);
+       if (!ssi_pdev) {
+               dev_err(&pdev->dev, "failed to find SSI platform device\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+       codec_dev = of_find_i2c_device_by_node(codec_np);
+       if (!codec_dev || !codec_dev->driver) {
+               dev_err(&pdev->dev, "failed to find codec platform device\n");
+               return -EINVAL;
+       }
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       data->codec_clk = devm_clk_get(&codec_dev->dev, NULL);
+       if (IS_ERR(data->codec_clk)) {
+               ret = PTR_ERR(data->codec_clk);
+               dev_err(&codec_dev->dev, "failed to get codec clk: %d\n", ret);
+               goto fail;
+       }
+
+       data->clk_frequency = clk_get_rate(data->codec_clk);
+       ret = clk_prepare_enable(data->codec_clk);
+       if (ret) {
+               dev_err(&codec_dev->dev, "failed to enable codec clk: %d\n", ret);
+               goto fail;
+       }
+
+       data->dai.name = "HiFi";
+       data->dai.stream_name = "HiFi";
+       data->dai.codec_dai_name = "wm8962";
+       data->dai.codec_of_node = codec_np;
+       data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev);
+       data->dai.platform_of_node = ssi_np;
+       data->dai.ops = &imx_hifi_ops;
+       data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                           SND_SOC_DAIFMT_CBM_CFM;
+
+       data->card.dev = &pdev->dev;
+       ret = snd_soc_of_parse_card_name(&data->card, "model");
+       if (ret)
+               goto clk_fail;
+       ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
+       if (ret)
+               goto clk_fail;
+       data->card.num_links = 1;
+       data->card.dai_link = &data->dai;
+       data->card.dapm_widgets = imx_wm8962_dapm_widgets;
+       data->card.num_dapm_widgets = ARRAY_SIZE(imx_wm8962_dapm_widgets);
+
+       data->card.late_probe = imx_wm8962_late_probe;
+       data->card.set_bias_level = imx_wm8962_set_bias_level;
+
+       ret = snd_soc_register_card(&data->card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+               goto clk_fail;
+       }
+
+       platform_set_drvdata(pdev, data);
+       of_node_put(ssi_np);
+       of_node_put(codec_np);
+
+       return 0;
+
+clk_fail:
+       if (!IS_ERR(data->codec_clk))
+               clk_disable_unprepare(data->codec_clk);
+fail:
+       if (ssi_np)
+               of_node_put(ssi_np);
+       if (codec_np)
+               of_node_put(codec_np);
+
+       return ret;
+}
+
+static int imx_wm8962_remove(struct platform_device *pdev)
+{
+       struct imx_wm8962_data *data = platform_get_drvdata(pdev);
+
+       if (!IS_ERR(data->codec_clk))
+               clk_disable_unprepare(data->codec_clk);
+       snd_soc_unregister_card(&data->card);
+
+       return 0;
+}
+
+static const struct of_device_id imx_wm8962_dt_ids[] = {
+       { .compatible = "fsl,imx-audio-wm8962", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_wm8962_dt_ids);
+
+static struct platform_driver imx_wm8962_driver = {
+       .driver = {
+               .name = "imx-wm8962",
+               .owner = THIS_MODULE,
+               .of_match_table = imx_wm8962_dt_ids,
+       },
+       .probe = imx_wm8962_probe,
+       .remove = imx_wm8962_remove,
+};
+module_platform_driver(imx_wm8962_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale i.MX WM8962 ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-wm8962");
index 4141b35ef0bbd27947d3d4147e482b34d45f58a1..3ef7a0c92efa07eb4719aadfefacf5c050a008cd 100644 (file)
@@ -131,13 +131,12 @@ static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
        psc_ac97_warm_reset(ac97);
 }
 
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops psc_ac97_ops = {
        .read           = psc_ac97_read,
        .write          = psc_ac97_write,
        .reset          = psc_ac97_cold_reset,
        .warm_reset     = psc_ac97_warm_reset,
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
@@ -290,6 +289,12 @@ static int psc_ac97_of_probe(struct platform_device *op)
        if (rc != 0)
                return rc;
 
+       rc = snd_soc_set_ac97_ops(&psc_ac97_ops);
+       if (rc != 0) {
+               dev_err(&op->dev, "Failed to set AC'97 ops: %d\n", ret);
+               return rc;
+       }
+
        rc = snd_soc_register_component(&op->dev, &psc_ac97_component,
                                        psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
        if (rc != 0) {
@@ -318,6 +323,7 @@ static int psc_ac97_of_remove(struct platform_device *op)
 {
        mpc5200_audio_dma_destroy(op);
        snd_soc_unregister_component(&op->dev);
+       snd_soc_set_ac97_ops(NULL);
        return 0;
 }
 
index 3d1074179057936faa402e90de0f8752822f60f4..f4c3bda5e69e1637936735a2278fcbf6471d2c4d 100644 (file)
@@ -161,7 +161,7 @@ static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
        .name           = "tlv320aic32x4",
        .stream_name    = "TLV320AIC32X4",
        .codec_dai_name = "tlv320aic32x4-hifi",
-       .platform_name  = "imx-pcm-audio.0",
+       .platform_name  = "imx-ssi.0",
        .codec_name     = "tlv320aic32x4.0-0018",
        .cpu_dai_name   = "imx-ssi.0",
        .ops            = &mx27vis_aic32x4_snd_ops,
index f8da6dd115ed1c292d66fe0d7bee395ba849f2f7..ae403c29688f51605af5c2f29a72fe70e9ac00e0 100644 (file)
@@ -33,7 +33,7 @@ static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
                .codec_dai_name         = "wm9712-hifi",
                .codec_name     = "wm9712-codec",
                .cpu_dai_name   = "imx-ssi.0",
-               .platform_name  = "imx-fiq-pcm-audio.0",
+               .platform_name  = "imx-ssi.0",
                .ops            = &imx_phycore_hifi_ops,
        },
 };
index fe54a69073e5cca05920b9d9b1864f916b261696..fce63252bdbbfda7cc1d7d0cefa2295f26faf43d 100644 (file)
@@ -245,7 +245,7 @@ static struct snd_soc_dai_link wm1133_ev1_dai = {
        .stream_name = "Audio",
        .cpu_dai_name = "imx-ssi.0",
        .codec_dai_name = "wm8350-hifi",
-       .platform_name = "imx-fiq-pcm-audio.0",
+       .platform_name = "imx-ssi.0",
        .codec_name = "wm8350-codec.0-0x1a",
        .init = wm1133_ev1_init,
        .ops = &wm1133_ev1_ops,
index 9a126441c5f379c0f00cc85bf7e36be34c3bd8a9..4c849a49c72ac3c6c6800aebec9292b3785be37c 100644 (file)
@@ -118,7 +118,7 @@ static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
        ctrl |= JZ_AIC_CTRL_FLUSH;
        jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
 
-       clk_enable(i2s->clk_i2s);
+       clk_prepare_enable(i2s->clk_i2s);
 
        conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
        conf |= JZ_AIC_CONF_ENABLE;
@@ -140,7 +140,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
        conf &= ~JZ_AIC_CONF_ENABLE;
        jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
 
-       clk_disable(i2s->clk_i2s);
+       clk_disable_unprepare(i2s->clk_i2s);
 }
 
 static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -314,10 +314,10 @@ static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
                conf &= ~JZ_AIC_CONF_ENABLE;
                jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
 
-               clk_disable(i2s->clk_i2s);
+               clk_disable_unprepare(i2s->clk_i2s);
        }
 
-       clk_disable(i2s->clk_aic);
+       clk_disable_unprepare(i2s->clk_aic);
 
        return 0;
 }
@@ -327,10 +327,10 @@ static int jz4740_i2s_resume(struct snd_soc_dai *dai)
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
-       clk_enable(i2s->clk_aic);
+       clk_prepare_enable(i2s->clk_aic);
 
        if (dai->active) {
-               clk_enable(i2s->clk_i2s);
+               clk_prepare_enable(i2s->clk_i2s);
 
                conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
                conf |= JZ_AIC_CONF_ENABLE;
@@ -368,7 +368,7 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
-       clk_enable(i2s->clk_aic);
+       clk_prepare_enable(i2s->clk_aic);
 
        jz4740_i2c_init_pcm_config(i2s);
 
@@ -388,7 +388,7 @@ static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
-       clk_disable(i2s->clk_aic);
+       clk_disable_unprepare(i2s->clk_aic);
        return 0;
 }
 
@@ -509,7 +509,6 @@ static int jz4740_i2s_dev_remove(struct platform_device *pdev)
        iounmap(i2s->base);
        release_mem_region(i2s->mem->start, resource_size(i2s->mem));
 
-       platform_set_drvdata(pdev, NULL);
        kfree(i2s);
 
        return 0;
index d3d4bdca1cc62d0387ca558cb7b7b020209b6f63..a9f14530c3db6a5eb9d3425f7bd6ef5ba4106add 100644 (file)
@@ -289,7 +289,7 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
        return count;
 }
 
-struct snd_pcm_ops kirkwood_dma_ops = {
+static struct snd_pcm_ops kirkwood_dma_ops = {
        .open =         kirkwood_dma_open,
        .close =        kirkwood_dma_close,
        .ioctl =        snd_pcm_lib_ioctl,
index 4139116c33b51f85bbc1794a885488f14811ec7e..ee363845759eca555346193ce17d740868d5fd6d 100644 (file)
@@ -371,7 +371,7 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
 
        /* audio interrupt base of SRAM location where
         * interrupts are stored by System FW */
-       mc_drv_ctx = kzalloc(sizeof(*mc_drv_ctx), GFP_ATOMIC);
+       mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
        if (!mc_drv_ctx) {
                pr_err("allocation failed\n");
                return -ENOMEM;
@@ -381,51 +381,39 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
                                pdev, IORESOURCE_MEM, "IRQ_BASE");
        if (!irq_mem) {
                pr_err("no mem resource given\n");
-               ret_val = -ENODEV;
-               goto unalloc;
+               return -ENODEV;
        }
-       mc_drv_ctx->int_base = ioremap_nocache(irq_mem->start,
-                                       resource_size(irq_mem));
+       mc_drv_ctx->int_base = devm_ioremap_nocache(&pdev->dev, irq_mem->start,
+                                                   resource_size(irq_mem));
        if (!mc_drv_ctx->int_base) {
                pr_err("Mapping of cache failed\n");
-               ret_val = -ENOMEM;
-               goto unalloc;
+               return -ENOMEM;
        }
        /* register for interrupt */
-       ret_val = request_threaded_irq(irq, snd_mfld_jack_intr_handler,
+       ret_val = devm_request_threaded_irq(&pdev->dev, irq,
+                       snd_mfld_jack_intr_handler,
                        snd_mfld_jack_detection,
                        IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
        if (ret_val) {
                pr_err("cannot register IRQ\n");
-               goto unalloc;
+               return ret_val;
        }
        /* register the soc card */
        snd_soc_card_mfld.dev = &pdev->dev;
        ret_val = snd_soc_register_card(&snd_soc_card_mfld);
        if (ret_val) {
                pr_debug("snd_soc_register_card failed %d\n", ret_val);
-               goto freeirq;
+               return ret_val;
        }
        platform_set_drvdata(pdev, mc_drv_ctx);
        pr_debug("successfully exited probe\n");
-       return ret_val;
-
-freeirq:
-       free_irq(irq, mc_drv_ctx);
-unalloc:
-       kfree(mc_drv_ctx);
-       return ret_val;
+       return 0;
 }
 
 static int snd_mfld_mc_remove(struct platform_device *pdev)
 {
-       struct mfld_mc_private *mc_drv_ctx = platform_get_drvdata(pdev);
-
        pr_debug("snd_mfld_mc_remove called\n");
-       free_irq(platform_get_irq(pdev, 0), mc_drv_ctx);
        snd_soc_unregister_card(&snd_soc_card_mfld);
-       kfree(mc_drv_ctx);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index b41fffc056fbec0ec583256d3b336a9d3520b73f..b16abbbf7764beddd61d42514f70bd33338a7781 100644 (file)
@@ -49,24 +49,8 @@ static const struct snd_pcm_hardware snd_mxs_hardware = {
        .fifo_size              = 32,
 };
 
-static bool filter(struct dma_chan *chan, void *param)
-{
-       struct mxs_pcm_dma_params *dma_params = param;
-
-       if (!mxs_dma_is_apbx(chan))
-               return false;
-
-       if (chan->chan_id != dma_params->chan_num)
-               return false;
-
-       chan->private = &dma_params->dma_data;
-
-       return true;
-}
-
 static const struct snd_dmaengine_pcm_config mxs_dmaengine_pcm_config = {
        .pcm_hardware = &snd_mxs_hardware,
-       .compat_filter_fn = filter,
        .prealloc_buffer_size = 64 * 1024,
 };
 
@@ -74,8 +58,6 @@ int mxs_pcm_platform_register(struct device *dev)
 {
        return snd_dmaengine_pcm_register(dev, &mxs_dmaengine_pcm_config,
                SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
-               SND_DMAENGINE_PCM_FLAG_NO_DT |
-               SND_DMAENGINE_PCM_FLAG_COMPAT |
                SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX);
 }
 EXPORT_SYMBOL_GPL(mxs_pcm_platform_register);
index 3aa918f9ed3eeff4d5c554ce8fe261eb4576aa33..bc685b67cac71e80c17657357c9eb388eac0ac2e 100644 (file)
 #ifndef _MXS_PCM_H
 #define _MXS_PCM_H
 
-#include <linux/fsl/mxs-dma.h>
-
-struct mxs_pcm_dma_params {
-       struct mxs_dma_data dma_data;
-       int chan_num;
-};
-
 int mxs_pcm_platform_register(struct device *dev);
 void mxs_pcm_platform_unregister(struct device *dev);
 
index d31dc52fa8626ff2fcb04931cc815873f8e94067..49d870034bc34fa7061dd255d9c0f997614c0691 100644 (file)
@@ -26,8 +26,6 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/time.h>
-#include <linux/fsl/mxs-dma.h>
-#include <linux/pinctrl/consumer.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -605,8 +603,6 @@ static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
        struct mxs_saif *saif = dev_get_drvdata(dai->dev);
 
        snd_soc_dai_set_drvdata(dai, saif);
-       dai->playback_dma_data = &saif->dma_param;
-       dai->capture_dma_data = &saif->dma_param;
 
        return 0;
 }
@@ -665,9 +661,8 @@ static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
 static int mxs_saif_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       struct resource *iores, *dmares;
+       struct resource *iores;
        struct mxs_saif *saif;
-       struct pinctrl *pinctrl;
        int ret = 0;
        struct device_node *master;
 
@@ -707,12 +702,6 @@ static int mxs_saif_probe(struct platform_device *pdev)
 
        mxs_saif[saif->id] = saif;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               ret = PTR_ERR(pinctrl);
-               return ret;
-       }
-
        saif->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(saif->clk)) {
                ret = PTR_ERR(saif->clk);
@@ -727,22 +716,6 @@ static int mxs_saif_probe(struct platform_device *pdev)
        if (IS_ERR(saif->base))
                return PTR_ERR(saif->base);
 
-       dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmares) {
-               /*
-                * TODO: This is a temporary solution and should be changed
-                * to use generic DMA binding later when the helplers get in.
-                */
-               ret = of_property_read_u32(np, "fsl,saif-dma-channel",
-                                          &saif->dma_param.chan_num);
-               if (ret) {
-                       dev_err(&pdev->dev, "failed to get dma channel\n");
-                       return ret;
-               }
-       } else {
-               saif->dma_param.chan_num = dmares->start;
-       }
-
        saif->irq = platform_get_irq(pdev, 0);
        if (saif->irq < 0) {
                ret = saif->irq;
@@ -759,14 +732,6 @@ static int mxs_saif_probe(struct platform_device *pdev)
                return ret;
        }
 
-       saif->dma_param.dma_data.chan_irq = platform_get_irq(pdev, 1);
-       if (saif->dma_param.dma_data.chan_irq < 0) {
-               ret = saif->dma_param.dma_data.chan_irq;
-               dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
-                       ret);
-               return ret;
-       }
-
        platform_set_drvdata(pdev, saif);
 
        ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component,
index 3cb342e5bc902b2c9b39eff62023015a43c7fe70..53eaa4bf0e2726b04c593d9c083895aece2becd6 100644 (file)
@@ -117,7 +117,6 @@ struct mxs_saif {
        unsigned int mclk_in_use;
        void __iomem *base;
        int irq;
-       struct mxs_pcm_dma_params dma_param;
        unsigned int id;
        unsigned int master_id;
        unsigned int cur_rate;
index b1d9b5ebeeeb77d5028a1bd183b4828e7737d78d..1b134d72f120a60b5956032986b964c6f659ab0e 100644 (file)
@@ -90,17 +90,11 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
                .name           = "HiFi Tx",
                .stream_name    = "HiFi Playback",
                .codec_dai_name = "sgtl5000",
-               .codec_name     = "sgtl5000.0-000a",
-               .cpu_dai_name   = "mxs-saif.0",
-               .platform_name  = "mxs-saif.0",
                .ops            = &mxs_sgtl5000_hifi_ops,
        }, {
                .name           = "HiFi Rx",
                .stream_name    = "HiFi Capture",
                .codec_dai_name = "sgtl5000",
-               .codec_name     = "sgtl5000.0-000a",
-               .cpu_dai_name   = "mxs-saif.1",
-               .platform_name  = "mxs-saif.1",
                .ops            = &mxs_sgtl5000_hifi_ops,
        },
 };
@@ -116,7 +110,7 @@ static int mxs_sgtl5000_probe_dt(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct device_node *saif_np[2], *codec_np;
-       int i, ret = 0;
+       int i;
 
        if (!np)
                return 1; /* no device tree */
@@ -142,7 +136,7 @@ static int mxs_sgtl5000_probe_dt(struct platform_device *pdev)
        of_node_put(saif_np[0]);
        of_node_put(saif_np[1]);
 
-       return ret;
+       return 0;
 }
 
 static int mxs_sgtl5000_probe(struct platform_device *pdev)
index fe3285ceaf5bdc4b8903260aed762ab78b02a890..f4c2417a8730bcf0ae99c37fe1bfcc76a685cb51 100644 (file)
@@ -197,13 +197,12 @@ static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97)
 }
 
 /* AC97 controller operations */
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops nuc900_ac97_ops = {
        .read           = nuc900_ac97_read,
        .write          = nuc900_ac97_write,
        .reset          = nuc900_ac97_cold_reset,
        .warm_reset     = nuc900_ac97_warm_reset,
-}
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
+};
 
 static int nuc900_ac97_trigger(struct snd_pcm_substream *substream,
                                int cmd, struct snd_soc_dai *dai)
@@ -326,64 +325,52 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
        if (nuc900_ac97_data)
                return -EBUSY;
 
-       nuc900_audio = kzalloc(sizeof(struct nuc900_audio), GFP_KERNEL);
+       nuc900_audio = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_audio),
+                                   GFP_KERNEL);
        if (!nuc900_audio)
                return -ENOMEM;
 
        spin_lock_init(&nuc900_audio->lock);
 
        nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!nuc900_audio->res) {
-               ret = -ENODEV;
-               goto out0;
-       }
-
-       if (!request_mem_region(nuc900_audio->res->start,
-                       resource_size(nuc900_audio->res), pdev->name)) {
-               ret = -EBUSY;
-               goto out0;
-       }
+       if (!nuc900_audio->res)
+               return ret;
 
-       nuc900_audio->mmio = ioremap(nuc900_audio->res->start,
-                                       resource_size(nuc900_audio->res));
-       if (!nuc900_audio->mmio) {
-               ret = -ENOMEM;
-               goto out1;
-       }
+       nuc900_audio->mmio = devm_ioremap_resource(&pdev->dev,
+                                                  nuc900_audio->res);
+       if (IS_ERR(nuc900_audio->mmio))
+               return PTR_ERR(nuc900_audio->mmio);
 
-       nuc900_audio->clk = clk_get(&pdev->dev, NULL);
+       nuc900_audio->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(nuc900_audio->clk)) {
                ret = PTR_ERR(nuc900_audio->clk);
-               goto out2;
+               goto out;
        }
 
        nuc900_audio->irq_num = platform_get_irq(pdev, 0);
        if (!nuc900_audio->irq_num) {
                ret = -EBUSY;
-               goto out3;
+               goto out;
        }
 
        nuc900_ac97_data = nuc900_audio;
 
+       ret = snd_soc_set_ac97_ops(&nuc900_ac97_ops);
+       if (ret)
+               goto out;
+
        ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component,
                                         &nuc900_ac97_dai, 1);
        if (ret)
-               goto out3;
+               goto out;
 
        /* enbale ac97 multifunction pin */
        mfp_set_groupg(nuc900_audio->dev, NULL);
 
        return 0;
 
-out3:
-       clk_put(nuc900_audio->clk);
-out2:
-       iounmap(nuc900_audio->mmio);
-out1:
-       release_mem_region(nuc900_audio->res->start,
-                                       resource_size(nuc900_audio->res));
-out0:
-       kfree(nuc900_audio);
+out:
+       snd_soc_set_ac97_ops(NULL);
        return ret;
 }
 
@@ -391,13 +378,8 @@ static int nuc900_ac97_drvremove(struct platform_device *pdev)
 {
        snd_soc_unregister_component(&pdev->dev);
 
-       clk_put(nuc900_ac97_data->clk);
-       iounmap(nuc900_ac97_data->mmio);
-       release_mem_region(nuc900_ac97_data->res->start,
-                               resource_size(nuc900_ac97_data->res));
-
-       kfree(nuc900_ac97_data);
        nuc900_ac97_data = NULL;
+       snd_soc_set_ac97_ops(NULL);
 
        return 0;
 }
index 60259f2f3f2cd7f65b1b702d43d88bba4f59b5c1..9f5d55e6b17a53d7e50f2a3c392f565b0fb2e014 100644 (file)
@@ -103,7 +103,7 @@ config SND_OMAP_SOC_OMAP_HDMI
        tristate "SoC Audio support for Texas Instruments OMAP HDMI"
        depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS
        select SND_OMAP_SOC_HDMI
-       select SND_SOC_OMAP_HDMI_CODEC
+       select SND_SOC_HDMI_CODEC
        select OMAP4_DSS_HDMI_AUDIO
        help
          Say Y if you want to add support for SoC HDMI audio on Texas Instruments
index 2b225945359beee9c2e4dd745979f2a40b443f50..a725905b2c68b7c8041389b4d84cffa4bb5c2f49 100644 (file)
@@ -26,7 +26,6 @@ obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
 obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
 obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
 obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP2EVM) += snd-soc-omap2evm.o
 obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
index d4eaa92e518ec22af5c3751be13653dff5b268f9..7e66e9cba5a8770ca2a77abbb1c3be2b3aab5a29 100644 (file)
@@ -35,7 +35,7 @@ static struct snd_soc_dai_link omap_hdmi_dai = {
        .cpu_dai_name = "omap-hdmi-audio-dai",
        .platform_name = "omap-pcm-audio",
        .codec_name = "hdmi-audio-codec",
-       .codec_dai_name = "omap-hdmi-hifi",
+       .codec_dai_name = "hdmi-hifi",
 };
 
 static struct snd_soc_card snd_soc_omap_hdmi = {
index eadbfb6b5000b74f26b627f7ec668397a48d8b45..7483efb6dc674e9bdb90e9ea3bd39a7505a9c34b 100644 (file)
@@ -814,8 +814,6 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
 
        clk_put(mcbsp->fclk);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 249cd230ad8f13e62aeeb30d18d301ff2e776384..611179c3bca48c4ca0e9128f3ab5016766373e44 100644 (file)
@@ -396,7 +396,7 @@ static int __init rx51_soc_init(void)
 {
        int err;
 
-       if (!machine_is_nokia_rx51())
+       if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
                return -ENODEV;
 
        err = gpio_request_one(RX51_TVOUT_SEL_GPIO,
index 4d2e46fae77cfc26548bde3504bf402ecbca66b7..b3580946754702b87a883220d547aeee26b04388 100644 (file)
@@ -130,26 +130,6 @@ config SND_PXA2XX_SOC_PALM27X
          Say Y if you want to add support for SoC audio on
          Palm T|X, T5, E2 or LifeDrive handheld computer.
 
-config SND_SOC_SAARB
-       tristate "SoC Audio support for Marvell Saarb"
-       depends on SND_PXA2XX_SOC && MACH_SAARB
-       select MFD_88PM860X
-       select SND_PXA_SOC_SSP
-       select SND_SOC_88PM860X
-       help
-         Say Y if you want to add support for SoC audio on the
-         Marvell Saarb reference platform.
-
-config SND_SOC_TAVOREVB3
-       tristate "SoC Audio support for Marvell Tavor EVB3"
-       depends on SND_PXA2XX_SOC && MACH_TAVOREVB3
-       select MFD_88PM860X
-       select SND_PXA_SOC_SSP
-       select SND_SOC_88PM860X
-       help
-         Say Y if you want to add support for SoC audio on the
-         Marvell Saarb reference platform.
-
 config SND_PXA910_SOC
        tristate "SoC Audio for Marvell PXA910 chip"
        depends on ARCH_MMP && SND
index d8a265d2d5d7ce07e005f2ab7ee786d4425db842..2cff67b61dc368b3d5559ecd6d0973c2be63a6c3 100644 (file)
@@ -23,8 +23,6 @@ snd-soc-e800-objs := e800_wm9712.o
 snd-soc-spitz-objs := spitz.o
 snd-soc-em-x270-objs := em-x270.o
 snd-soc-palm27x-objs := palm27x.o
-snd-soc-saarb-objs := saarb.o
-snd-soc-tavorevb3-objs := tavorevb3.o
 snd-soc-zylonite-objs := zylonite.o
 snd-soc-hx4700-objs := hx4700.o
 snd-soc-magician-objs := magician.o
@@ -48,8 +46,6 @@ obj-$(CONFIG_SND_PXA2XX_SOC_HX4700) += snd-soc-hx4700.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
-obj-$(CONFIG_SND_SOC_SAARB) += snd-soc-saarb.o
-obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
 obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
 obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
index 3499300152648599d0ef8f38abcd63bbfd322c75..5d57e071cdf522e8f8b11670c32a47595b5d6e92 100644 (file)
@@ -147,7 +147,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
                vma->vm_end - vma->vm_start, vma->vm_page_prot);
 }
 
-struct snd_pcm_ops mmp_pcm_ops = {
+static struct snd_pcm_ops mmp_pcm_ops = {
        .open           = mmp_pcm_open,
        .close          = snd_dmaengine_pcm_close_release_chan,
        .ioctl          = snd_pcm_lib_ioctl,
@@ -208,7 +208,7 @@ static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream,
        return 0;
 }
 
-int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
+static int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm_substream *substream;
        struct snd_pcm *pcm = rtd->pcm;
@@ -229,7 +229,7 @@ err:
        return ret;
 }
 
-struct snd_soc_platform_driver mmp_soc_platform = {
+static struct snd_soc_platform_driver mmp_soc_platform = {
        .ops            = &mmp_pcm_ops,
        .pcm_new        = mmp_pcm_new,
        .pcm_free       = mmp_pcm_free_dma_buffers,
index a647799801773d0baedcbffc5e9d3ddec4208b62..62142ce367c7e68fcffbe7b34b92b7364d7a0af3 100644 (file)
@@ -388,7 +388,7 @@ static struct snd_soc_dai_ops mmp_sspa_dai_ops = {
        .set_fmt        = mmp_sspa_set_dai_fmt,
 };
 
-struct snd_soc_dai_driver mmp_sspa_dai = {
+static struct snd_soc_dai_driver mmp_sspa_dai = {
        .probe = mmp_sspa_probe,
        .playback = {
                .channels_min = 1,
index 57ea8e6c54885372f7808376968b7f56783ef78a..1475515712e65616b345f3d7e56ddedf954f6b4a 100644 (file)
@@ -41,13 +41,12 @@ static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
        pxa2xx_ac97_finish_reset(ac97);
 }
 
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
        .read   = pxa2xx_ac97_read,
        .write  = pxa2xx_ac97_write,
        .warm_reset     = pxa2xx_ac97_warm_reset,
        .reset  = pxa2xx_ac97_cold_reset,
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
        .name                   = "AC97 PCM Stereo out",
@@ -239,11 +238,17 @@ static const struct snd_soc_component_driver pxa_ac97_component = {
 
 static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 {
+       int ret;
+
        if (pdev->id != -1) {
                dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n");
                return -ENXIO;
        }
 
+       ret = snd_soc_set_ac97_ops(&pxa2xx_ac97_ops);
+       if (ret != 0)
+               return ret;
+
        /* Punt most of the init to the SoC probe; we may need the machine
         * driver to do interesting things with the clocking to get us up
         * and running.
@@ -255,6 +260,7 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 static int pxa2xx_ac97_dev_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_component(&pdev->dev);
+       snd_soc_set_ac97_ops(NULL);
        return 0;
 }
 
index eda891e6f31bab8ff1395a193bbc3949d2fecc8c..a49c21ba3842c8e93acd7d2865ff89c91ae2a5ec 100644 (file)
@@ -14,7 +14,4 @@
 #define PXA2XX_DAI_AC97_AUX            1
 #define PXA2XX_DAI_AC97_MIC            2
 
-/* platform data */
-extern struct snd_ac97_bus_ops pxa2xx_ac97_ops;
-
 #endif
diff --git a/sound/soc/pxa/saarb.c b/sound/soc/pxa/saarb.c
deleted file mode 100644 (file)
index c34146b..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * saarb.c -- SoC audio for saarb
- *
- * Copyright (C) 2010 Marvell International Ltd.
- *     Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-
-#include "../codecs/88pm860x-codec.h"
-#include "pxa-ssp.h"
-
-static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd);
-
-static struct platform_device *saarb_snd_device;
-
-static struct snd_soc_jack hs_jack, mic_jack;
-
-static struct snd_soc_jack_pin hs_jack_pins[] = {
-       { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
-};
-
-static struct snd_soc_jack_pin mic_jack_pins[] = {
-       { .pin = "Headset Mic 2",       .mask = SND_JACK_MICROPHONE, },
-};
-
-/* saarb machine dapm widgets */
-static const struct snd_soc_dapm_widget saarb_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Stereophone", NULL),
-       SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
-       SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
-       SND_SOC_DAPM_SPK("Ext Speaker", NULL),
-       SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
-};
-
-/* saarb machine audio map */
-static const struct snd_soc_dapm_route saarb_audio_map[] = {
-       {"Headset Stereophone", NULL, "HS1"},
-       {"Headset Stereophone", NULL, "HS2"},
-
-       {"Ext Speaker", NULL, "LSP"},
-       {"Ext Speaker", NULL, "LSN"},
-
-       {"Lineout Out 1", NULL, "LINEOUT1"},
-       {"Lineout Out 2", NULL, "LINEOUT2"},
-
-       {"MIC1P", NULL, "Mic1 Bias"},
-       {"MIC1N", NULL, "Mic1 Bias"},
-       {"Mic1 Bias", NULL, "Ext Mic 1"},
-
-       {"MIC2P", NULL, "Mic1 Bias"},
-       {"MIC2N", NULL, "Mic1 Bias"},
-       {"Mic1 Bias", NULL, "Headset Mic 2"},
-
-       {"MIC3P", NULL, "Mic3 Bias"},
-       {"MIC3N", NULL, "Mic3 Bias"},
-       {"Mic3 Bias", NULL, "Ext Mic 3"},
-};
-
-static int saarb_i2s_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int width = snd_pcm_format_physical_width(params_format(params));
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
-                                    PM860X_CLK_DIR_OUT);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
-
-       return ret;
-}
-
-static struct snd_soc_ops saarb_i2s_ops = {
-       .hw_params      = saarb_i2s_hw_params,
-};
-
-static struct snd_soc_dai_link saarb_dai[] = {
-       {
-               .name           = "88PM860x I2S",
-               .stream_name    = "I2S Audio",
-               .cpu_dai_name   = "pxa-ssp-dai.1",
-               .codec_dai_name = "88pm860x-i2s",
-               .platform_name  = "pxa-pcm-audio",
-               .codec_name     = "88pm860x-codec",
-               .init           = saarb_pm860x_init,
-               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM,
-               .ops            = &saarb_i2s_ops,
-       },
-};
-
-static struct snd_soc_card snd_soc_card_saarb = {
-       .name = "Saarb",
-       .owner = THIS_MODULE,
-       .dai_link = saarb_dai,
-       .num_links = ARRAY_SIZE(saarb_dai),
-
-       .dapm_widgets = saarb_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(saarb_dapm_widgets),
-       .dapm_routes = saarb_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(saarb_audio_map),
-};
-
-static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* connected pins */
-       snd_soc_dapm_enable_pin(dapm, "Ext Speaker");
-       snd_soc_dapm_enable_pin(dapm, "Ext Mic 1");
-       snd_soc_dapm_enable_pin(dapm, "Ext Mic 3");
-       snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
-       snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
-
-       /* Headset jack detection */
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
-                       | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
-                       &hs_jack);
-       snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                             hs_jack_pins);
-       snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
-                        &mic_jack);
-       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
-                             mic_jack_pins);
-
-       /* headphone, microphone detection & headset short detection */
-       pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
-                             SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
-       pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
-       return 0;
-}
-
-static int __init saarb_init(void)
-{
-       int ret;
-
-       if (!machine_is_saarb())
-               return -ENODEV;
-       saarb_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!saarb_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(saarb_snd_device, &snd_soc_card_saarb);
-
-       ret = platform_device_add(saarb_snd_device);
-       if (ret)
-               platform_device_put(saarb_snd_device);
-
-       return ret;
-}
-
-static void __exit saarb_exit(void)
-{
-       platform_device_unregister(saarb_snd_device);
-}
-
-module_init(saarb_init);
-module_exit(saarb_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("ALSA SoC 88PM860x Saarb");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/tavorevb3.c b/sound/soc/pxa/tavorevb3.c
deleted file mode 100644 (file)
index 8b5ab8f..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * tavorevb3.c -- SoC audio for Tavor EVB3
- *
- * Copyright (C) 2010 Marvell International Ltd.
- *     Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/clk.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-
-#include "../codecs/88pm860x-codec.h"
-#include "pxa-ssp.h"
-
-static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd);
-
-static struct platform_device *evb3_snd_device;
-
-static struct snd_soc_jack hs_jack, mic_jack;
-
-static struct snd_soc_jack_pin hs_jack_pins[] = {
-       { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
-};
-
-static struct snd_soc_jack_pin mic_jack_pins[] = {
-       { .pin = "Headset Mic 2",       .mask = SND_JACK_MICROPHONE, },
-};
-
-/* tavorevb3 machine dapm widgets */
-static const struct snd_soc_dapm_widget evb3_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
-       SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
-       SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
-       SND_SOC_DAPM_SPK("Ext Speaker", NULL),
-       SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic 2", NULL),
-       SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
-};
-
-/* tavorevb3 machine audio map */
-static const struct snd_soc_dapm_route evb3_audio_map[] = {
-       {"Headset Stereophone", NULL, "HS1"},
-       {"Headset Stereophone", NULL, "HS2"},
-
-       {"Ext Speaker", NULL, "LSP"},
-       {"Ext Speaker", NULL, "LSN"},
-
-       {"Lineout Out 1", NULL, "LINEOUT1"},
-       {"Lineout Out 2", NULL, "LINEOUT2"},
-
-       {"MIC1P", NULL, "Mic1 Bias"},
-       {"MIC1N", NULL, "Mic1 Bias"},
-       {"Mic1 Bias", NULL, "Ext Mic 1"},
-
-       {"MIC2P", NULL, "Mic1 Bias"},
-       {"MIC2N", NULL, "Mic1 Bias"},
-       {"Mic1 Bias", NULL, "Headset Mic 2"},
-
-       {"MIC3P", NULL, "Mic3 Bias"},
-       {"MIC3N", NULL, "Mic3 Bias"},
-       {"Mic3 Bias", NULL, "Ext Mic 3"},
-};
-
-static int evb3_i2s_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int width = snd_pcm_format_physical_width(params_format(params));
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
-                                    PM860X_CLK_DIR_OUT);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
-       return ret;
-}
-
-static struct snd_soc_ops evb3_i2s_ops = {
-       .hw_params      = evb3_i2s_hw_params,
-};
-
-static struct snd_soc_dai_link evb3_dai[] = {
-       {
-               .name           = "88PM860x I2S",
-               .stream_name    = "I2S Audio",
-               .cpu_dai_name   = "pxa-ssp-dai.1",
-               .codec_dai_name = "88pm860x-i2s",
-               .platform_name  = "pxa-pcm-audio",
-               .codec_name     = "88pm860x-codec",
-               .init           = evb3_pm860x_init,
-               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM,
-               .ops            = &evb3_i2s_ops,
-       },
-};
-
-static struct snd_soc_card snd_soc_card_evb3 = {
-       .name = "Tavor EVB3",
-       .owner = THIS_MODULE,
-       .dai_link = evb3_dai,
-       .num_links = ARRAY_SIZE(evb3_dai),
-
-       .dapm_widgets = evb3_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(evb3_dapm_widgets),
-       .dapm_routes = evb3_audio_map,
-       .num_dapm_routes = ARRAY_SIZE(evb3_audio_map),
-};
-
-static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* connected pins */
-       snd_soc_dapm_enable_pin(dapm, "Ext Speaker");
-       snd_soc_dapm_enable_pin(dapm, "Ext Mic 1");
-       snd_soc_dapm_enable_pin(dapm, "Ext Mic 3");
-       snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
-       snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
-
-       /* Headset jack detection */
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
-                       | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
-                       &hs_jack);
-       snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
-                             hs_jack_pins);
-       snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
-                        &mic_jack);
-       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
-                             mic_jack_pins);
-
-       /* headphone, microphone detection & headset short detection */
-       pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
-                             SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
-       pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
-       return 0;
-}
-
-static int __init tavorevb3_init(void)
-{
-       int ret;
-
-       if (!machine_is_tavorevb3())
-               return -ENODEV;
-       evb3_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!evb3_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(evb3_snd_device, &snd_soc_card_evb3);
-
-       ret = platform_device_add(evb3_snd_device);
-       if (ret)
-               platform_device_put(evb3_snd_device);
-
-       return ret;
-}
-
-static void __exit tavorevb3_exit(void)
-{
-       platform_device_unregister(evb3_snd_device);
-}
-
-module_init(tavorevb3_init);
-module_exit(tavorevb3_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("ALSA SoC 88PM860x Tavor EVB3");
-MODULE_LICENSE("GPL");
index ceb656695b0fbc2f438779ac8331052063d83643..db8aadf8932dbc9e319975d474bd17a47884a2c7 100644 (file)
@@ -256,7 +256,6 @@ static struct snd_soc_card zylonite = {
        .resume_pre = &zylonite_resume_pre,
        .dai_link = zylonite_dai,
        .num_links = ARRAY_SIZE(zylonite_dai),
-       .owner = THIS_MODULE,
 };
 
 static struct platform_device *zylonite_snd_ac97_device;
index 475fb0d8b3c6bc4faa1c062e39ef2cbd886176f1..9855dfc3e3ec86f726526540d3bf0446cca22cd5 100644 (file)
@@ -39,7 +39,7 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753
        depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
        select SND_S3C24XX_I2S
        select SND_SOC_WM8753
-       select SND_SOC_DFBMCS320
+       select SND_SOC_BT_SCO
        help
          Say Y here to enable audio support for the Openmoko Neo1973
          Smartphones.
index cb88ead98917b354c459673ae879a80a37b40ad5..2dd623fa3882b8fe17ceab2c6a86f45f54059f9d 100644 (file)
@@ -214,13 +214,12 @@ static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops s3c_ac97_ops = {
        .read       = s3c_ac97_read,
        .write      = s3c_ac97_write,
        .warm_reset = s3c_ac97_warm_reset,
        .reset      = s3c_ac97_cold_reset,
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params,
@@ -417,11 +416,9 @@ static int s3c_ac97_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       if (!request_mem_region(mem_res->start,
-                               resource_size(mem_res), "ac97")) {
-               dev_err(&pdev->dev, "Unable to request register region\n");
-               return -EBUSY;
-       }
+       s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res);
+       if (IS_ERR(s3c_ac97.regs))
+               return PTR_ERR(s3c_ac97.regs);
 
        s3c_ac97_pcm_out.channel = dmatx_res->start;
        s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
@@ -433,14 +430,7 @@ static int s3c_ac97_probe(struct platform_device *pdev)
        init_completion(&s3c_ac97.done);
        mutex_init(&s3c_ac97.lock);
 
-       s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res));
-       if (s3c_ac97.regs == NULL) {
-               dev_err(&pdev->dev, "Unable to ioremap register region\n");
-               ret = -ENXIO;
-               goto err1;
-       }
-
-       s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
+       s3c_ac97.ac97_clk = devm_clk_get(&pdev->dev, "ac97");
        if (IS_ERR(s3c_ac97.ac97_clk)) {
                dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n");
                ret = -ENODEV;
@@ -461,6 +451,12 @@ static int s3c_ac97_probe(struct platform_device *pdev)
                goto err4;
        }
 
+       ret = snd_soc_set_ac97_ops(&s3c_ac97_ops);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
+               goto err4;
+       }
+
        ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
                                         s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
        if (ret)
@@ -480,18 +476,14 @@ err5:
 err4:
 err3:
        clk_disable_unprepare(s3c_ac97.ac97_clk);
-       clk_put(s3c_ac97.ac97_clk);
 err2:
-       iounmap(s3c_ac97.regs);
-err1:
-       release_mem_region(mem_res->start, resource_size(mem_res));
-
+       snd_soc_set_ac97_ops(NULL);
        return ret;
 }
 
 static int s3c_ac97_remove(struct platform_device *pdev)
 {
-       struct resource *mem_res, *irq_res;
+       struct resource *irq_res;
 
        asoc_dma_platform_unregister(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
@@ -501,13 +493,7 @@ static int s3c_ac97_remove(struct platform_device *pdev)
                free_irq(irq_res->start, NULL);
 
        clk_disable_unprepare(s3c_ac97.ac97_clk);
-       clk_put(s3c_ac97.ac97_clk);
-
-       iounmap(s3c_ac97.regs);
-
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (mem_res)
-               release_mem_region(mem_res->start, resource_size(mem_res));
+       snd_soc_set_ac97_ops(NULL);
 
        return 0;
 }
index ceed466af9ff8f25b0007b8399cec68c87a06daa..29e246803626baf1ba32f066226e1902cb7e1a86 100644 (file)
@@ -350,8 +350,16 @@ static struct snd_soc_codec_conf bells_codec_conf[] = {
        },
 };
 
+static struct snd_soc_dapm_widget bells_widgets[] = {
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
 static struct snd_soc_dapm_route bells_routes[] = {
        { "Sub CLK_SYS", NULL, "OPCLK" },
+
+       { "DMIC", NULL, "MICBIAS2" },
+       { "IN2L", NULL, "DMIC" },
+       { "IN2R", NULL, "DMIC" },
 };
 
 static struct snd_soc_card bells_cards[] = {
@@ -365,6 +373,8 @@ static struct snd_soc_card bells_cards[] = {
 
                .late_probe = bells_late_probe,
 
+               .dapm_widgets = bells_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(bells_widgets),
                .dapm_routes = bells_routes,
                .num_dapm_routes = ARRAY_SIZE(bells_routes),
 
@@ -383,6 +393,8 @@ static struct snd_soc_card bells_cards[] = {
 
                .late_probe = bells_late_probe,
 
+               .dapm_widgets = bells_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(bells_widgets),
                .dapm_routes = bells_routes,
                .num_dapm_routes = ARRAY_SIZE(bells_routes),
 
@@ -401,6 +413,8 @@ static struct snd_soc_card bells_cards[] = {
 
                .late_probe = bells_late_probe,
 
+               .dapm_widgets = bells_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(bells_widgets),
                .dapm_routes = bells_routes,
                .num_dapm_routes = ARRAY_SIZE(bells_routes),
 
index e591c386917abb58b3f612971e79e65bb96a3abd..807db417d234a5d3571f6ff6be86893acad514d9 100644 (file)
@@ -373,7 +373,7 @@ static struct snd_soc_dai_link neo1973_dai[] = {
 { /* Voice via BT */
        .name = "Bluetooth",
        .stream_name = "Voice",
-       .cpu_dai_name = "dfbmcs320-pcm",
+       .cpu_dai_name = "bt-sco-pcm",
        .codec_dai_name = "wm8753-voice",
        .codec_name = "wm8753.0-001a",
        .ops = &neo1973_voice_ops,
index e43bd4294f99ad26011744f0192a83aaad89f9c3..23a9204b106d66a7e6a64eb8f7dc7f3b5bb2e186 100644 (file)
@@ -176,7 +176,6 @@ static int snd_smdk_probe(struct platform_device *pdev)
 static int snd_smdk_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_card(&smdk_pcm);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index 3688a32000a2bc752122958abdd4818cfb7d7046..0c84ca0996126b86c28dc9412dbfd08494501c02 100644 (file)
@@ -146,7 +146,6 @@ static int snd_smdk_probe(struct platform_device *pdev)
 static int snd_smdk_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_card(&smdk_pcm);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index f830c41f97dd1a5dd95df65f0f0cf4f3eef69994..30390260bb6782aa4c1d1e744b6e80f1d1aa263b 100644 (file)
@@ -276,7 +276,7 @@ struct fsi_stream_handler {
        int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev);
        int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io);
        int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io);
-       void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
+       int (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io,
                           int enable);
 };
 #define fsi_stream_handler_call(io, func, args...)     \
@@ -1188,7 +1188,7 @@ static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io)
                                  samples);
 }
 
-static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
+static int fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
                               int enable)
 {
        struct fsi_master *master = fsi_get_master(fsi);
@@ -1201,6 +1201,8 @@ static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
 
        if (fsi_is_clk_master(fsi))
                fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
+
+       return 0;
 }
 
 static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io)
@@ -1409,7 +1411,7 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
        return 0;
 }
 
-static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
+static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
                                 int start)
 {
        struct fsi_master *master = fsi_get_master(fsi);
@@ -1422,6 +1424,8 @@ static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
 
        if (fsi_is_clk_master(fsi))
                fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
+
+       return 0;
 }
 
 static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
index af19f77b7bf0fa84c101170b5bee45cad6920f26..0af2e4dfd13949a502e670846a84e098bff1719a 100644 (file)
@@ -227,13 +227,12 @@ static void hac_ac97_coldrst(struct snd_ac97 *ac97)
        hac_ac97_warmrst(ac97);
 }
 
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops hac_ac97_ops = {
        .read   = hac_ac97_read,
        .write  = hac_ac97_write,
        .reset  = hac_ac97_coldrst,
        .warm_reset = hac_ac97_warmrst,
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static int hac_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *params,
@@ -316,6 +315,10 @@ static const struct snd_soc_component_driver sh4_hac_component = {
 
 static int hac_soc_platform_probe(struct platform_device *pdev)
 {
+       ret = snd_soc_set_ac97_ops(&hac_ac97_ops);
+       if (ret != 0)
+               return ret;
+
        return snd_soc_register_component(&pdev->dev, &sh4_hac_component,
                                          sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
 }
@@ -323,6 +326,7 @@ static int hac_soc_platform_probe(struct platform_device *pdev)
 static int hac_soc_platform_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_component(&pdev->dev);
+       snd_soc_set_ac97_ops(NULL);
        return 0;
 }
 
index d56bbea6e75e60158405f45b1cf280f4d0fb9ac1..0ec070cf7231ebcc39a057061af8995d7f7574ff 100644 (file)
@@ -272,8 +272,8 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
        codec->debugfs_codec_root = debugfs_create_dir(codec->name,
                                                       debugfs_card_root);
        if (!codec->debugfs_codec_root) {
-               dev_warn(codec->dev, "ASoC: Failed to create codec debugfs"
-                       " directory\n");
+               dev_warn(codec->dev,
+                       "ASoC: Failed to create codec debugfs directory\n");
                return;
        }
 
@@ -286,8 +286,8 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
                                                 codec->debugfs_codec_root,
                                                 codec, &codec_reg_fops);
        if (!codec->debugfs_reg)
-               dev_warn(codec->dev, "ASoC: Failed to create codec register"
-                       " debugfs file\n");
+               dev_warn(codec->dev,
+                       "ASoC: Failed to create codec register debugfs file\n");
 
        snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root);
 }
@@ -631,8 +631,7 @@ int snd_soc_suspend(struct device *dev)
                                 */
                                if (codec->dapm.idle_bias_off) {
                                        dev_dbg(codec->dev,
-                                               "ASoC: idle_bias_off CODEC on"
-                                               " over suspend\n");
+                                               "ASoC: idle_bias_off CODEC on over suspend\n");
                                        break;
                                }
                        case SND_SOC_BIAS_OFF:
@@ -643,8 +642,8 @@ int snd_soc_suspend(struct device *dev)
                                        regcache_mark_dirty(codec->control_data);
                                break;
                        default:
-                               dev_dbg(codec->dev, "ASoC: CODEC is on"
-                                       " over suspend\n");
+                               dev_dbg(codec->dev,
+                                       "ASoC: CODEC is on over suspend\n");
                                break;
                        }
                }
@@ -713,8 +712,8 @@ static void soc_resume_deferred(struct work_struct *work)
                                codec->suspended = 0;
                                break;
                        default:
-                               dev_dbg(codec->dev, "ASoC: CODEC was on over"
-                                       " suspend\n");
+                               dev_dbg(codec->dev,
+                                       "ASoC: CODEC was on over suspend\n");
                                break;
                        }
                }
@@ -1110,8 +1109,8 @@ static int soc_probe_codec(struct snd_soc_card *card,
                }
                WARN(codec->dapm.idle_bias_off &&
                        codec->dapm.bias_level != SND_SOC_BIAS_OFF,
-                       "codec %s can not start from non-off bias"
-                       " with idle_bias_off==1\n", codec->name);
+                       "codec %s can not start from non-off bias with idle_bias_off==1\n",
+                       codec->name);
        }
 
        /* If the driver didn't set I/O up try regmap */
@@ -1582,8 +1581,9 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
                codec->compress_type = compress_type;
        ret = snd_soc_cache_init(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "ASoC: Failed to set cache compression"
-                       " type: %d\n", ret);
+               dev_err(codec->dev,
+                       "ASoC: Failed to set cache compression type: %d\n",
+                       ret);
                return ret;
        }
        codec->cache_init = 1;
@@ -1639,8 +1639,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
                        card->owner, 0, &card->snd_card);
        if (ret < 0) {
-               dev_err(card->dev, "ASoC: can't create sound card for"
-                       " card %s: %d\n", card->name, ret);
+               dev_err(card->dev,
+                       "ASoC: can't create sound card for card %s: %d\n",
+                       card->name, ret);
                goto base_error;
        }
        card->snd_card->dev = card->dev;
@@ -1815,8 +1816,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
        for (i = 0; i < card->num_rtd; i++) {
                ret = soc_register_ac97_dai_link(&card->rtd[i]);
                if (ret < 0) {
-                       dev_err(card->dev, "ASoC: failed to register AC97:"
-                               " %d\n", ret);
+                       dev_err(card->dev,
+                               "ASoC: failed to register AC97: %d\n", ret);
                        while (--i >= 0)
                                soc_unregister_ac97_dai_link(card->rtd[i].codec);
                        goto probe_aux_dev_err;
@@ -2079,6 +2080,23 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
 
+struct snd_ac97_bus_ops *soc_ac97_ops;
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops)
+{
+       if (ops == soc_ac97_ops)
+               return 0;
+
+       if (soc_ac97_ops && ops)
+               return -EBUSY;
+
+       soc_ac97_ops = ops;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops);
+
 /**
  * snd_soc_free_ac97_codec - free AC97 codec device
  * @codec: audio codec
@@ -2218,29 +2236,6 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
 }
 EXPORT_SYMBOL_GPL(snd_soc_test_bits);
 
-/**
- * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
- * @substream: the pcm substream
- * @hw: the hardware parameters
- *
- * Sets the substream runtime hardware parameters.
- */
-int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
-       const struct snd_pcm_hardware *hw)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       runtime->hw.info = hw->info;
-       runtime->hw.formats = hw->formats;
-       runtime->hw.period_bytes_min = hw->period_bytes_min;
-       runtime->hw.period_bytes_max = hw->period_bytes_max;
-       runtime->hw.periods_min = hw->periods_min;
-       runtime->hw.periods_max = hw->periods_max;
-       runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
-       runtime->hw.fifo_size = hw->fifo_size;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
-
 /**
  * snd_soc_cnew - create new control
  * @_template: control template
@@ -2259,7 +2254,6 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
        struct snd_kcontrol_new template;
        struct snd_kcontrol *kcontrol;
        char *name = NULL;
-       int name_len;
 
        memcpy(&template, _template, sizeof(template));
        template.index = 0;
@@ -2268,13 +2262,10 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
                long_name = template.name;
 
        if (prefix) {
-               name_len = strlen(long_name) + strlen(prefix) + 2;
-               name = kmalloc(name_len, GFP_KERNEL);
+               name = kasprintf(GFP_KERNEL, "%s %s", prefix, long_name);
                if (!name)
                        return NULL;
 
-               snprintf(name, name_len, "%s %s", prefix, long_name);
-
                template.name = name;
        } else {
                template.name = long_name;
@@ -3586,14 +3577,16 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 * not both or neither.
                 */
                if (!!link->codec_name == !!link->codec_of_node) {
-                       dev_err(card->dev, "ASoC: Neither/both codec"
-                               " name/of_node are set for %s\n", link->name);
+                       dev_err(card->dev,
+                               "ASoC: Neither/both codec name/of_node are set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
                /* Codec DAI name must be specified */
                if (!link->codec_dai_name) {
-                       dev_err(card->dev, "ASoC: codec_dai_name not"
-                               " set for %s\n", link->name);
+                       dev_err(card->dev,
+                               "ASoC: codec_dai_name not set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
 
@@ -3602,8 +3595,9 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 * can be left unspecified, and a dummy platform will be used.
                 */
                if (link->platform_name && link->platform_of_node) {
-                       dev_err(card->dev, "ASoC: Both platform name/of_node"
-                               " are set for %s\n", link->name);
+                       dev_err(card->dev,
+                               "ASoC: Both platform name/of_node are set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
 
@@ -3613,8 +3607,9 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 * name alone..
                 */
                if (link->cpu_name && link->cpu_of_node) {
-                       dev_err(card->dev, "ASoC: Neither/both "
-                               "cpu name/of_node are set for %s\n",link->name);
+                       dev_err(card->dev,
+                               "ASoC: Neither/both cpu name/of_node are set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
                /*
@@ -3623,8 +3618,9 @@ int snd_soc_register_card(struct snd_soc_card *card)
                 */
                if (!link->cpu_dai_name &&
                    !(link->cpu_name || link->cpu_of_node)) {
-                       dev_err(card->dev, "ASoC: Neither cpu_dai_name nor "
-                               "cpu_name/of_node are set for %s\n", link->name);
+                       dev_err(card->dev,
+                               "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n",
+                               link->name);
                        return -EINVAL;
                }
        }
@@ -3728,8 +3724,9 @@ static inline char *fmt_multiple_name(struct device *dev,
                struct snd_soc_dai_driver *dai_drv)
 {
        if (dai_drv->name == NULL) {
-               dev_err(dev, "ASoC: error - multiple DAI %s registered with"
-                               " no name\n", dev_name(dev));
+               dev_err(dev,
+                       "ASoC: error - multiple DAI %s registered with no name\n",
+                       dev_name(dev));
                return NULL;
        }
 
@@ -3859,8 +3856,9 @@ static int snd_soc_register_dais(struct device *dev,
 
                list_for_each_entry(codec, &codec_list, list) {
                        if (codec->dev == dev) {
-                               dev_dbg(dev, "ASoC: Mapped DAI %s to "
-                                       "CODEC %s\n", dai->name, codec->name);
+                               dev_dbg(dev,
+                                       "ASoC: Mapped DAI %s to CODEC %s\n",
+                                       dai->name, codec->name);
                                dai->codec = codec;
                                break;
                        }
@@ -4296,8 +4294,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
 
        num_routes = of_property_count_strings(np, propname);
        if (num_routes < 0 || num_routes & 1) {
-               dev_err(card->dev, "ASoC: Property '%s' does not exist or its"
-                       " length is not even\n", propname);
+               dev_err(card->dev,
+                       "ASoC: Property '%s' does not exist or its length is not even\n",
+                       propname);
                return -EINVAL;
        }
        num_routes /= 2;
index c7051c457b75c0f09acdd9cd1e39ef62eda22f0f..b94190820e8cfa1b6c24e925f176196cc5efff98 100644 (file)
@@ -64,6 +64,7 @@ static int dapm_up_seq[] = {
        [snd_soc_dapm_virt_mux] = 5,
        [snd_soc_dapm_value_mux] = 5,
        [snd_soc_dapm_dac] = 6,
+       [snd_soc_dapm_switch] = 7,
        [snd_soc_dapm_mixer] = 7,
        [snd_soc_dapm_mixer_named_ctl] = 7,
        [snd_soc_dapm_pga] = 8,
@@ -83,6 +84,7 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_line] = 2,
        [snd_soc_dapm_out_drv] = 2,
        [snd_soc_dapm_pga] = 4,
+       [snd_soc_dapm_switch] = 5,
        [snd_soc_dapm_mixer_named_ctl] = 5,
        [snd_soc_dapm_mixer] = 5,
        [snd_soc_dapm_dac] = 6,
@@ -365,11 +367,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                val = soc_widget_read(w, e->reg);
                item = (val >> e->shift_l) & e->mask;
 
-               p->connect = 0;
-               for (i = 0; i < e->max; i++) {
-                       if (!(strcmp(p->name, e->texts[i])) && item == i)
-                               p->connect = 1;
-               }
+               if (item < e->max && !strcmp(p->name, e->texts[item]))
+                       p->connect = 1;
+               else
+                       p->connect = 0;
        }
        break;
        case snd_soc_dapm_virt_mux: {
@@ -399,11 +400,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                                break;
                }
 
-               p->connect = 0;
-               for (i = 0; i < e->max; i++) {
-                       if (!(strcmp(p->name, e->texts[i])) && item == i)
-                               p->connect = 1;
-               }
+               if (item < e->max && !strcmp(p->name, e->texts[item]))
+                       p->connect = 1;
+               else
+                       p->connect = 0;
        }
        break;
        /* does not affect routing - always connected */
@@ -507,6 +507,11 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
        return 0;
 }
 
+static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
+{
+       kfree(kctl->private_data);
+}
+
 /*
  * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
  * create it. Either way, add the widget into the control's widget list
@@ -524,7 +529,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
        int wlistentries;
        size_t wlistsize;
        bool wname_in_long_name, kcname_in_long_name;
-       size_t name_len;
        char *long_name;
        const char *name;
        int ret;
@@ -589,25 +593,19 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                }
 
                if (wname_in_long_name && kcname_in_long_name) {
-                       name_len = strlen(w->name) - prefix_len + 1 +
-                                  strlen(w->kcontrol_news[kci].name) + 1;
-
-                       long_name = kmalloc(name_len, GFP_KERNEL);
-                       if (long_name == NULL) {
-                               kfree(wlist);
-                               return -ENOMEM;
-                       }
-
                        /*
                         * The control will get a prefix from the control
                         * creation process but we're also using the same
                         * prefix for widgets so cut the prefix off the
                         * front of the widget name.
                         */
-                       snprintf(long_name, name_len, "%s %s",
+                       long_name = kasprintf(GFP_KERNEL, "%s %s",
                                 w->name + prefix_len,
                                 w->kcontrol_news[kci].name);
-                       long_name[name_len - 1] = '\0';
+                       if (long_name == NULL) {
+                               kfree(wlist);
+                               return -ENOMEM;
+                       }
 
                        name = long_name;
                } else if (wname_in_long_name) {
@@ -620,17 +618,16 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
 
                kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
                                        prefix);
+               kcontrol->private_free = dapm_kcontrol_free;
+               kfree(long_name);
                ret = snd_ctl_add(card, kcontrol);
                if (ret < 0) {
                        dev_err(dapm->dev,
                                "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
                                w->name, name, ret);
                        kfree(wlist);
-                       kfree(long_name);
                        return ret;
                }
-
-               path->long_name = long_name;
        }
 
        kcontrol->private_data = wlist;
@@ -1270,6 +1267,14 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
                ev_name = "POST_PMD";
                power = 0;
                break;
+       case SND_SOC_DAPM_WILL_PMU:
+               ev_name = "WILL_PMU";
+               power = 1;
+               break;
+       case SND_SOC_DAPM_WILL_PMD:
+               ev_name = "WILL_PMD";
+               power = 0;
+               break;
        default:
                BUG();
                return;
@@ -1730,6 +1735,14 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                                        &async_domain);
        async_synchronize_full_domain(&async_domain);
 
+       list_for_each_entry(w, &down_list, power_list) {
+               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD);
+       }
+
+       list_for_each_entry(w, &up_list, power_list) {
+               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU);
+       }
+
        /* Power down widgets first; try to avoid amplifying pops. */
        dapm_seq_run(dapm, &down_list, event, false);
 
@@ -2094,6 +2107,14 @@ static void snd_soc_dapm_sys_remove(struct device *dev)
        device_remove_file(dev, &dev_attr_dapm_widget);
 }
 
+static void dapm_free_path(struct snd_soc_dapm_path *path)
+{
+       list_del(&path->list_sink);
+       list_del(&path->list_source);
+       list_del(&path->list);
+       kfree(path);
+}
+
 /* free all dapm widgets and resources */
 static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
 {
@@ -2109,20 +2130,12 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
                 * While removing the path, remove reference to it from both
                 * source and sink widgets so that path is removed only once.
                 */
-               list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
-                       list_del(&p->list_sink);
-                       list_del(&p->list_source);
-                       list_del(&p->list);
-                       kfree(p->long_name);
-                       kfree(p);
-               }
-               list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
-                       list_del(&p->list_sink);
-                       list_del(&p->list_source);
-                       list_del(&p->list);
-                       kfree(p->long_name);
-                       kfree(p);
-               }
+               list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
+                       dapm_free_path(p);
+
+               list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
+                       dapm_free_path(p);
+
                kfree(w->kcontrols);
                kfree(w->name);
                kfree(w);
@@ -2398,10 +2411,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
                dapm_mark_dirty(path->source, "Route removed");
                dapm_mark_dirty(path->sink, "Route removed");
 
-               list_del(&path->list);
-               list_del(&path->list_sink);
-               list_del(&path->list_source);
-               kfree(path);
+               dapm_free_path(path);
        } else {
                dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
                         source, sink);
@@ -3055,7 +3065,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                         const struct snd_soc_dapm_widget *widget)
 {
        struct snd_soc_dapm_widget *w;
-       size_t name_len;
        int ret;
 
        if ((w = dapm_cnew_widget(widget)) == NULL)
@@ -3096,19 +3105,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                break;
        }
 
-       name_len = strlen(widget->name) + 1;
        if (dapm->codec && dapm->codec->name_prefix)
-               name_len += 1 + strlen(dapm->codec->name_prefix);
-       w->name = kmalloc(name_len, GFP_KERNEL);
+               w->name = kasprintf(GFP_KERNEL, "%s %s",
+                       dapm->codec->name_prefix, widget->name);
+       else
+               w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
+
        if (w->name == NULL) {
                kfree(w);
                return NULL;
        }
-       if (dapm->codec && dapm->codec->name_prefix)
-               snprintf((char *)w->name, name_len, "%s %s",
-                       dapm->codec->name_prefix, widget->name);
-       else
-               snprintf((char *)w->name, name_len, "%s", widget->name);
 
        switch (w->id) {
        case snd_soc_dapm_switch:
index ccb6be4d658d27e3dd56528e02fdf5a59eecb999..b6c640332a1722c95c27fa8aa99b4d8b135d456f 100644 (file)
 
 #define DPCM_MAX_BE_USERS      8
 
+/**
+ * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
+ * @substream: the pcm substream
+ * @hw: the hardware parameters
+ *
+ * Sets the substream runtime hardware parameters.
+ */
+int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
+       const struct snd_pcm_hardware *hw)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       runtime->hw.info = hw->info;
+       runtime->hw.formats = hw->formats;
+       runtime->hw.period_bytes_min = hw->period_bytes_min;
+       runtime->hw.period_bytes_max = hw->period_bytes_max;
+       runtime->hw.periods_min = hw->periods_min;
+       runtime->hw.periods_max = hw->periods_max;
+       runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
+       runtime->hw.fifo_size = hw->fifo_size;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
+
 /* DPCM stream event, send event to FE and all active BEs. */
 static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
        int event)
@@ -124,6 +147,26 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
        }
 }
 
+static void soc_pcm_init_runtime_hw(struct snd_pcm_hardware *hw,
+       struct snd_soc_pcm_stream *codec_stream,
+       struct snd_soc_pcm_stream *cpu_stream)
+{
+       hw->rate_min = max(codec_stream->rate_min, cpu_stream->rate_min);
+       hw->rate_max = max(codec_stream->rate_max, cpu_stream->rate_max);
+       hw->channels_min = max(codec_stream->channels_min,
+               cpu_stream->channels_min);
+       hw->channels_max = min(codec_stream->channels_max,
+               cpu_stream->channels_max);
+       hw->formats = codec_stream->formats & cpu_stream->formats;
+       hw->rates = codec_stream->rates & cpu_stream->rates;
+       if (codec_stream->rates
+               & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
+               hw->rates |= cpu_stream->rates;
+       if (cpu_stream->rates
+               & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
+               hw->rates |= codec_stream->rates;
+}
+
 /*
  * Called by ALSA when a PCM substream is opened, the runtime->hw record is
  * then initialized and any private data can be allocated. This also calls
@@ -189,51 +232,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 
        /* Check that the codec and cpu DAIs are compatible */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               runtime->hw.rate_min =
-                       max(codec_dai_drv->playback.rate_min,
-                           cpu_dai_drv->playback.rate_min);
-               runtime->hw.rate_max =
-                       min(codec_dai_drv->playback.rate_max,
-                           cpu_dai_drv->playback.rate_max);
-               runtime->hw.channels_min =
-                       max(codec_dai_drv->playback.channels_min,
-                               cpu_dai_drv->playback.channels_min);
-               runtime->hw.channels_max =
-                       min(codec_dai_drv->playback.channels_max,
-                               cpu_dai_drv->playback.channels_max);
-               runtime->hw.formats =
-                       codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
-               runtime->hw.rates =
-                       codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
-               if (codec_dai_drv->playback.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= cpu_dai_drv->playback.rates;
-               if (cpu_dai_drv->playback.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= codec_dai_drv->playback.rates;
+               soc_pcm_init_runtime_hw(&runtime->hw, &codec_dai_drv->playback,
+                       &cpu_dai_drv->playback);
        } else {
-               runtime->hw.rate_min =
-                       max(codec_dai_drv->capture.rate_min,
-                           cpu_dai_drv->capture.rate_min);
-               runtime->hw.rate_max =
-                       min(codec_dai_drv->capture.rate_max,
-                           cpu_dai_drv->capture.rate_max);
-               runtime->hw.channels_min =
-                       max(codec_dai_drv->capture.channels_min,
-                               cpu_dai_drv->capture.channels_min);
-               runtime->hw.channels_max =
-                       min(codec_dai_drv->capture.channels_max,
-                               cpu_dai_drv->capture.channels_max);
-               runtime->hw.formats =
-                       codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
-               runtime->hw.rates =
-                       codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
-               if (codec_dai_drv->capture.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= cpu_dai_drv->capture.rates;
-               if (cpu_dai_drv->capture.rates
-                          & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= codec_dai_drv->capture.rates;
+               soc_pcm_init_runtime_hw(&runtime->hw, &codec_dai_drv->capture,
+                       &cpu_dai_drv->capture);
        }
 
        ret = -EINVAL;
index 4b3be6c3c91e28b170a7dcebd998559f9292f0ec..29b211e9c06020a641b1449099fc163e58770f87 100644 (file)
@@ -159,15 +159,10 @@ int __init snd_soc_util_init(void)
 {
        int ret;
 
-       soc_dummy_dev = platform_device_alloc("snd-soc-dummy", -1);
-       if (!soc_dummy_dev)
-               return -ENOMEM;
-
-       ret = platform_device_add(soc_dummy_dev);
-       if (ret != 0) {
-               platform_device_put(soc_dummy_dev);
-               return ret;
-       }
+       soc_dummy_dev =
+               platform_device_register_simple("snd-soc-dummy", -1, NULL, 0);
+       if (IS_ERR(soc_dummy_dev))
+               return PTR_ERR(soc_dummy_dev);
 
        ret = platform_driver_register(&soc_dummy_driver);
        if (ret != 0)
diff --git a/sound/soc/spear/Kconfig b/sound/soc/spear/Kconfig
new file mode 100644 (file)
index 0000000..3567d73
--- /dev/null
@@ -0,0 +1,9 @@
+config SND_SPEAR_SOC
+       tristate
+       select SND_SOC_DMAENGINE_PCM
+
+config SND_SPEAR_SPDIF_OUT
+       tristate
+
+config SND_SPEAR_SPDIF_IN
+       tristate
diff --git a/sound/soc/spear/Makefile b/sound/soc/spear/Makefile
new file mode 100644 (file)
index 0000000..c4ea716
--- /dev/null
@@ -0,0 +1,8 @@
+# SPEAR Platform Support
+snd-soc-spear-pcm-objs := spear_pcm.o
+snd-soc-spear-spdif-in-objs := spdif_in.o
+snd-soc-spear-spdif-out-objs := spdif_out.o
+
+obj-$(CONFIG_SND_SPEAR_SOC) += snd-soc-spear-pcm.o
+obj-$(CONFIG_SND_SPEAR_SPDIF_IN) += snd-soc-spear-spdif-in.o
+obj-$(CONFIG_SND_SPEAR_SPDIF_OUT) += snd-soc-spear-spdif-out.o
index 14d57e89bcbac5362efa85f40a41a9cf3e28f026..63acfeb4b69d22e91ab9e98cf81d7fbf9ef4cc04 100644 (file)
@@ -49,15 +49,12 @@ static void spdif_in_configure(struct spdif_in_dev *host)
        writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK);
 }
 
-static int spdif_in_startup(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *cpu_dai)
+static int spdif_in_dai_probe(struct snd_soc_dai *dai)
 {
-       struct spdif_in_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
+       struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
 
-       if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
-               return -EINVAL;
+       dai->capture_dma_data = &host->dma_params;
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&host->dma_params);
        return 0;
 }
 
@@ -70,7 +67,6 @@ static void spdif_in_shutdown(struct snd_pcm_substream *substream,
                return;
 
        writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK);
-       snd_soc_dai_set_dma_data(dai, substream, NULL);
 }
 
 static void spdif_in_format(struct spdif_in_dev *host, u32 format)
@@ -151,13 +147,13 @@ static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
 }
 
 static struct snd_soc_dai_ops spdif_in_dai_ops = {
-       .startup        = spdif_in_startup,
        .shutdown       = spdif_in_shutdown,
        .trigger        = spdif_in_trigger,
        .hw_params      = spdif_in_hw_params,
 };
 
-struct snd_soc_dai_driver spdif_in_dai = {
+static struct snd_soc_dai_driver spdif_in_dai = {
+       .probe = spdif_in_dai_probe,
        .capture = {
                .channels_min = 2,
                .channels_max = 2,
@@ -235,7 +231,7 @@ static int spdif_in_probe(struct platform_device *pdev)
        if (host->irq < 0)
                return -EINVAL;
 
-       host->clk = clk_get(&pdev->dev, NULL);
+       host->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->clk))
                return PTR_ERR(host->clk);
 
@@ -257,34 +253,21 @@ static int spdif_in_probe(struct platform_device *pdev)
        ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0,
                        "spdif-in", host);
        if (ret) {
-               clk_put(host->clk);
                dev_warn(&pdev->dev, "request_irq failed\n");
                return ret;
        }
 
-       ret = snd_soc_register_component(&pdev->dev, &spdif_in_component,
+       return snd_soc_register_component(&pdev->dev, &spdif_in_component,
                                         &spdif_in_dai, 1);
-       if (ret != 0) {
-               clk_put(host->clk);
-               return ret;
-       }
-
-       return 0;
 }
 
 static int spdif_in_remove(struct platform_device *pdev)
 {
-       struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev);
-
        snd_soc_unregister_component(&pdev->dev);
-       dev_set_drvdata(&pdev->dev, NULL);
-
-       clk_put(host->clk);
 
        return 0;
 }
 
-
 static struct platform_driver spdif_in_driver = {
        .probe          = spdif_in_probe,
        .remove         = spdif_in_remove,
index 1e3c3dda359846e07fa73f13b3538f81b3dedeb7..2fdf68c98d22a92fb53f587919123d069b31a43c 100644 (file)
@@ -62,8 +62,6 @@ static int spdif_out_startup(struct snd_pcm_substream *substream,
        if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
                return -EINVAL;
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&host->dma_params);
-
        ret = clk_enable(host->clk);
        if (ret)
                return ret;
@@ -84,7 +82,6 @@ static void spdif_out_shutdown(struct snd_pcm_substream *substream,
 
        clk_disable(host->clk);
        host->running = false;
-       snd_soc_dai_set_dma_data(dai, substream, NULL);
 }
 
 static void spdif_out_clock(struct spdif_out_dev *host, u32 core_freq,
@@ -243,8 +240,12 @@ static const struct snd_kcontrol_new spdif_out_controls[] = {
                        spdif_mute_get, spdif_mute_put),
 };
 
-int spdif_soc_dai_probe(struct snd_soc_dai *dai)
+static int spdif_soc_dai_probe(struct snd_soc_dai *dai)
 {
+       struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
+
+       dai->playback_dma_data = &host->dma_params;
+
        return snd_soc_add_dai_controls(dai, spdif_out_controls,
                                ARRAY_SIZE(spdif_out_controls));
 }
@@ -281,30 +282,18 @@ static int spdif_out_probe(struct platform_device *pdev)
        struct resource *res;
        int ret;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -EINVAL;
-
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                               resource_size(res), pdev->name)) {
-               dev_warn(&pdev->dev, "Failed to get memory resourse\n");
-               return -ENOENT;
-       }
-
        host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
        if (!host) {
                dev_warn(&pdev->dev, "kzalloc fail\n");
                return -ENOMEM;
        }
 
-       host->io_base = devm_ioremap(&pdev->dev, res->start,
-                               resource_size(res));
-       if (!host->io_base) {
-               dev_warn(&pdev->dev, "ioremap failed\n");
-               return -ENOMEM;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(host->io_base))
+               return PTR_ERR(host->io_base);
 
-       host->clk = clk_get(&pdev->dev, NULL);
+       host->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->clk))
                return PTR_ERR(host->clk);
 
@@ -320,22 +309,12 @@ static int spdif_out_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_component(&pdev->dev, &spdif_out_component,
                                         &spdif_out_dai, 1);
-       if (ret != 0) {
-               clk_put(host->clk);
-               return ret;
-       }
-
-       return 0;
+       return ret;
 }
 
 static int spdif_out_remove(struct platform_device *pdev)
 {
-       struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev);
-
        snd_soc_unregister_component(&pdev->dev);
-       dev_set_drvdata(&pdev->dev, NULL);
-
-       clk_put(host->clk);
 
        return 0;
 }
index 2fbd4899d8ef292dc11beac79ff01e66b8bda751..4707f2b862c3762502d622d1d799944ee0e401fc 100644 (file)
 
 #include <linux/module.h>
 #include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-#include <sound/core.h>
 #include <sound/dmaengine_pcm.h>
 #include <sound/pcm.h>
-#include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/spear_dma.h>
 
-static struct snd_pcm_hardware spear_pcm_hardware = {
+static const struct snd_pcm_hardware spear_pcm_hardware = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
@@ -37,149 +31,33 @@ static struct snd_pcm_hardware spear_pcm_hardware = {
        .fifo_size = 0, /* fifo size in bytes */
 };
 
-static int spear_pcm_hw_params(struct snd_pcm_substream *substream,
-               struct snd_pcm_hw_params *params)
+static struct dma_chan *spear_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
+       struct snd_pcm_substream *substream)
 {
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+       struct spear_dma_data *dma_data;
 
-       return 0;
-}
-
-static int spear_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       snd_pcm_set_runtime_buffer(substream, NULL);
-
-       return 0;
-}
-
-static int spear_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       struct spear_dma_data *dma_data = (struct spear_dma_data *)
-               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       int ret;
-
-       ret = snd_soc_set_runtime_hwparams(substream, &spear_pcm_hardware);
-       if (ret)
-               return ret;
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
-       return snd_dmaengine_pcm_open_request_chan(substream, dma_data->filter,
-                               dma_data);
+       return snd_dmaengine_pcm_request_channel(dma_data->filter, dma_data);
 }
 
-static int spear_pcm_mmap(struct snd_pcm_substream *substream,
-               struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                       runtime->dma_area, runtime->dma_addr,
-                       runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops spear_pcm_ops = {
-       .open           = spear_pcm_open,
-       .close          = snd_dmaengine_pcm_close_release_chan,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = spear_pcm_hw_params,
-       .hw_free        = spear_pcm_hw_free,
-       .trigger        = snd_dmaengine_pcm_trigger,
-       .pointer        = snd_dmaengine_pcm_pointer,
-       .mmap           = spear_pcm_mmap,
-};
-
-static int
-spear_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
-               size_t size)
-{
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
-
-       buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = pcm->card->dev;
-       buf->private_data = NULL;
-
-       buf->area = dma_alloc_writecombine(pcm->card->dev, size,
-                       &buf->addr, GFP_KERNEL);
-       if (!buf->area)
-               return -ENOMEM;
-
-       dev_info(buf->dev.dev,
-                       " preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
-                       (void *)buf->area, (void *)buf->addr, size);
-
-       buf->bytes = size;
-       return 0;
-}
-
-static void spear_pcm_free(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       for (stream = 0; stream < 2; stream++) {
-               substream = pcm->streams[stream].substream;
-               if (!substream)
-                       continue;
-
-               buf = &substream->dma_buffer;
-               if (!buf || !buf->area)
-                       continue;
-
-               dma_free_writecombine(pcm->card->dev, buf->bytes,
-                               buf->area, buf->addr);
-               buf->area = NULL;
-       }
-}
-
-static u64 spear_pcm_dmamask = DMA_BIT_MASK(32);
-
-static int spear_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_card *card = rtd->card->snd_card;
-       int ret;
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &spear_pcm_dmamask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
-       if (rtd->cpu_dai->driver->playback.channels_min) {
-               ret = spear_pcm_preallocate_dma_buffer(rtd->pcm,
-                               SNDRV_PCM_STREAM_PLAYBACK,
-                               spear_pcm_hardware.buffer_bytes_max);
-               if (ret)
-                       return ret;
-       }
-
-       if (rtd->cpu_dai->driver->capture.channels_min) {
-               ret = spear_pcm_preallocate_dma_buffer(rtd->pcm,
-                               SNDRV_PCM_STREAM_CAPTURE,
-                               spear_pcm_hardware.buffer_bytes_max);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_platform_driver spear_soc_platform = {
-       .ops            =       &spear_pcm_ops,
-       .pcm_new        =       spear_pcm_new,
-       .pcm_free       =       spear_pcm_free,
+static const struct snd_dmaengine_pcm_config spear_dmaengine_pcm_config = {
+       .pcm_hardware = &spear_pcm_hardware,
+       .compat_request_channel = spear_pcm_request_chan,
+       .prealloc_buffer_size = 16 * 1024,
 };
 
 static int spear_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&pdev->dev, &spear_soc_platform);
+       return snd_dmaengine_pcm_register(&pdev->dev,
+               &spear_dmaengine_pcm_config,
+               SND_DMAENGINE_PCM_FLAG_NO_DT |
+               SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 
 static int spear_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&pdev->dev);
-
+       snd_dmaengine_pcm_unregister(&pdev->dev);
        return 0;
 }
 
index b1c9d573da052f5cdd74a6f4637e51cfffdebce5..995b120c2cd0a49a90a191e1e06649cb52396839 100644 (file)
@@ -59,6 +59,16 @@ config SND_SOC_TEGRA30_I2S
          Tegra30 I2S interface. You will also need to select the individual
          machine drivers to support below.
 
+config SND_SOC_TEGRA_RT5640
+       tristate "SoC Audio support for Tegra boards using an RT5640 codec"
+       depends on SND_SOC_TEGRA && I2C
+       select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+       select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+       select SND_SOC_RT5640
+       help
+         Say Y or M here if you want to add support for SoC audio on Tegra
+         boards using the RT5640 codec, such as Dalmore.
+
 config SND_SOC_TEGRA_WM8753
        tristate "SoC Audio support for Tegra boards using a WM8753 codec"
        depends on SND_SOC_TEGRA && I2C
index 416a14bde41b59452dc350fa64633e491b28916b..21d2550a08a4fc1e15e41f4c66cc0a84a290396f 100644 (file)
@@ -18,12 +18,14 @@ obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
 obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 
 # Tegra machine Support
+snd-soc-tegra-rt5640-objs := tegra_rt5640.o
 snd-soc-tegra-wm8753-objs := tegra_wm8753.o
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
 snd-soc-tegra-wm9712-objs := tegra_wm9712.o
 snd-soc-tegra-trimslice-objs := trimslice.o
 snd-soc-tegra-alc5632-objs := tegra_alc5632.o
 
+obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o
index 2f70ea7f6618ae04dc8f125925638d4e9f90c147..e58233f7df616e6bb406f809cea23069c4059933 100644 (file)
@@ -142,13 +142,12 @@ static void tegra20_ac97_codec_write(struct snd_ac97 *ac97_snd,
        } while (!time_after(jiffies, timeout));
 }
 
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops tegra20_ac97_ops = {
        .read           = tegra20_ac97_codec_read,
        .write          = tegra20_ac97_codec_write,
        .reset          = tegra20_ac97_codec_reset,
        .warm_reset     = tegra20_ac97_codec_warm_reset,
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static inline void tegra20_ac97_start_playback(struct tegra20_ac97 *ac97)
 {
@@ -313,7 +312,7 @@ static const struct regmap_config tegra20_ac97_regmap_config = {
 static int tegra20_ac97_platform_probe(struct platform_device *pdev)
 {
        struct tegra20_ac97 *ac97;
-       struct resource *mem, *memregion;
+       struct resource *mem;
        u32 of_dma[2];
        void __iomem *regs;
        int ret = 0;
@@ -327,7 +326,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        }
        dev_set_drvdata(&pdev->dev, ac97);
 
-       ac97->clk_ac97 = clk_get(&pdev->dev, NULL);
+       ac97->clk_ac97 = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(ac97->clk_ac97)) {
                dev_err(&pdev->dev, "Can't retrieve ac97 clock\n");
                ret = PTR_ERR(ac97->clk_ac97);
@@ -341,18 +340,9 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
                goto err_clk_put;
        }
 
-       memregion = devm_request_mem_region(&pdev->dev, mem->start,
-                                           resource_size(mem), DRV_NAME);
-       if (!memregion) {
-               dev_err(&pdev->dev, "Memory region already claimed\n");
-               ret = -EBUSY;
-               goto err_clk_put;
-       }
-
-       regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
-       if (!regs) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -ENOMEM;
+       regs = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(regs)) {
+               ret = PTR_ERR(regs);
                goto err_clk_put;
        }
 
@@ -403,23 +393,9 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        ac97->capture_dma_data.maxburst = 4;
        ac97->capture_dma_data.slave_id = of_dma[0];
 
-       ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
-                                        &tegra20_ac97_dai, 1);
-       if (ret) {
-               dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
-               ret = -ENOMEM;
-               goto err_clk_put;
-       }
-
-       ret = tegra_pcm_platform_register(&pdev->dev);
-       if (ret) {
-               dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-               goto err_unregister_component;
-       }
-
        ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
        if (ret)
-               goto err_unregister_pcm;
+               goto err_clk_put;
 
        ret = tegra_asoc_utils_set_ac97_rate(&ac97->util_data);
        if (ret)
@@ -431,20 +407,40 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
                goto err_asoc_utils_fini;
        }
 
+       ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
+               goto err_asoc_utils_fini;
+       }
+
+       ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
+                                        &tegra20_ac97_dai, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+               ret = -ENOMEM;
+               goto err_asoc_utils_fini;
+       }
+
+       ret = tegra_pcm_platform_register(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+               goto err_unregister_component;
+       }
+
        /* XXX: crufty ASoC AC97 API - only one AC97 codec allowed */
        workdata = ac97;
 
        return 0;
 
-err_asoc_utils_fini:
-       tegra_asoc_utils_fini(&ac97->util_data);
 err_unregister_pcm:
        tegra_pcm_platform_unregister(&pdev->dev);
 err_unregister_component:
        snd_soc_unregister_component(&pdev->dev);
+err_asoc_utils_fini:
+       tegra_asoc_utils_fini(&ac97->util_data);
 err_clk_put:
-       clk_put(ac97->clk_ac97);
 err:
+       snd_soc_set_ac97_ops(NULL);
        return ret;
 }
 
@@ -458,7 +454,8 @@ static int tegra20_ac97_platform_remove(struct platform_device *pdev)
        tegra_asoc_utils_fini(&ac97->util_data);
 
        clk_disable_unprepare(ac97->clk_ac97);
-       clk_put(ac97->clk_ac97);
+
+       snd_soc_set_ac97_ops(NULL);
 
        return 0;
 }
index 23e592f453faa9786b282f7e86c365edaf6af2ea..d554d46d08b550788a1bd0ad706f8ed7948a318a 100644 (file)
@@ -627,9 +627,34 @@ static int tegra30_ahub_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tegra30_ahub_suspend(struct device *dev)
+{
+       regcache_mark_dirty(ahub->regmap_ahub);
+       regcache_mark_dirty(ahub->regmap_apbif);
+
+       return 0;
+}
+
+static int tegra30_ahub_resume(struct device *dev)
+{
+       int ret;
+
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               return ret;
+       ret = regcache_sync(ahub->regmap_ahub);
+       ret |= regcache_sync(ahub->regmap_apbif);
+       pm_runtime_put(dev);
+
+       return ret;
+}
+#endif
+
 static const struct dev_pm_ops tegra30_ahub_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
                           tegra30_ahub_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra30_ahub_suspend, tegra30_ahub_resume)
 };
 
 static struct platform_driver tegra30_ahub_driver = {
index 31d092d83c71e5981cc36adee0ca0655e308bde1..d04146cad61f4f2dd0227815d0f25970e22e4cae 100644 (file)
@@ -514,6 +514,31 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tegra30_i2s_suspend(struct device *dev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+
+       regcache_mark_dirty(i2s->regmap);
+
+       return 0;
+}
+
+static int tegra30_i2s_resume(struct device *dev)
+{
+       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+       int ret;
+
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               return ret;
+       ret = regcache_sync(i2s->regmap);
+       pm_runtime_put(dev);
+
+       return ret;
+}
+#endif
+
 static const struct of_device_id tegra30_i2s_of_match[] = {
        { .compatible = "nvidia,tegra30-i2s", },
        {},
@@ -522,6 +547,7 @@ static const struct of_device_id tegra30_i2s_of_match[] = {
 static const struct dev_pm_ops tegra30_i2s_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
                           tegra30_i2s_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(tegra30_i2s_suspend, tegra30_i2s_resume)
 };
 
 static struct platform_driver tegra30_i2s_driver = {
index 24fb001be7f4e7007b8d4f0d1f4ad99b53d3ecb9..d173880f290d0f762ec0151fb442e815354b8815 100644 (file)
@@ -173,7 +173,6 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
                          struct device *dev)
 {
        int ret;
-       bool new_clocks = false;
 
        data->dev = dev;
 
@@ -181,40 +180,28 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
                data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
        else if (of_machine_is_compatible("nvidia,tegra30"))
                data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
-       else if (of_machine_is_compatible("nvidia,tegra114")) {
+       else if (of_machine_is_compatible("nvidia,tegra114"))
                data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA114;
-               new_clocks = true;
-       } else {
+       else {
                dev_err(data->dev, "SoC unknown to Tegra ASoC utils\n");
                return -EINVAL;
        }
 
-       if (new_clocks)
-               data->clk_pll_a = clk_get(dev, "pll_a");
-       else
-               data->clk_pll_a = clk_get_sys(NULL, "pll_a");
+       data->clk_pll_a = clk_get(dev, "pll_a");
        if (IS_ERR(data->clk_pll_a)) {
                dev_err(data->dev, "Can't retrieve clk pll_a\n");
                ret = PTR_ERR(data->clk_pll_a);
                goto err;
        }
 
-       if (new_clocks)
-               data->clk_pll_a_out0 = clk_get(dev, "pll_a_out0");
-       else
-               data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
+       data->clk_pll_a_out0 = clk_get(dev, "pll_a_out0");
        if (IS_ERR(data->clk_pll_a_out0)) {
                dev_err(data->dev, "Can't retrieve clk pll_a_out0\n");
                ret = PTR_ERR(data->clk_pll_a_out0);
                goto err_put_pll_a;
        }
 
-       if (new_clocks)
-               data->clk_cdev1 = clk_get(dev, "mclk");
-       else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
-               data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
-       else
-               data->clk_cdev1 = clk_get_sys("extern1", NULL);
+       data->clk_cdev1 = clk_get(dev, "mclk");
        if (IS_ERR(data->clk_cdev1)) {
                dev_err(data->dev, "Can't retrieve clk cdev1\n");
                ret = PTR_ERR(data->clk_cdev1);
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
new file mode 100644 (file)
index 0000000..08794f9
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+* tegra_rt5640.c - Tegra machine ASoC driver for boards using WM8903 codec.
+ *
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/rt5640.h"
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-rt5640"
+
+struct tegra_rt5640 {
+       struct tegra_asoc_utils_data util_data;
+       int gpio_hp_det;
+};
+
+static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_card *card = codec->card;
+       struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
+       int srate, mclk;
+       int err;
+
+       srate = params_rate(params);
+       mclk = 256 * srate;
+
+       err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+       if (err < 0) {
+               dev_err(card->dev, "Can't configure clocks\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, mclk,
+                                       SND_SOC_CLOCK_IN);
+       if (err < 0) {
+               dev_err(card->dev, "codec_dai clock not set\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops tegra_rt5640_ops = {
+       .hw_params = tegra_rt5640_asoc_hw_params,
+};
+
+static struct snd_soc_jack tegra_rt5640_hp_jack;
+
+static struct snd_soc_jack_pin tegra_rt5640_hp_jack_pins[] = {
+       {
+               .pin = "Headphones",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+static struct snd_soc_jack_gpio tegra_rt5640_hp_jack_gpio = {
+       .name = "Headphone detection",
+       .report = SND_JACK_HEADPHONE,
+       .debounce_time = 150,
+       .invert = 1,
+};
+
+static const struct snd_soc_dapm_widget tegra_rt5640_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphones", NULL),
+       SND_SOC_DAPM_SPK("Speakers", NULL),
+};
+
+static const struct snd_kcontrol_new tegra_rt5640_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speakers"),
+};
+
+static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(codec->card);
+
+       snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
+                        &tegra_rt5640_hp_jack);
+       snd_soc_jack_add_pins(&tegra_rt5640_hp_jack,
+                       ARRAY_SIZE(tegra_rt5640_hp_jack_pins),
+                       tegra_rt5640_hp_jack_pins);
+
+       if (gpio_is_valid(machine->gpio_hp_det)) {
+               tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det;
+               snd_soc_jack_add_gpios(&tegra_rt5640_hp_jack,
+                                               1,
+                                               &tegra_rt5640_hp_jack_gpio);
+       }
+
+       return 0;
+}
+
+static struct snd_soc_dai_link tegra_rt5640_dai = {
+       .name = "RT5640",
+       .stream_name = "RT5640 PCM",
+       .codec_dai_name = "rt5640-aif1",
+       .init = tegra_rt5640_asoc_init,
+       .ops = &tegra_rt5640_ops,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_rt5640 = {
+       .name = "tegra-rt5640",
+       .owner = THIS_MODULE,
+       .dai_link = &tegra_rt5640_dai,
+       .num_links = 1,
+       .controls = tegra_rt5640_controls,
+       .num_controls = ARRAY_SIZE(tegra_rt5640_controls),
+       .dapm_widgets = tegra_rt5640_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tegra_rt5640_dapm_widgets),
+       .fully_routed = true,
+};
+
+static int tegra_rt5640_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct snd_soc_card *card = &snd_soc_tegra_rt5640;
+       struct tegra_rt5640 *machine;
+       int ret;
+
+       machine = devm_kzalloc(&pdev->dev,
+                       sizeof(struct tegra_rt5640), GFP_KERNEL);
+       if (!machine) {
+               dev_err(&pdev->dev, "Can't allocate tegra_rt5640\n");
+               return -ENOMEM;
+       }
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, machine);
+
+       machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+       if (machine->gpio_hp_det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+       if (ret)
+               goto err;
+
+       ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+       if (ret)
+               goto err;
+
+       tegra_rt5640_dai.codec_of_node = of_parse_phandle(np,
+                       "nvidia,audio-codec", 0);
+       if (!tegra_rt5640_dai.codec_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,audio-codec' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_rt5640_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
+       if (!tegra_rt5640_dai.cpu_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_rt5640_dai.platform_of_node = tegra_rt5640_dai.cpu_of_node;
+
+       ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+       if (ret)
+               goto err;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+                       ret);
+               goto err_fini_utils;
+       }
+
+       return 0;
+
+err_fini_utils:
+       tegra_asoc_utils_fini(&machine->util_data);
+err:
+       return ret;
+}
+
+static int tegra_rt5640_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
+
+       snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, 1,
+                               &tegra_rt5640_hp_jack_gpio);
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&machine->util_data);
+
+       return 0;
+}
+
+static const struct of_device_id tegra_rt5640_of_match[] = {
+       { .compatible = "nvidia,tegra-audio-rt5640", },
+       {},
+};
+
+static struct platform_driver tegra_rt5640_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = tegra_rt5640_of_match,
+       },
+       .probe = tegra_rt5640_probe,
+       .remove = tegra_rt5640_remove,
+};
+module_platform_driver(tegra_rt5640_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra+RT5640 machine ASoC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_rt5640_of_match);
index 8a2840304d288e80cbce6e0b7946d354eaa8b1cb..4bcce8a3cdedd618e18844a55373c273cbd6427c 100644 (file)
@@ -119,12 +119,11 @@ static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
 }
 
 /* AC97 controller operations */
-struct snd_ac97_bus_ops soc_ac97_ops = {
+static struct snd_ac97_bus_ops txx9aclc_ac97_ops = {
        .read           = txx9aclc_ac97_read,
        .write          = txx9aclc_ac97_write,
        .reset          = txx9aclc_ac97_cold_reset,
 };
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
 {
@@ -188,9 +187,9 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
        if (!r)
                return -EBUSY;
 
-       if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
-                                    dev_name(&pdev->dev)))
-               return -EBUSY;
+       drvdata->base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(drvdata->base))
+               return PTR_ERR(drvdata->base);
 
        drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
@@ -201,14 +200,15 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
            r->start >= TXX9_DIRECTMAP_BASE &&
            r->start < TXX9_DIRECTMAP_BASE + 0x400000)
                drvdata->physbase |= 0xf00000000ull;
-       drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
-       if (!drvdata->base)
-               return -EBUSY;
        err = devm_request_irq(&pdev->dev, irq, txx9aclc_ac97_irq,
                               0, dev_name(&pdev->dev), drvdata);
        if (err < 0)
                return err;
 
+       err = snd_soc_set_ac97_ops(&txx9aclc_ac97_ops);
+       if (err < 0)
+               return err;
+
        return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component,
                                          &txx9aclc_ac97_dai, 1);
 }
@@ -216,6 +216,7 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
 static int txx9aclc_ac97_dev_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_component(&pdev->dev);
+       snd_soc_set_ac97_ops(NULL);
        return 0;
 }
 
index 204b899c2311e6033f525a9f0c79ea9fb29ee3c1..8f5cd00a6e468622af895ed4faebeaf78d7b8f9e 100644 (file)
@@ -27,7 +27,7 @@
 #include "mop500_ab8500.h"
 
 /* Define the whole MOP500 soundcard, linking platform to the codec-drivers  */
-struct snd_soc_dai_link mop500_dai_links[] = {
+static struct snd_soc_dai_link mop500_dai_links[] = {
        {
                .name = "ab8500_0",
                .stream_name = "ab8500_0",
index 892ad9a05c9f0238018b822aabe7061063815683..7e923ecf89010e92b1ec288d0fcd9966a38e7401 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/mutex.h>
 
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -24,6 +25,7 @@
 
 #include "ux500_pcm.h"
 #include "ux500_msp_dai.h"
+#include "mop500_ab8500.h"
 #include "../codecs/ab8500-codec.h"
 
 #define TX_SLOT_MONO   0x0008
 static unsigned int tx_slots = DEF_TX_SLOTS;
 static unsigned int rx_slots = DEF_RX_SLOTS;
 
+/* Configuration consistency parameters */
+static DEFINE_MUTEX(mop500_ab8500_params_lock);
+static unsigned long mop500_ab8500_usage;
+static int mop500_ab8500_rate;
+static int mop500_ab8500_channels;
+
 /* Clocks */
 static const char * const enum_mclk[] = {
        "SYSCLK",
@@ -125,9 +133,9 @@ static int mop500_ab8500_set_mclk(struct device *dev,
 static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
        struct mop500_ab8500_drvdata *drvdata =
-                               snd_soc_card_get_drvdata(codec->card);
+                               snd_soc_card_get_drvdata(card);
 
        ucontrol->value.enumerated.item[0] = drvdata->mclk_sel;
 
@@ -137,9 +145,9 @@ static int mclk_input_control_get(struct snd_kcontrol *kcontrol,
 static int mclk_input_control_put(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
        struct mop500_ab8500_drvdata *drvdata =
-                               snd_soc_card_get_drvdata(codec->card);
+                               snd_soc_card_get_drvdata(card);
        unsigned int val = ucontrol->value.enumerated.item[0];
 
        if (val > (unsigned int)MCLK_ULPCLK)
@@ -160,16 +168,6 @@ static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
        SOC_ENUM_EXT("Master Clock Select",
                soc_enum_mclk,
                mclk_input_control_get, mclk_input_control_put),
-       /* Digital interface - Clocks */
-       SOC_SINGLE("Digital Interface Master Generator Switch",
-               AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENMASTGEN,
-               1, 0),
-       SOC_SINGLE("Digital Interface 0 Bit-clock Switch",
-               AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENFSBITCLK0,
-               1, 0),
-       SOC_SINGLE("Digital Interface 1 Bit-clock Switch",
-               AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENFSBITCLK1,
-               1, 0),
        SOC_DAPM_PIN_SWITCH("Headset Left"),
        SOC_DAPM_PIN_SWITCH("Headset Right"),
        SOC_DAPM_PIN_SWITCH("Earpiece"),
@@ -193,7 +191,7 @@ static struct snd_kcontrol_new mop500_ab8500_ctrls[] = {
 
 /* ASoC */
 
-int mop500_ab8500_startup(struct snd_pcm_substream *substream)
+static int mop500_ab8500_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
@@ -202,7 +200,7 @@ int mop500_ab8500_startup(struct snd_pcm_substream *substream)
                                snd_soc_card_get_drvdata(rtd->card));
 }
 
-void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
+static void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct device *dev = rtd->card->dev;
@@ -216,7 +214,7 @@ void mop500_ab8500_shutdown(struct snd_pcm_substream *substream)
                rx_slots = DEF_RX_SLOTS;
 }
 
-int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
+static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
                        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -240,6 +238,21 @@ int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
                substream->name,
                substream->number);
 
+       /* Ensure configuration consistency between DAIs */
+       mutex_lock(&mop500_ab8500_params_lock);
+       if (mop500_ab8500_usage) {
+               if (mop500_ab8500_rate != params_rate(params) ||
+                   mop500_ab8500_channels != params_channels(params)) {
+                       mutex_unlock(&mop500_ab8500_params_lock);
+                       return -EBUSY;
+               }
+       } else {
+               mop500_ab8500_rate = params_rate(params);
+               mop500_ab8500_channels = params_channels(params);
+       }
+       __set_bit(cpu_dai->id, &mop500_ab8500_usage);
+       mutex_unlock(&mop500_ab8500_params_lock);
+
        channels = params_channels(params);
 
        switch (params_format(params)) {
@@ -338,9 +351,22 @@ int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int mop500_ab8500_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+       mutex_lock(&mop500_ab8500_params_lock);
+       __clear_bit(cpu_dai->id, &mop500_ab8500_usage);
+       mutex_unlock(&mop500_ab8500_params_lock);
+
+       return 0;
+}
+
 struct snd_soc_ops mop500_ab8500_ops[] = {
        {
                .hw_params = mop500_ab8500_hw_params,
+               .hw_free = mop500_ab8500_hw_free,
                .startup = mop500_ab8500_startup,
                .shutdown = mop500_ab8500_shutdown,
        }
@@ -385,7 +411,7 @@ int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd)
        drvdata->mclk_sel = MCLK_ULPCLK;
 
        /* Add controls */
-       ret = snd_soc_add_codec_controls(codec, mop500_ab8500_ctrls,
+       ret = snd_soc_add_card_controls(codec->card, mop500_ab8500_ctrls,
                        ARRAY_SIZE(mop500_ab8500_ctrls));
        if (ret < 0) {
                pr_err("%s: Failed to add machine-controls (%d)!\n",
index 7d5fc1328523dfa60e6ae77bd4e856709ee0c246..c6fb5cce980e365f4fa84a02fa2b4254a9887e66 100644 (file)
@@ -658,14 +658,11 @@ static int ux500_msp_dai_probe(struct snd_soc_dai *dai)
 {
        struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
 
-       drvdata->playback_dma_data.dma_cfg = drvdata->msp->dma_cfg_tx;
-       drvdata->capture_dma_data.dma_cfg = drvdata->msp->dma_cfg_rx;
+       dai->playback_dma_data = &drvdata->msp->playback_dma_data;
+       dai->capture_dma_data = &drvdata->msp->capture_dma_data;
 
-       dai->playback_dma_data = &drvdata->playback_dma_data;
-       dai->capture_dma_data = &drvdata->capture_dma_data;
-
-       drvdata->playback_dma_data.data_size = drvdata->slot_width;
-       drvdata->capture_dma_data.data_size = drvdata->slot_width;
+       drvdata->msp->playback_dma_data.data_size = drvdata->slot_width;
+       drvdata->msp->capture_dma_data.data_size = drvdata->slot_width;
 
        return 0;
 }
index f53104359f15585ac13591d681e70e50ce7f9184..312ae535e35144c014a834bd62f7f0858b2a37b3 100644 (file)
@@ -51,15 +51,11 @@ enum ux500_msp_clock_id {
 struct ux500_msp_i2s_drvdata {
        struct ux500_msp *msp;
        struct regulator *reg_vape;
-       struct ux500_msp_dma_params playback_dma_data;
-       struct ux500_msp_dma_params capture_dma_data;
        unsigned int fmt;
        unsigned int tx_mask;
        unsigned int rx_mask;
        int slots;
        int slot_width;
-       u8 configured;
-       int data_delay;
 
        /* Clocks */
        unsigned int master_clk;
index f2db6c90a9e2056cde84ce0798b5ae6100086eb6..1ca8b08ae993d34a100b22032315b9c94ce9ec03 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/io.h>
@@ -26,9 +25,6 @@
 
 #include "ux500_msp_i2s.h"
 
-/* MSP1/3 Tx/Rx usage protection */
-static DEFINE_SPINLOCK(msp_rxtx_lock);
-
  /* Protocol desciptors */
 static const struct msp_protdesc prot_descs[] = {
        { /* I2S */
@@ -356,24 +352,8 @@ static int configure_multichannel(struct ux500_msp *msp,
 
 static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
 {
-       int status = 0, retval = 0;
+       int status = 0;
        u32 reg_val_DMACR, reg_val_GCR;
-       unsigned long flags;
-
-       /* Check msp state whether in RUN or CONFIGURED Mode */
-       if (msp->msp_state == MSP_STATE_IDLE) {
-               spin_lock_irqsave(&msp_rxtx_lock, flags);
-               if (msp->pinctrl_rxtx_ref == 0 &&
-                       !(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_def))) {
-                       retval = pinctrl_select_state(msp->pinctrl_p,
-                                               msp->pinctrl_def);
-                       if (retval)
-                               pr_err("could not set MSP defstate\n");
-               }
-               if (!retval)
-                       msp->pinctrl_rxtx_ref++;
-               spin_unlock_irqrestore(&msp_rxtx_lock, flags);
-       }
 
        /* Configure msp with protocol dependent settings */
        configure_protocol(msp, config);
@@ -387,12 +367,14 @@ static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
        }
 
        /* Make sure the correct DMA-directions are configured */
-       if ((config->direction & MSP_DIR_RX) && (!msp->dma_cfg_rx)) {
+       if ((config->direction & MSP_DIR_RX) &&
+                       !msp->capture_dma_data.dma_cfg) {
                dev_err(msp->dev, "%s: ERROR: MSP RX-mode is not configured!",
                        __func__);
                return -EINVAL;
        }
-       if ((config->direction == MSP_DIR_TX) && (!msp->dma_cfg_tx)) {
+       if ((config->direction == MSP_DIR_TX) &&
+                       !msp->playback_dma_data.dma_cfg) {
                dev_err(msp->dev, "%s: ERROR: MSP TX-mode is not configured!",
                        __func__);
                return -EINVAL;
@@ -630,8 +612,7 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
 
 int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
 {
-       int status = 0, retval = 0;
-       unsigned long flags;
+       int status = 0;
 
        dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
 
@@ -643,18 +624,6 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
                               (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
                              msp->registers + MSP_GCR);
 
-               spin_lock_irqsave(&msp_rxtx_lock, flags);
-               WARN_ON(!msp->pinctrl_rxtx_ref);
-               msp->pinctrl_rxtx_ref--;
-               if (msp->pinctrl_rxtx_ref == 0 &&
-                       !(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_sleep))) {
-                       retval = pinctrl_select_state(msp->pinctrl_p,
-                                               msp->pinctrl_sleep);
-                       if (retval)
-                               pr_err("could not set MSP sleepstate\n");
-               }
-               spin_unlock_irqrestore(&msp_rxtx_lock, flags);
-
                writel(0, msp->registers + MSP_GCR);
                writel(0, msp->registers + MSP_TCF);
                writel(0, msp->registers + MSP_RCF);
@@ -682,7 +651,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
                        struct msp_i2s_platform_data *platform_data)
 {
        struct resource *res = NULL;
-       struct i2s_controller *i2s_cont;
        struct device_node *np = pdev->dev.of_node;
        struct ux500_msp *msp;
 
@@ -707,8 +675,8 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
 
        msp->id = platform_data->id;
        msp->dev = &pdev->dev;
-       msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
-       msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
+       msp->playback_dma_data.dma_cfg = platform_data->msp_i2s_dma_tx;
+       msp->capture_dma_data.dma_cfg = platform_data->msp_i2s_dma_rx;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
@@ -717,6 +685,9 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
                return -ENOMEM;
        }
 
+       msp->playback_dma_data.tx_rx_addr = res->start + MSP_DR;
+       msp->capture_dma_data.tx_rx_addr = res->start + MSP_DR;
+
        msp->registers = devm_ioremap(&pdev->dev, res->start,
                                      resource_size(res));
        if (msp->registers == NULL) {
@@ -727,41 +698,6 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
        msp->msp_state = MSP_STATE_IDLE;
        msp->loopback_enable = 0;
 
-       /* I2S-controller is allocated and added in I2S controller class. */
-       i2s_cont = devm_kzalloc(&pdev->dev, sizeof(*i2s_cont), GFP_KERNEL);
-       if (!i2s_cont) {
-               dev_err(&pdev->dev,
-                       "%s: ERROR: Failed to allocate I2S-controller!\n",
-                       __func__);
-               return -ENOMEM;
-       }
-       i2s_cont->dev.parent = &pdev->dev;
-       i2s_cont->data = (void *)msp;
-       i2s_cont->id = (s16)msp->id;
-       snprintf(i2s_cont->name, sizeof(i2s_cont->name), "ux500-msp-i2s.%04x",
-               msp->id);
-       dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name);
-       msp->i2s_cont = i2s_cont;
-
-       msp->pinctrl_p = pinctrl_get(msp->dev);
-       if (IS_ERR(msp->pinctrl_p))
-               dev_err(&pdev->dev, "could not get MSP pinctrl\n");
-       else {
-               msp->pinctrl_def = pinctrl_lookup_state(msp->pinctrl_p,
-                                               PINCTRL_STATE_DEFAULT);
-               if (IS_ERR(msp->pinctrl_def)) {
-                       dev_err(&pdev->dev,
-                               "could not get MSP defstate (%li)\n",
-                               PTR_ERR(msp->pinctrl_def));
-               }
-               msp->pinctrl_sleep = pinctrl_lookup_state(msp->pinctrl_p,
-                                               PINCTRL_STATE_SLEEP);
-               if (IS_ERR(msp->pinctrl_sleep))
-                       dev_err(&pdev->dev,
-                               "could not get MSP idlestate (%li)\n",
-                               PTR_ERR(msp->pinctrl_def));
-       }
-
        return 0;
 }
 
@@ -769,8 +705,6 @@ void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
                        struct ux500_msp *msp)
 {
        dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id);
-
-       device_unregister(&msp->i2s_cont->dev);
 }
 
 MODULE_LICENSE("GPL v2");
index e5cd105c90f9387dd450f92c40291596d3398db7..258d0bcee0bd540aed67c757742f1a0f698f3a5f 100644 (file)
@@ -16,6 +16,7 @@
 #define UX500_MSP_I2S_H
 
 #include <linux/platform_device.h>
+#include <linux/platform_data/asoc-ux500-msp.h>
 
 #define MSP_INPUT_FREQ_APB 48000000
 
@@ -341,11 +342,6 @@ enum msp_compress_mode {
        MSP_COMPRESS_MODE_A_LAW = 3
 };
 
-enum msp_spi_burst_mode {
-       MSP_SPI_BURST_MODE_DISABLE = 0,
-       MSP_SPI_BURST_MODE_ENABLE = 1
-};
-
 enum msp_expand_mode {
        MSP_EXPAND_MODE_LINEAR = 0,
        MSP_EXPAND_MODE_LINEAR_SIGNED = 1,
@@ -370,13 +366,6 @@ enum msp_protocol {
  */
 #define MAX_MSP_BACKUP_REGS 36
 
-enum enum_i2s_controller {
-       MSP_0_I2S_CONTROLLER = 0,
-       MSP_1_I2S_CONTROLLER,
-       MSP_2_I2S_CONTROLLER,
-       MSP_3_I2S_CONTROLLER,
-};
-
 enum i2s_direction_t {
        MSP_DIR_TX = 0x01,
        MSP_DIR_RX = 0x02,
@@ -454,32 +443,6 @@ struct msp_protdesc {
        u32 clocks_per_frame;
 };
 
-struct i2s_message {
-       enum i2s_direction_t i2s_direction;
-       void *txdata;
-       void *rxdata;
-       size_t txbytes;
-       size_t rxbytes;
-       int dma_flag;
-       int tx_offset;
-       int rx_offset;
-       bool cyclic_dma;
-       dma_addr_t buf_addr;
-       size_t buf_len;
-       size_t period_len;
-};
-
-struct i2s_controller {
-       struct module *owner;
-       unsigned int id;
-       unsigned int class;
-       const struct i2s_algorithm *algo; /* the algorithm to access the bus */
-       void *data;
-       struct mutex bus_lock;
-       struct device dev; /* the controller device */
-       char name[48];
-};
-
 struct ux500_msp_config {
        unsigned int f_inputclk;
        unsigned int rx_clk_sel;
@@ -491,8 +454,6 @@ struct ux500_msp_config {
        unsigned int tx_fsync_sel;
        unsigned int rx_fifo_config;
        unsigned int tx_fifo_config;
-       unsigned int spi_clk_mode;
-       unsigned int spi_burst_mode;
        unsigned int loopback_enable;
        unsigned int tx_data_enable;
        unsigned int default_protdesc;
@@ -502,43 +463,28 @@ struct ux500_msp_config {
        unsigned int direction;
        unsigned int protocol;
        unsigned int frame_freq;
-       unsigned int frame_size;
        enum msp_data_size data_size;
        unsigned int def_elem_len;
        unsigned int iodelay;
-       void (*handler) (void *data);
-       void *tx_callback_data;
-       void *rx_callback_data;
+};
+
+struct ux500_msp_dma_params {
+       unsigned int data_size;
+       dma_addr_t tx_rx_addr;
+       struct stedma40_chan_cfg *dma_cfg;
 };
 
 struct ux500_msp {
-       enum enum_i2s_controller id;
+       enum msp_i2s_id id;
        void __iomem *registers;
        struct device *dev;
-       struct i2s_controller *i2s_cont;
-       struct stedma40_chan_cfg *dma_cfg_rx;
-       struct stedma40_chan_cfg *dma_cfg_tx;
-       struct dma_chan *tx_pipeid;
-       struct dma_chan *rx_pipeid;
+       struct ux500_msp_dma_params playback_dma_data;
+       struct ux500_msp_dma_params capture_dma_data;
        enum msp_state msp_state;
-       int (*transfer) (struct ux500_msp *msp, struct i2s_message *message);
-       struct timer_list notify_timer;
        int def_elem_len;
        unsigned int dir_busy;
        int loopback_enable;
-       u32 backup_regs[MAX_MSP_BACKUP_REGS];
        unsigned int f_bitclk;
-       /* Pin modes */
-       struct pinctrl *pinctrl_p;
-       struct pinctrl_state *pinctrl_def;
-       struct pinctrl_state *pinctrl_sleep;
-       /* Reference Count */
-       int pinctrl_rxtx_ref;
-};
-
-struct ux500_msp_dma_params {
-       unsigned int data_size;
-       struct stedma40_chan_cfg *dma_cfg;
 };
 
 struct msp_i2s_platform_data;
index 31f9bbc745216c6c81d825c07df9ab8f36eb5d91..ce554de5d9dc5a131aa52e9f3d9c1da87b8ddb8c 100644 (file)
@@ -103,10 +103,40 @@ static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
        return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg);
 }
 
+static int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params,
+               struct dma_slave_config *slave_config)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct ux500_msp_dma_params *dma_params;
+       struct stedma40_chan_cfg *dma_cfg;
+       int ret;
+
+       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       dma_cfg = dma_params->dma_cfg;
+
+       ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
+       if (ret)
+               return ret;
+
+       slave_config->dst_maxburst = 4;
+       slave_config->dst_addr_width = dma_cfg->dst_info.data_width;
+       slave_config->src_maxburst = 4;
+       slave_config->src_addr_width = dma_cfg->src_info.data_width;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               slave_config->dst_addr = dma_params->tx_rx_addr;
+       else
+               slave_config->src_addr = dma_params->tx_rx_addr;
+
+       return 0;
+}
+
 static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = {
        .pcm_hardware = &ux500_pcm_hw,
        .compat_request_channel = ux500_pcm_request_chan,
        .prealloc_buffer_size = 128 * 1024,
+       .prepare_slave_config = ux500_pcm_prepare_slave_config,
 };
 
 int ux500_pcm_register_platform(struct platform_device *pdev)
index 359753fc24e161931bb0a95070331aba59c87aff..45759f4cca754488d38f15bcae85b161a85fb4a9 100644 (file)
@@ -292,7 +292,7 @@ retry:
        }
 
        device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
-                     NULL, s->name+6);
+                     NULL, "%s", s->name+6);
        return s->unit_minor;
 
 fail:
index 75e6016d3efe79e0b025115f2f0148a9e3403aa3..eee7afcae37510db454f132c65f01ba5c34f776e 100644 (file)
@@ -2670,8 +2670,6 @@ static int dbri_remove(struct platform_device *op)
        snd_dbri_free(card->private_data);
        snd_card_free(card);
 
-       dev_set_drvdata(&op->dev, NULL);
-
        return 0;
 }
 
index a1a24b979ed2799476e8962cd65908c6ca538c9f..8e3d9a6c7a3ba6e88f6cd29d0894a6c5a69162d7 100644 (file)
@@ -1070,7 +1070,6 @@ out:
 
        ssc_free(chip->ssc);
        snd_card_free(card);
-       dev_set_drvdata(&spi->dev, NULL);
 
        return 0;
 }
index 4394ae796356c2c46cce90e9e5e20707e85de06d..c39c77978468b9270fd117d6d055ecc2e021fdb3 100644 (file)
@@ -30,7 +30,7 @@
 MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>");
 MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}");
+MODULE_SUPPORTED_DEVICE("{{TerraTec,DMX 6Fire USB}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
index 40dd50a80f55de653ffc30c2c4a4960c4d868025..c5b9cac37dc4c205d1cff5128906f853d0ea7a76 100644 (file)
@@ -450,13 +450,13 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub)
 static int usb6fire_pcm_hw_params(struct snd_pcm_substream *alsa_sub,
                struct snd_pcm_hw_params *hw_params)
 {
-       return snd_pcm_lib_malloc_pages(alsa_sub,
-                       params_buffer_bytes(hw_params));
+       return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub,
+                                               params_buffer_bytes(hw_params));
 }
 
 static int usb6fire_pcm_hw_free(struct snd_pcm_substream *alsa_sub)
 {
-       return snd_pcm_lib_free_pages(alsa_sub);
+       return snd_pcm_lib_free_vmalloc_buffer(alsa_sub);
 }
 
 static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
@@ -560,6 +560,8 @@ static struct snd_pcm_ops pcm_ops = {
        .prepare = usb6fire_pcm_prepare,
        .trigger = usb6fire_pcm_trigger,
        .pointer = usb6fire_pcm_pointer,
+       .page = snd_pcm_lib_get_vmalloc_page,
+       .mmap = snd_pcm_lib_mmap_vmalloc,
 };
 
 static void usb6fire_pcm_init_urb(struct pcm_urb *urb,
@@ -622,10 +624,6 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops);
 
-       ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
-                       SNDRV_DMA_TYPE_CONTINUOUS,
-                       snd_dma_continuous_data(GFP_KERNEL),
-                       MAX_BUFSIZE, MAX_BUFSIZE);
        if (ret) {
                kfree(rt);
                snd_printk(KERN_ERR PREFIX
index 225dfd737265411bead537f7f839b75863432e51..de9408b83f7577b22071aac72b1ecf0390522d44 100644 (file)
@@ -115,5 +115,36 @@ config SND_USB_6FIRE
           and further help can be found at
           http://sixfireusb.sourceforge.net
 
+config SND_USB_HIFACE
+        tristate "M2Tech hiFace USB-SPDIF driver"
+        select SND_PCM
+        help
+         Select this option to include support for M2Tech hiFace USB-SPDIF
+         interface.
+
+         This driver supports the original M2Tech hiFace and some other
+         compatible devices. The supported products are:
+
+           * M2Tech Young
+           * M2Tech hiFace
+           * M2Tech North Star
+           * M2Tech W4S Young
+           * M2Tech Corrson
+           * M2Tech AUDIA
+           * M2Tech SL Audio
+           * M2Tech Empirical
+           * M2Tech Rockna
+           * M2Tech Pathos
+           * M2Tech Metronome
+           * M2Tech CAD
+           * M2Tech Audio Esclusive
+           * M2Tech Rotel
+           * M2Tech Eeaudio
+           * The Chord Company CHORD
+           * AVA Group A/S Vitus
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-usb-hiface.
+
 endif  # SND_USB
 
index ac256dc4c6bed1d0b4d4008c58f544f50ec04085..abe668f660d16eb997950a692512f48638d152fb 100644 (file)
@@ -23,4 +23,4 @@ obj-$(CONFIG_SND_USB_UA101) += snd-usbmidi-lib.o
 obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
 obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
 
-obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/
+obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/
index c1916184e2e1e604955b19ba0f9ae23b4788cc2a..7103b0908d130436743bceb6bf422222bd421466 100644 (file)
@@ -183,14 +183,15 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
 static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
                                       struct snd_pcm_hw_params *hw_params)
 {
-       return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
+       return snd_pcm_lib_alloc_vmalloc_buffer(sub,
+                                               params_buffer_bytes(hw_params));
 }
 
 static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
 {
        struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
        deactivate_substream(cdev, sub);
-       return snd_pcm_lib_free_pages(sub);
+       return snd_pcm_lib_free_vmalloc_buffer(sub);
 }
 
 /* this should probably go upstream */
@@ -345,7 +346,9 @@ static struct snd_pcm_ops snd_usb_caiaq_ops = {
        .hw_free =      snd_usb_caiaq_pcm_hw_free,
        .prepare =      snd_usb_caiaq_pcm_prepare,
        .trigger =      snd_usb_caiaq_pcm_trigger,
-       .pointer =      snd_usb_caiaq_pcm_pointer
+       .pointer =      snd_usb_caiaq_pcm_pointer,
+       .page =         snd_pcm_lib_get_vmalloc_page,
+       .mmap =         snd_pcm_lib_mmap_vmalloc,
 };
 
 static void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev,
@@ -852,11 +855,6 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
        snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_CAPTURE,
                                &snd_usb_caiaq_ops);
 
-       snd_pcm_lib_preallocate_pages_for_all(cdev->pcm,
-                                       SNDRV_DMA_TYPE_CONTINUOUS,
-                                       snd_dma_continuous_data(GFP_KERNEL),
-                                       MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
-
        cdev->data_cb_info =
                kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS,
                                        GFP_KERNEL);
index 48b63ccc78c7e9da35aa4e1ba81d3a8e16672c20..1a61dd12fe38a9bb881e462f396e92f43a048e36 100644 (file)
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 MODULE_DESCRIPTION("caiaq USB audio");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
-                        "{Native Instruments, RigKontrol3},"
-                        "{Native Instruments, Kore Controller},"
-                        "{Native Instruments, Kore Controller 2},"
-                        "{Native Instruments, Audio Kontrol 1},"
-                        "{Native Instruments, Audio 2 DJ},"
-                        "{Native Instruments, Audio 4 DJ},"
-                        "{Native Instruments, Audio 8 DJ},"
-                        "{Native Instruments, Traktor Audio 2},"
-                        "{Native Instruments, Session I/O},"
-                        "{Native Instruments, GuitarRig mobile},"
-                        "{Native Instruments, Traktor Kontrol X1},"
-                        "{Native Instruments, Traktor Kontrol S4},"
-                        "{Native Instruments, Maschine Controller}}");
+MODULE_SUPPORTED_DEVICE("{{Native Instruments,RigKontrol2},"
+                        "{Native Instruments,RigKontrol3},"
+                        "{Native Instruments,Kore Controller},"
+                        "{Native Instruments,Kore Controller 2},"
+                        "{Native Instruments,Audio Kontrol 1},"
+                        "{Native Instruments,Audio 2 DJ},"
+                        "{Native Instruments,Audio 4 DJ},"
+                        "{Native Instruments,Audio 8 DJ},"
+                        "{Native Instruments,Traktor Audio 2},"
+                        "{Native Instruments,Session I/O},"
+                        "{Native Instruments,GuitarRig mobile},"
+                        "{Native Instruments,Traktor Kontrol X1},"
+                        "{Native Instruments,Traktor Kontrol S4},"
+                        "{Native Instruments,Maschine Controller}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
-static int snd_card_used[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the caiaq sound device");
@@ -388,7 +387,7 @@ static int create_card(struct usb_device *usb_dev,
        struct snd_usb_caiaqdev *cdev;
 
        for (devnum = 0; devnum < SNDRV_CARDS; devnum++)
-               if (enable[devnum] && !snd_card_used[devnum])
+               if (enable[devnum])
                        break;
 
        if (devnum >= SNDRV_CARDS)
index bf2889a2cae548a1da3022c0c926d0a907b3aa41..5ecacaa90b53fc163c9383b18100bb1ce97f1dfe 100644 (file)
@@ -21,6 +21,7 @@ struct audioformat {
        unsigned char endpoint;         /* endpoint */
        unsigned char ep_attr;          /* endpoint attributes */
        unsigned char datainterval;     /* log_2 of data packet interval */
+       unsigned char protocol;         /* UAC_VERSION_1/2 */
        unsigned int maxpacksize;       /* max. packet size */
        unsigned int rates;             /* rate bitmasks */
        unsigned int rate_min, rate_max;        /* min/max rates */
index 3a2ce390e278afed2e9793d7d7b981965e604462..86f80c60b21f91202c8c17c40d7981c3d7f873f8 100644 (file)
@@ -407,9 +407,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
                             struct usb_host_interface *alts,
                             struct audioformat *fmt, int rate)
 {
-       struct usb_interface_descriptor *altsd = get_iface_desc(alts);
-
-       switch (altsd->bInterfaceProtocol) {
+       switch (fmt->protocol) {
        case UAC_VERSION_1:
        default:
                return set_sample_rate_v1(chip, iface, alts, fmt, rate);
index 99299ffb33ac22597d57b1a11fd2b1e856f154bd..3525231c6b97325dcbb400ae0c7f9e021555ad8b 100644 (file)
  */
 static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
                                     struct audioformat *fp,
-                                    unsigned int format, void *_fmt,
-                                    int protocol)
+                                    unsigned int format, void *_fmt)
 {
        int sample_width, sample_bytes;
        u64 pcm_formats = 0;
 
-       switch (protocol) {
+       switch (fp->protocol) {
        case UAC_VERSION_1:
        default: {
                struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
@@ -360,11 +359,8 @@ err:
  */
 static int parse_audio_format_i(struct snd_usb_audio *chip,
                                struct audioformat *fp, unsigned int format,
-                               struct uac_format_type_i_continuous_descriptor *fmt,
-                               struct usb_host_interface *iface)
+                               struct uac_format_type_i_continuous_descriptor *fmt)
 {
-       struct usb_interface_descriptor *altsd = get_iface_desc(iface);
-       int protocol = altsd->bInterfaceProtocol;
        snd_pcm_format_t pcm_format;
        int ret;
 
@@ -387,8 +383,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
                }
                fp->formats = pcm_format_to_bits(pcm_format);
        } else {
-               fp->formats = parse_audio_format_i_type(chip, fp, format,
-                                                       fmt, protocol);
+               fp->formats = parse_audio_format_i_type(chip, fp, format, fmt);
                if (!fp->formats)
                        return -EINVAL;
        }
@@ -398,11 +393,8 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
         * proprietary class specific descriptor.
         * audio class v2 uses class specific EP0 range requests for that.
         */
-       switch (protocol) {
+       switch (fp->protocol) {
        default:
-               snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
-                          chip->dev->devnum, fp->iface, fp->altsetting, protocol);
-               /* fall through */
        case UAC_VERSION_1:
                fp->channels = fmt->bNrChannels;
                ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
@@ -427,12 +419,9 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
  */
 static int parse_audio_format_ii(struct snd_usb_audio *chip,
                                 struct audioformat *fp,
-                                int format, void *_fmt,
-                                struct usb_host_interface *iface)
+                                int format, void *_fmt)
 {
        int brate, framesize, ret;
-       struct usb_interface_descriptor *altsd = get_iface_desc(iface);
-       int protocol = altsd->bInterfaceProtocol;
 
        switch (format) {
        case UAC_FORMAT_TYPE_II_AC3:
@@ -452,11 +441,8 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
 
        fp->channels = 1;
 
-       switch (protocol) {
+       switch (fp->protocol) {
        default:
-               snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
-                          chip->dev->devnum, fp->iface, fp->altsetting, protocol);
-               /* fall through */
        case UAC_VERSION_1: {
                struct uac_format_type_ii_discrete_descriptor *fmt = _fmt;
                brate = le16_to_cpu(fmt->wMaxBitRate);
@@ -483,17 +469,17 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
 int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
                               struct audioformat *fp, unsigned int format,
                               struct uac_format_type_i_continuous_descriptor *fmt,
-                              int stream, struct usb_host_interface *iface)
+                              int stream)
 {
        int err;
 
        switch (fmt->bFormatType) {
        case UAC_FORMAT_TYPE_I:
        case UAC_FORMAT_TYPE_III:
-               err = parse_audio_format_i(chip, fp, format, fmt, iface);
+               err = parse_audio_format_i(chip, fp, format, fmt);
                break;
        case UAC_FORMAT_TYPE_II:
-               err = parse_audio_format_ii(chip, fp, format, fmt, iface);
+               err = parse_audio_format_ii(chip, fp, format, fmt);
                break;
        default:
                snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
index 6f315226f32042ea95881766d42aedfc26cf9f66..4b8a01129f240361a946f3993be4184077d120e9 100644 (file)
@@ -4,6 +4,6 @@
 int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
                               struct audioformat *fp, unsigned int format,
                               struct uac_format_type_i_continuous_descriptor *fmt,
-                              int stream, struct usb_host_interface *iface);
+                              int stream);
 
 #endif /*  __USBAUDIO_FORMAT_H */
diff --git a/sound/usb/hiface/Makefile b/sound/usb/hiface/Makefile
new file mode 100644 (file)
index 0000000..463b136
--- /dev/null
@@ -0,0 +1,2 @@
+snd-usb-hiface-objs := chip.o pcm.o
+obj-$(CONFIG_SND_USB_HIFACE) += snd-usb-hiface.o
diff --git a/sound/usb/hiface/chip.c b/sound/usb/hiface/chip.c
new file mode 100644 (file)
index 0000000..b0dcb39
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors:  Michael Trimarchi <michael@amarulasolutions.com>
+ *           Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/initval.h>
+
+#include "chip.h"
+#include "pcm.h"
+
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_AUTHOR("Antonio Ospite <ao2@amarulasolutions.com>");
+MODULE_DESCRIPTION("M2Tech hiFace USB-SPDIF audio driver");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{M2Tech,Young},"
+                        "{M2Tech,hiFace},"
+                        "{M2Tech,North Star},"
+                        "{M2Tech,W4S Young},"
+                        "{M2Tech,Corrson},"
+                        "{M2Tech,AUDIA},"
+                        "{M2Tech,SL Audio},"
+                        "{M2Tech,Empirical},"
+                        "{M2Tech,Rockna},"
+                        "{M2Tech,Pathos},"
+                        "{M2Tech,Metronome},"
+                        "{M2Tech,CAD},"
+                        "{M2Tech,Audio Esclusive},"
+                        "{M2Tech,Rotel},"
+                        "{M2Tech,Eeaudio},"
+                        "{The Chord Company,CHORD},"
+                        "{AVA Group A/S,Vitus}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
+
+#define DRIVER_NAME "snd-usb-hiface"
+#define CARD_NAME "hiFace"
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+static DEFINE_MUTEX(register_mutex);
+
+struct hiface_vendor_quirk {
+       const char *device_name;
+       u8 extra_freq;
+};
+
+static int hiface_chip_create(struct usb_device *device, int idx,
+                             const struct hiface_vendor_quirk *quirk,
+                             struct hiface_chip **rchip)
+{
+       struct snd_card *card = NULL;
+       struct hiface_chip *chip;
+       int ret;
+       int len;
+
+       *rchip = NULL;
+
+       /* if we are here, card can be registered in alsa. */
+       ret = snd_card_create(index[idx], id[idx], THIS_MODULE, sizeof(*chip), &card);
+       if (ret < 0) {
+               dev_err(&device->dev, "cannot create alsa card.\n");
+               return ret;
+       }
+
+       strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+
+       if (quirk && quirk->device_name)
+               strlcpy(card->shortname, quirk->device_name, sizeof(card->shortname));
+       else
+               strlcpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
+
+       strlcat(card->longname, card->shortname, sizeof(card->longname));
+       len = strlcat(card->longname, " at ", sizeof(card->longname));
+       if (len < sizeof(card->longname))
+               usb_make_path(device, card->longname + len,
+                             sizeof(card->longname) - len);
+
+       chip = card->private_data;
+       chip->dev = device;
+       chip->card = card;
+
+       *rchip = chip;
+       return 0;
+}
+
+static int hiface_chip_probe(struct usb_interface *intf,
+                            const struct usb_device_id *usb_id)
+{
+       const struct hiface_vendor_quirk *quirk = (struct hiface_vendor_quirk *)usb_id->driver_info;
+       int ret;
+       int i;
+       struct hiface_chip *chip;
+       struct usb_device *device = interface_to_usbdev(intf);
+
+       ret = usb_set_interface(device, 0, 0);
+       if (ret != 0) {
+               dev_err(&device->dev, "can't set first interface for " CARD_NAME " device.\n");
+               return -EIO;
+       }
+
+       /* check whether the card is already registered */
+       chip = NULL;
+       mutex_lock(&register_mutex);
+
+       for (i = 0; i < SNDRV_CARDS; i++)
+               if (enable[i])
+                       break;
+
+       if (i >= SNDRV_CARDS) {
+               dev_err(&device->dev, "no available " CARD_NAME " audio device\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       ret = hiface_chip_create(device, i, quirk, &chip);
+       if (ret < 0)
+               goto err;
+
+       snd_card_set_dev(chip->card, &intf->dev);
+
+       ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0);
+       if (ret < 0)
+               goto err_chip_destroy;
+
+       ret = snd_card_register(chip->card);
+       if (ret < 0) {
+               dev_err(&device->dev, "cannot register " CARD_NAME " card\n");
+               goto err_chip_destroy;
+       }
+
+       mutex_unlock(&register_mutex);
+
+       usb_set_intfdata(intf, chip);
+       return 0;
+
+err_chip_destroy:
+       snd_card_free(chip->card);
+err:
+       mutex_unlock(&register_mutex);
+       return ret;
+}
+
+static void hiface_chip_disconnect(struct usb_interface *intf)
+{
+       struct hiface_chip *chip;
+       struct snd_card *card;
+
+       chip = usb_get_intfdata(intf);
+       if (!chip)
+               return;
+
+       card = chip->card;
+
+       /* Make sure that the userspace cannot create new request */
+       snd_card_disconnect(card);
+
+       hiface_pcm_abort(chip);
+       snd_card_free_when_closed(card);
+}
+
+static const struct usb_device_id device_table[] = {
+       {
+               USB_DEVICE(0x04b4, 0x0384),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Young",
+                       .extra_freq = 1,
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x930b),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "hiFace",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x931b),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "North Star",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x931c),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "W4S Young",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x931d),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Corrson",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x931e),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "AUDIA",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x931f),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "SL Audio",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x9320),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Empirical",
+               }
+       },
+       {
+               USB_DEVICE(0x04b4, 0x9321),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Rockna",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x9001),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Pathos",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x9002),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Metronome",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x9006),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "CAD",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x9008),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Audio Esclusive",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x931c),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Rotel",
+               }
+       },
+       {
+               USB_DEVICE(0x249c, 0x932c),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Eeaudio",
+               }
+       },
+       {
+               USB_DEVICE(0x245f, 0x931c),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "CHORD",
+               }
+       },
+       {
+               USB_DEVICE(0x25c6, 0x9002),
+               .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
+                       .device_name = "Vitus",
+               }
+       },
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+static struct usb_driver hiface_usb_driver = {
+       .name = DRIVER_NAME,
+       .probe = hiface_chip_probe,
+       .disconnect = hiface_chip_disconnect,
+       .id_table = device_table,
+};
+
+module_usb_driver(hiface_usb_driver);
diff --git a/sound/usb/hiface/chip.h b/sound/usb/hiface/chip.h
new file mode 100644 (file)
index 0000000..189a137
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors:  Michael Trimarchi <michael@amarulasolutions.com>
+ *           Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 HIFACE_CHIP_H
+#define HIFACE_CHIP_H
+
+#include <linux/usb.h>
+#include <sound/core.h>
+
+struct pcm_runtime;
+
+struct hiface_chip {
+       struct usb_device *dev;
+       struct snd_card *card;
+       struct pcm_runtime *pcm;
+};
+#endif /* HIFACE_CHIP_H */
diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c
new file mode 100644 (file)
index 0000000..6430ed2
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors:  Michael Trimarchi <michael@amarulasolutions.com>
+ *           Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <sound/pcm.h>
+
+#include "pcm.h"
+#include "chip.h"
+
+#define OUT_EP          0x2
+#define PCM_N_URBS      8
+#define PCM_PACKET_SIZE 4096
+#define PCM_BUFFER_SIZE (2 * PCM_N_URBS * PCM_PACKET_SIZE)
+
+struct pcm_urb {
+       struct hiface_chip *chip;
+
+       struct urb instance;
+       struct usb_anchor submitted;
+       u8 *buffer;
+};
+
+struct pcm_substream {
+       spinlock_t lock;
+       struct snd_pcm_substream *instance;
+
+       bool active;
+       snd_pcm_uframes_t dma_off;    /* current position in alsa dma_area */
+       snd_pcm_uframes_t period_off; /* current position in current period */
+};
+
+enum { /* pcm streaming states */
+       STREAM_DISABLED, /* no pcm streaming */
+       STREAM_STARTING, /* pcm streaming requested, waiting to become ready */
+       STREAM_RUNNING,  /* pcm streaming running */
+       STREAM_STOPPING
+};
+
+struct pcm_runtime {
+       struct hiface_chip *chip;
+       struct snd_pcm *instance;
+
+       struct pcm_substream playback;
+       bool panic; /* if set driver won't do anymore pcm on device */
+
+       struct pcm_urb out_urbs[PCM_N_URBS];
+
+       struct mutex stream_mutex;
+       u8 stream_state; /* one of STREAM_XXX */
+       u8 extra_freq;
+       wait_queue_head_t stream_wait_queue;
+       bool stream_wait_cond;
+};
+
+static const unsigned int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000,
+                                     352800, 384000 };
+static const struct snd_pcm_hw_constraint_list constraints_extra_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static const struct snd_pcm_hardware pcm_hw = {
+       .info = SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_PAUSE |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_BATCH,
+
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+
+       .rates = SNDRV_PCM_RATE_44100 |
+               SNDRV_PCM_RATE_48000 |
+               SNDRV_PCM_RATE_88200 |
+               SNDRV_PCM_RATE_96000 |
+               SNDRV_PCM_RATE_176400 |
+               SNDRV_PCM_RATE_192000,
+
+       .rate_min = 44100,
+       .rate_max = 192000, /* changes in hiface_pcm_open to support extra rates */
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = PCM_BUFFER_SIZE,
+       .period_bytes_min = PCM_PACKET_SIZE,
+       .period_bytes_max = PCM_BUFFER_SIZE,
+       .periods_min = 2,
+       .periods_max = 1024
+};
+
+/* message values used to change the sample rate */
+#define HIFACE_SET_RATE_REQUEST 0xb0
+
+#define HIFACE_RATE_44100  0x43
+#define HIFACE_RATE_48000  0x4b
+#define HIFACE_RATE_88200  0x42
+#define HIFACE_RATE_96000  0x4a
+#define HIFACE_RATE_176400 0x40
+#define HIFACE_RATE_192000 0x48
+#define HIFACE_RATE_352000 0x58
+#define HIFACE_RATE_384000 0x68
+
+static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate)
+{
+       struct usb_device *device = rt->chip->dev;
+       u16 rate_value;
+       int ret;
+
+       /* We are already sure that the rate is supported here thanks to
+        * ALSA constraints
+        */
+       switch (rate) {
+       case 44100:
+               rate_value = HIFACE_RATE_44100;
+               break;
+       case 48000:
+               rate_value = HIFACE_RATE_48000;
+               break;
+       case 88200:
+               rate_value = HIFACE_RATE_88200;
+               break;
+       case 96000:
+               rate_value = HIFACE_RATE_96000;
+               break;
+       case 176400:
+               rate_value = HIFACE_RATE_176400;
+               break;
+       case 192000:
+               rate_value = HIFACE_RATE_192000;
+               break;
+       case 352000:
+               rate_value = HIFACE_RATE_352000;
+               break;
+       case 384000:
+               rate_value = HIFACE_RATE_384000;
+               break;
+       default:
+               dev_err(&device->dev, "Unsupported rate %d\n", rate);
+               return -EINVAL;
+       }
+
+       /*
+        * USBIO: Vendor 0xb0(wValue=0x0043, wIndex=0x0000)
+        * 43 b0 43 00 00 00 00 00
+        * USBIO: Vendor 0xb0(wValue=0x004b, wIndex=0x0000)
+        * 43 b0 4b 00 00 00 00 00
+        * This control message doesn't have any ack from the
+        * other side
+        */
+       ret = usb_control_msg(device, usb_sndctrlpipe(device, 0),
+                             HIFACE_SET_RATE_REQUEST,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                             rate_value, 0, NULL, 0, 100);
+       if (ret < 0) {
+               dev_err(&device->dev, "Error setting samplerate %d.\n", rate);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct pcm_substream *hiface_pcm_get_substream(struct snd_pcm_substream
+                                                     *alsa_sub)
+{
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+       struct device *device = &rt->chip->dev->dev;
+
+       if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return &rt->playback;
+
+       dev_err(device, "Error getting pcm substream slot.\n");
+       return NULL;
+}
+
+/* call with stream_mutex locked */
+static void hiface_pcm_stream_stop(struct pcm_runtime *rt)
+{
+       int i, time;
+
+       if (rt->stream_state != STREAM_DISABLED) {
+               rt->stream_state = STREAM_STOPPING;
+
+               for (i = 0; i < PCM_N_URBS; i++) {
+                       time = usb_wait_anchor_empty_timeout(
+                                       &rt->out_urbs[i].submitted, 100);
+                       if (!time)
+                               usb_kill_anchored_urbs(
+                                       &rt->out_urbs[i].submitted);
+                       usb_kill_urb(&rt->out_urbs[i].instance);
+               }
+
+               rt->stream_state = STREAM_DISABLED;
+       }
+}
+
+/* call with stream_mutex locked */
+static int hiface_pcm_stream_start(struct pcm_runtime *rt)
+{
+       int ret = 0;
+       int i;
+
+       if (rt->stream_state == STREAM_DISABLED) {
+
+               /* reset panic state when starting a new stream */
+               rt->panic = false;
+
+               /* submit our out urbs zero init */
+               rt->stream_state = STREAM_STARTING;
+               for (i = 0; i < PCM_N_URBS; i++) {
+                       memset(rt->out_urbs[i].buffer, 0, PCM_PACKET_SIZE);
+                       usb_anchor_urb(&rt->out_urbs[i].instance,
+                                      &rt->out_urbs[i].submitted);
+                       ret = usb_submit_urb(&rt->out_urbs[i].instance,
+                                            GFP_ATOMIC);
+                       if (ret) {
+                               hiface_pcm_stream_stop(rt);
+                               return ret;
+                       }
+               }
+
+               /* wait for first out urb to return (sent in in urb handler) */
+               wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond,
+                                  HZ);
+               if (rt->stream_wait_cond) {
+                       struct device *device = &rt->chip->dev->dev;
+                       dev_dbg(device, "%s: Stream is running wakeup event\n",
+                                __func__);
+                       rt->stream_state = STREAM_RUNNING;
+               } else {
+                       hiface_pcm_stream_stop(rt);
+                       return -EIO;
+               }
+       }
+       return ret;
+}
+
+/* The hardware wants word-swapped 32-bit values */
+static void memcpy_swahw32(u8 *dest, u8 *src, unsigned int n)
+{
+       unsigned int i;
+
+       for (i = 0; i < n / 4; i++)
+               ((u32 *)dest)[i] = swahw32(((u32 *)src)[i]);
+}
+
+/* call with substream locked */
+/* returns true if a period elapsed */
+static bool hiface_pcm_playback(struct pcm_substream *sub, struct pcm_urb *urb)
+{
+       struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
+       struct device *device = &urb->chip->dev->dev;
+       u8 *source;
+       unsigned int pcm_buffer_size;
+
+       WARN_ON(alsa_rt->format != SNDRV_PCM_FORMAT_S32_LE);
+
+       pcm_buffer_size = snd_pcm_lib_buffer_bytes(sub->instance);
+
+       if (sub->dma_off + PCM_PACKET_SIZE <= pcm_buffer_size) {
+               dev_dbg(device, "%s: (1) buffer_size %#x dma_offset %#x\n", __func__,
+                        (unsigned int) pcm_buffer_size,
+                        (unsigned int) sub->dma_off);
+
+               source = alsa_rt->dma_area + sub->dma_off;
+               memcpy_swahw32(urb->buffer, source, PCM_PACKET_SIZE);
+       } else {
+               /* wrap around at end of ring buffer */
+               unsigned int len;
+
+               dev_dbg(device, "%s: (2) buffer_size %#x dma_offset %#x\n", __func__,
+                        (unsigned int) pcm_buffer_size,
+                        (unsigned int) sub->dma_off);
+
+               len = pcm_buffer_size - sub->dma_off;
+
+               source = alsa_rt->dma_area + sub->dma_off;
+               memcpy_swahw32(urb->buffer, source, len);
+
+               source = alsa_rt->dma_area;
+               memcpy_swahw32(urb->buffer + len, source,
+                              PCM_PACKET_SIZE - len);
+       }
+       sub->dma_off += PCM_PACKET_SIZE;
+       if (sub->dma_off >= pcm_buffer_size)
+               sub->dma_off -= pcm_buffer_size;
+
+       sub->period_off += PCM_PACKET_SIZE;
+       if (sub->period_off >= alsa_rt->period_size) {
+               sub->period_off %= alsa_rt->period_size;
+               return true;
+       }
+       return false;
+}
+
+static void hiface_pcm_out_urb_handler(struct urb *usb_urb)
+{
+       struct pcm_urb *out_urb = usb_urb->context;
+       struct pcm_runtime *rt = out_urb->chip->pcm;
+       struct pcm_substream *sub;
+       bool do_period_elapsed = false;
+       unsigned long flags;
+       int ret;
+
+       if (rt->panic || rt->stream_state == STREAM_STOPPING)
+               return;
+
+       if (unlikely(usb_urb->status == -ENOENT ||      /* unlinked */
+                    usb_urb->status == -ENODEV ||      /* device removed */
+                    usb_urb->status == -ECONNRESET ||  /* unlinked */
+                    usb_urb->status == -ESHUTDOWN)) {  /* device disabled */
+               goto out_fail;
+       }
+
+       if (rt->stream_state == STREAM_STARTING) {
+               rt->stream_wait_cond = true;
+               wake_up(&rt->stream_wait_queue);
+       }
+
+       /* now send our playback data (if a free out urb was found) */
+       sub = &rt->playback;
+       spin_lock_irqsave(&sub->lock, flags);
+       if (sub->active)
+               do_period_elapsed = hiface_pcm_playback(sub, out_urb);
+       else
+               memset(out_urb->buffer, 0, PCM_PACKET_SIZE);
+
+       spin_unlock_irqrestore(&sub->lock, flags);
+
+       if (do_period_elapsed)
+               snd_pcm_period_elapsed(sub->instance);
+
+       ret = usb_submit_urb(&out_urb->instance, GFP_ATOMIC);
+       if (ret < 0)
+               goto out_fail;
+
+       return;
+
+out_fail:
+       rt->panic = true;
+}
+
+static int hiface_pcm_open(struct snd_pcm_substream *alsa_sub)
+{
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+       struct pcm_substream *sub = NULL;
+       struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
+       int ret;
+
+       if (rt->panic)
+               return -EPIPE;
+
+       mutex_lock(&rt->stream_mutex);
+       alsa_rt->hw = pcm_hw;
+
+       if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               sub = &rt->playback;
+
+       if (!sub) {
+               struct device *device = &rt->chip->dev->dev;
+               mutex_unlock(&rt->stream_mutex);
+               dev_err(device, "Invalid stream type\n");
+               return -EINVAL;
+       }
+
+       if (rt->extra_freq) {
+               alsa_rt->hw.rates |= SNDRV_PCM_RATE_KNOT;
+               alsa_rt->hw.rate_max = 384000;
+
+               /* explicit constraints needed as we added SNDRV_PCM_RATE_KNOT */
+               ret = snd_pcm_hw_constraint_list(alsa_sub->runtime, 0,
+                                                SNDRV_PCM_HW_PARAM_RATE,
+                                                &constraints_extra_rates);
+               if (ret < 0) {
+                       mutex_unlock(&rt->stream_mutex);
+                       return ret;
+               }
+       }
+
+       sub->instance = alsa_sub;
+       sub->active = false;
+       mutex_unlock(&rt->stream_mutex);
+       return 0;
+}
+
+static int hiface_pcm_close(struct snd_pcm_substream *alsa_sub)
+{
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+       struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+       unsigned long flags;
+
+       if (rt->panic)
+               return 0;
+
+       mutex_lock(&rt->stream_mutex);
+       if (sub) {
+               hiface_pcm_stream_stop(rt);
+
+               /* deactivate substream */
+               spin_lock_irqsave(&sub->lock, flags);
+               sub->instance = NULL;
+               sub->active = false;
+               spin_unlock_irqrestore(&sub->lock, flags);
+
+       }
+       mutex_unlock(&rt->stream_mutex);
+       return 0;
+}
+
+static int hiface_pcm_hw_params(struct snd_pcm_substream *alsa_sub,
+                               struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_alloc_vmalloc_buffer(alsa_sub,
+                                               params_buffer_bytes(hw_params));
+}
+
+static int hiface_pcm_hw_free(struct snd_pcm_substream *alsa_sub)
+{
+       return snd_pcm_lib_free_vmalloc_buffer(alsa_sub);
+}
+
+static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub)
+{
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+       struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+       struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
+       int ret;
+
+       if (rt->panic)
+               return -EPIPE;
+       if (!sub)
+               return -ENODEV;
+
+       mutex_lock(&rt->stream_mutex);
+
+       sub->dma_off = 0;
+       sub->period_off = 0;
+
+       if (rt->stream_state == STREAM_DISABLED) {
+
+               ret = hiface_pcm_set_rate(rt, alsa_rt->rate);
+               if (ret) {
+                       mutex_unlock(&rt->stream_mutex);
+                       return ret;
+               }
+               ret = hiface_pcm_stream_start(rt);
+               if (ret) {
+                       mutex_unlock(&rt->stream_mutex);
+                       return ret;
+               }
+       }
+       mutex_unlock(&rt->stream_mutex);
+       return 0;
+}
+
+static int hiface_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd)
+{
+       struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+
+       if (rt->panic)
+               return -EPIPE;
+       if (!sub)
+               return -ENODEV;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               spin_lock_irq(&sub->lock);
+               sub->active = true;
+               spin_unlock_irq(&sub->lock);
+               return 0;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock_irq(&sub->lock);
+               sub->active = false;
+               spin_unlock_irq(&sub->lock);
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static snd_pcm_uframes_t hiface_pcm_pointer(struct snd_pcm_substream *alsa_sub)
+{
+       struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub);
+       struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+       unsigned long flags;
+       snd_pcm_uframes_t dma_offset;
+
+       if (rt->panic || !sub)
+               return SNDRV_PCM_STATE_XRUN;
+
+       spin_lock_irqsave(&sub->lock, flags);
+       dma_offset = sub->dma_off;
+       spin_unlock_irqrestore(&sub->lock, flags);
+       return bytes_to_frames(alsa_sub->runtime, dma_offset);
+}
+
+static struct snd_pcm_ops pcm_ops = {
+       .open = hiface_pcm_open,
+       .close = hiface_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = hiface_pcm_hw_params,
+       .hw_free = hiface_pcm_hw_free,
+       .prepare = hiface_pcm_prepare,
+       .trigger = hiface_pcm_trigger,
+       .pointer = hiface_pcm_pointer,
+       .page = snd_pcm_lib_get_vmalloc_page,
+       .mmap = snd_pcm_lib_mmap_vmalloc,
+};
+
+static int hiface_pcm_init_urb(struct pcm_urb *urb,
+                              struct hiface_chip *chip,
+                              unsigned int ep,
+                              void (*handler)(struct urb *))
+{
+       urb->chip = chip;
+       usb_init_urb(&urb->instance);
+
+       urb->buffer = kzalloc(PCM_PACKET_SIZE, GFP_KERNEL);
+       if (!urb->buffer)
+               return -ENOMEM;
+
+       usb_fill_bulk_urb(&urb->instance, chip->dev,
+                         usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer,
+                         PCM_PACKET_SIZE, handler, urb);
+       init_usb_anchor(&urb->submitted);
+
+       return 0;
+}
+
+void hiface_pcm_abort(struct hiface_chip *chip)
+{
+       struct pcm_runtime *rt = chip->pcm;
+
+       if (rt) {
+               rt->panic = true;
+
+               mutex_lock(&rt->stream_mutex);
+               hiface_pcm_stream_stop(rt);
+               mutex_unlock(&rt->stream_mutex);
+       }
+}
+
+static void hiface_pcm_destroy(struct hiface_chip *chip)
+{
+       struct pcm_runtime *rt = chip->pcm;
+       int i;
+
+       for (i = 0; i < PCM_N_URBS; i++)
+               kfree(rt->out_urbs[i].buffer);
+
+       kfree(chip->pcm);
+       chip->pcm = NULL;
+}
+
+static void hiface_pcm_free(struct snd_pcm *pcm)
+{
+       struct pcm_runtime *rt = pcm->private_data;
+
+       if (rt)
+               hiface_pcm_destroy(rt->chip);
+}
+
+int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq)
+{
+       int i;
+       int ret;
+       struct snd_pcm *pcm;
+       struct pcm_runtime *rt;
+
+       rt = kzalloc(sizeof(*rt), GFP_KERNEL);
+       if (!rt)
+               return -ENOMEM;
+
+       rt->chip = chip;
+       rt->stream_state = STREAM_DISABLED;
+       if (extra_freq)
+               rt->extra_freq = 1;
+
+       init_waitqueue_head(&rt->stream_wait_queue);
+       mutex_init(&rt->stream_mutex);
+       spin_lock_init(&rt->playback.lock);
+
+       for (i = 0; i < PCM_N_URBS; i++)
+               hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP,
+                                   hiface_pcm_out_urb_handler);
+
+       ret = snd_pcm_new(chip->card, "USB-SPDIF Audio", 0, 1, 0, &pcm);
+       if (ret < 0) {
+               kfree(rt);
+               dev_err(&chip->dev->dev, "Cannot create pcm instance\n");
+               return ret;
+       }
+
+       pcm->private_data = rt;
+       pcm->private_free = hiface_pcm_free;
+
+       strlcpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name));
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
+
+       rt->instance = pcm;
+
+       chip->pcm = rt;
+       return 0;
+}
diff --git a/sound/usb/hiface/pcm.h b/sound/usb/hiface/pcm.h
new file mode 100644 (file)
index 0000000..77edd7c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Linux driver for M2Tech hiFace compatible devices
+ *
+ * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
+ *
+ * Authors:  Michael Trimarchi <michael@amarulasolutions.com>
+ *           Antonio Ospite <ao2@amarulasolutions.com>
+ *
+ * The driver is based on the work done in TerraTec DMX 6Fire USB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 HIFACE_PCM_H
+#define HIFACE_PCM_H
+
+struct hiface_chip;
+
+int hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq);
+void hiface_pcm_abort(struct hiface_chip *chip);
+#endif /* HIFACE_PCM_H */
index 8e01fa4991c519a07b9f7c8dda22acac1d38cb77..b901f468b67ada579739828b382e165713de324e 100644 (file)
@@ -1575,8 +1575,41 @@ static struct port_info {
        EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"),
        EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"),
        EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"),
+       /* BOSS GT-PRO */
+       CONTROL_PORT(0x0582, 0x0089, 0, "%s Control"),
        /* Edirol UM-3EX */
        CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"),
+       /* Roland VG-99 */
+       CONTROL_PORT(0x0582, 0x00b2, 0, "%s Control"),
+       EXTERNAL_PORT(0x0582, 0x00b2, 1, "%s MIDI"),
+       /* Cakewalk Sonar V-Studio 100 */
+       EXTERNAL_PORT(0x0582, 0x00eb, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x00eb, 1, "%s Control"),
+       /* Roland VB-99 */
+       CONTROL_PORT(0x0582, 0x0102, 0, "%s Control"),
+       EXTERNAL_PORT(0x0582, 0x0102, 1, "%s MIDI"),
+       /* Roland A-PRO */
+       EXTERNAL_PORT(0x0582, 0x010f, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x010f, 1, "%s 1"),
+       CONTROL_PORT(0x0582, 0x010f, 2, "%s 2"),
+       /* Roland SD-50 */
+       ROLAND_SYNTH_PORT(0x0582, 0x0114, 0, "%s Synth", 128),
+       EXTERNAL_PORT(0x0582, 0x0114, 1, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x0114, 2, "%s Control"),
+       /* Roland OCTA-CAPTURE */
+       EXTERNAL_PORT(0x0582, 0x0120, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x0120, 1, "%s Control"),
+       EXTERNAL_PORT(0x0582, 0x0121, 0, "%s MIDI"),
+       CONTROL_PORT(0x0582, 0x0121, 1, "%s Control"),
+       /* Roland SPD-SX */
+       CONTROL_PORT(0x0582, 0x0145, 0, "%s Control"),
+       EXTERNAL_PORT(0x0582, 0x0145, 1, "%s MIDI"),
+       /* Roland A-Series */
+       CONTROL_PORT(0x0582, 0x0156, 0, "%s Keyboard"),
+       EXTERNAL_PORT(0x0582, 0x0156, 1, "%s MIDI"),
+       /* Roland INTEGRA-7 */
+       ROLAND_SYNTH_PORT(0x0582, 0x015b, 0, "%s Synth", 128),
+       CONTROL_PORT(0x0582, 0x015b, 1, "%s Control"),
        /* M-Audio MidiSport 8x8 */
        CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"),
        CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"),
@@ -1947,6 +1980,44 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,
        return snd_usbmidi_detect_endpoints(umidi, endpoint, 1);
 }
 
+/*
+ * Detects the endpoints and ports of Roland devices.
+ */
+static int snd_usbmidi_detect_roland(struct snd_usb_midi* umidi,
+                                    struct snd_usb_midi_endpoint_info* endpoint)
+{
+       struct usb_interface* intf;
+       struct usb_host_interface *hostif;
+       u8* cs_desc;
+
+       intf = umidi->iface;
+       if (!intf)
+               return -ENOENT;
+       hostif = intf->altsetting;
+       /*
+        * Some devices have a descriptor <06 24 F1 02 <inputs> <outputs>>,
+        * some have standard class descriptors, or both kinds, or neither.
+        */
+       for (cs_desc = hostif->extra;
+            cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2;
+            cs_desc += cs_desc[0]) {
+               if (cs_desc[0] >= 6 &&
+                   cs_desc[1] == USB_DT_CS_INTERFACE &&
+                   cs_desc[2] == 0xf1 &&
+                   cs_desc[3] == 0x02) {
+                       endpoint->in_cables  = (1 << cs_desc[4]) - 1;
+                       endpoint->out_cables = (1 << cs_desc[5]) - 1;
+                       return snd_usbmidi_detect_endpoints(umidi, endpoint, 1);
+               } else if (cs_desc[0] >= 7 &&
+                          cs_desc[1] == USB_DT_CS_INTERFACE &&
+                          cs_desc[2] == UAC_HEADER) {
+                       return snd_usbmidi_get_ms_info(umidi, endpoint);
+               }
+       }
+
+       return -ENODEV;
+}
+
 /*
  * Creates the endpoints and their ports for Midiman devices.
  */
@@ -2162,6 +2233,9 @@ int snd_usbmidi_create(struct snd_card *card,
        case QUIRK_MIDI_YAMAHA:
                err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);
                break;
+       case QUIRK_MIDI_ROLAND:
+               err = snd_usbmidi_detect_roland(umidi, &endpoints[0]);
+               break;
        case QUIRK_MIDI_MIDIMAN:
                umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops;
                memcpy(&endpoints[0], quirk->data,
index 6ad617b947321b438d3ae1b1071364109747d379..8b5d2c564e042af16fb6fa15290afb1df7f9b594 100644 (file)
@@ -1349,7 +1349,7 @@ static void ua101_disconnect(struct usb_interface *interface)
        snd_card_disconnect(ua->card);
 
        /* make sure that there are no pending USB requests */
-       __list_for_each(midi, &ua->midi_list)
+       list_for_each(midi, &ua->midi_list)
                snd_usbmidi_disconnect(midi);
        abort_alsa_playback(ua);
        abort_alsa_capture(ua);
index ebe91440a068a8f500901652892d5a3575b68e63..d42a584cf8292d99d349a309f55e2d1724e45898 100644 (file)
@@ -9,6 +9,8 @@
  *         Alan Cox (alan@lxorguk.ukuu.org.uk)
  *         Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
+ *   Audio Advantage Micro II support added by:
+ *         Przemek Rudy (prudy1@o2.pl)
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -30,6 +32,7 @@
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
 
+#include <sound/asoundef.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/hwdep.h>
@@ -1315,6 +1318,211 @@ static struct std_mono_table ebox44_table[] = {
        {}
 };
 
+/* Audio Advantage Micro II findings:
+ *
+ * Mapping spdif AES bits to vendor register.bit:
+ * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00
+ * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01
+ * AES2: [0 0 0 0 0 0 0 0]
+ * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request
+ *                           (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices
+ *
+ * power on values:
+ * r2: 0x10
+ * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set
+ *           just after it to 0xa0, presumably it disables/mutes some analog
+ *           parts when there is no audio.)
+ * r9: 0x28
+ *
+ * Optical transmitter on/off:
+ * vendor register.bit: 9.1
+ * 0 - on (0x28 register value)
+ * 1 - off (0x2a register value)
+ *
+ */
+static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+       return 0;
+}
+
+static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+       int err;
+       struct usb_interface *iface;
+       struct usb_host_interface *alts;
+       unsigned int ep;
+       unsigned char data[3];
+       int rate;
+
+       ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff;
+       ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff;
+       ucontrol->value.iec958.status[2] = 0x00;
+
+       /* use known values for that card: interface#1 altsetting#1 */
+       iface = usb_ifnum_to_if(mixer->chip->dev, 1);
+       alts = &iface->altsetting[1];
+       ep = get_endpoint(alts, 0)->bEndpointAddress;
+
+       err = snd_usb_ctl_msg(mixer->chip->dev,
+                       usb_rcvctrlpipe(mixer->chip->dev, 0),
+                       UAC_GET_CUR,
+                       USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
+                       UAC_EP_CS_ATTR_SAMPLE_RATE << 8,
+                       ep,
+                       data,
+                       sizeof(data));
+       if (err < 0)
+               goto end;
+
+       rate = data[0] | (data[1] << 8) | (data[2] << 16);
+       ucontrol->value.iec958.status[3] = (rate == 48000) ?
+                       IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100;
+
+       err = 0;
+end:
+       return err;
+}
+
+static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+       int err;
+       u8 reg;
+       unsigned long priv_backup = kcontrol->private_value;
+
+       reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) |
+                       (ucontrol->value.iec958.status[0] & 0x0f);
+       err = snd_usb_ctl_msg(mixer->chip->dev,
+                       usb_sndctrlpipe(mixer->chip->dev, 0),
+                       UAC_SET_CUR,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                       reg,
+                       2,
+                       NULL,
+                       0);
+       if (err < 0)
+               goto end;
+
+       kcontrol->private_value &= 0xfffff0f0;
+       kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
+       kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f);
+
+       reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ?
+                       0xa0 : 0x20;
+       reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f;
+       err = snd_usb_ctl_msg(mixer->chip->dev,
+                       usb_sndctrlpipe(mixer->chip->dev, 0),
+                       UAC_SET_CUR,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                       reg,
+                       3,
+                       NULL,
+                       0);
+       if (err < 0)
+               goto end;
+
+       kcontrol->private_value &= 0xffff0fff;
+       kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;
+
+       /* The frequency bits in AES3 cannot be set via register access. */
+
+       /* Silently ignore any bits from the request that cannot be set. */
+
+       err = (priv_backup != kcontrol->private_value);
+end:
+       return err;
+}
+
+static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.iec958.status[0] = 0x0f;
+       ucontrol->value.iec958.status[1] = 0xff;
+       ucontrol->value.iec958.status[2] = 0x00;
+       ucontrol->value.iec958.status[3] = 0x00;
+
+       return 0;
+}
+
+static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02);
+
+       return 0;
+}
+
+static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+       int err;
+       u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
+
+       err = snd_usb_ctl_msg(mixer->chip->dev,
+                       usb_sndctrlpipe(mixer->chip->dev, 0),
+                       UAC_SET_CUR,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                       reg,
+                       9,
+                       NULL,
+                       0);
+
+       if (!err) {
+               err = (reg != (kcontrol->private_value & 0x0ff));
+               if (err)
+                       kcontrol->private_value = reg;
+       }
+
+       return err;
+}
+
+static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
+       {
+               .iface =    SNDRV_CTL_ELEM_IFACE_PCM,
+               .name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+               .info =     snd_microii_spdif_info,
+               .get =      snd_microii_spdif_default_get,
+               .put =      snd_microii_spdif_default_put,
+               .private_value = 0x00000100UL,/* reset value */
+       },
+       {
+               .access =   SNDRV_CTL_ELEM_ACCESS_READ,
+               .iface =    SNDRV_CTL_ELEM_IFACE_PCM,
+               .name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+               .info =     snd_microii_spdif_info,
+               .get =      snd_microii_spdif_mask_get,
+       },
+       {
+               .iface =    SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
+               .info =     snd_ctl_boolean_mono_info,
+               .get =      snd_microii_spdif_switch_get,
+               .put =      snd_microii_spdif_switch_put,
+               .private_value = 0x00000028UL,/* reset value */
+       }
+};
+
+static int snd_microii_controls_create(struct usb_mixer_interface *mixer)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) {
+               err = snd_ctl_add(mixer->chip->card,
+                       snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer));
+               if (err < 0)
+                       return err;
+       }
+
+       return err;
+}
+
 int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 {
        int err = 0;
@@ -1353,6 +1561,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
                err = snd_xonar_u1_controls_create(mixer);
                break;
 
+       case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */
+               err = snd_microii_controls_create(mixer);
+               break;
+
        case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
                err = snd_nativeinstruments_create_mixer(mixer,
                                snd_nativeinstruments_ta6_mixers,
index 93b6e32cfeadbdec4e55aff381b8dc60738fca4a..15b151ed4899c6032704d361b9c641d2b53b849f 100644 (file)
@@ -202,13 +202,11 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
                       struct usb_host_interface *alts,
                       struct audioformat *fmt)
 {
-       struct usb_interface_descriptor *altsd = get_iface_desc(alts);
-
        /* if endpoint doesn't have pitch control, bail out */
        if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
                return 0;
 
-       switch (altsd->bInterfaceProtocol) {
+       switch (fmt->protocol) {
        case UAC_VERSION_1:
        default:
                return init_pitch_v1(chip, iface, alts, fmt);
@@ -300,6 +298,35 @@ static int deactivate_endpoints(struct snd_usb_substream *subs)
        return 0;
 }
 
+static int search_roland_implicit_fb(struct usb_device *dev, int ifnum,
+                                    unsigned int altsetting,
+                                    struct usb_host_interface **alts,
+                                    unsigned int *ep)
+{
+       struct usb_interface *iface;
+       struct usb_interface_descriptor *altsd;
+       struct usb_endpoint_descriptor *epd;
+
+       iface = usb_ifnum_to_if(dev, ifnum);
+       if (!iface || iface->num_altsetting < altsetting + 1)
+               return -ENOENT;
+       *alts = &iface->altsetting[altsetting];
+       altsd = get_iface_desc(*alts);
+       if (altsd->bAlternateSetting != altsetting ||
+           altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
+           (altsd->bInterfaceSubClass != 2 &&
+            altsd->bInterfaceProtocol != 2   ) ||
+           altsd->bNumEndpoints < 1)
+               return -ENOENT;
+       epd = get_endpoint(*alts, 0);
+       if (!usb_endpoint_is_isoc_in(epd) ||
+           (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
+                                       USB_ENDPOINT_USAGE_IMPLICIT_FB)
+               return -ENOENT;
+       *ep = epd->bEndpointAddress;
+       return 0;
+}
+
 /*
  * find a matching format and set up the interface
  */
@@ -395,6 +422,18 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
                        goto add_sync_ep;
                }
        }
+       if (is_playback &&
+           attr == USB_ENDPOINT_SYNC_ASYNC &&
+           altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
+           altsd->bInterfaceProtocol == 2 &&
+           altsd->bNumEndpoints == 1 &&
+           USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ &&
+           search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1,
+                                     altsd->bAlternateSetting,
+                                     &alts, &ep) >= 0) {
+               implicit_fb = 1;
+               goto add_sync_ep;
+       }
 
        if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
             (!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
index 8b75bcf136f6d17e91053f93820ae3b7042da027..f5f0595ef9c7a36bfef2d5c48c425a61e9dd796d 100644 (file)
@@ -461,6 +461,17 @@ YAMAHA_DEVICE(0x7000, "DTX"),
 YAMAHA_DEVICE(0x7010, "UB99"),
 #undef YAMAHA_DEVICE
 #undef YAMAHA_INTERFACE
+/* this catches most recent vendor-specific Yamaha devices */
+{
+       .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+                      USB_DEVICE_ID_MATCH_INT_CLASS,
+       .idVendor = 0x0499,
+       .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_AUTODETECT
+       }
+},
 
 /*
  * Roland/RolandED/Edirol/BOSS devices
@@ -1136,7 +1147,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-       /* TODO: add Roland M-1000 support */
 {
        /*
         * Has ID 0x0038 when not in "Advanced Driver" mode;
@@ -1251,7 +1261,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-       /* TODO: add Edirol M-100FX support */
 {
        /* has ID 0x004e when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x004c),
@@ -1370,20 +1379,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-{
-       /* has ID 0x006b when not in "Advanced Driver" mode */
-       USB_DEVICE_VENDOR_SPEC(0x0582, 0x006a),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "SP-606",
-               .ifnum = 3,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x0001,
-                       .in_cables  = 0x0001
-               }
-       }
-},
 {
        /* has ID 0x006e when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x006d),
@@ -1471,8 +1466,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-       /* TODO: add Roland V-SYNTH XT support */
-       /* TODO: add BOSS GT-PRO support */
 {
        /* has ID 0x008c when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x008b),
@@ -1486,42 +1479,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                        .in_cables  = 0x0001
                }
        }
-},
-       /* TODO: add Edirol PC-80 support */
-{
-       USB_DEVICE(0x0582, 0x0096),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "EDIROL",
-               .product_name = "UA-1EX",
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       USB_DEVICE(0x0582, 0x009a),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "EDIROL",
-               .product_name = "UM-3EX",
-               .ifnum = 0,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x000f,
-                       .in_cables  = 0x000f
-               }
-       }
 },
 {
        /*
@@ -1552,125 +1509,9 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                        }
                }
        }
-},
-       /* TODO: add Edirol MD-P1 support */
-{
-       USB_DEVICE(0x582, 0x00a6),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "Juno-G",
-               .ifnum = 0,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x0001,
-                       .in_cables  = 0x0001
-               }
-       }
-},
-{
-       /* Roland SH-201 */
-       USB_DEVICE(0x0582, 0x00ad),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "SH-201",
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       /* Advanced mode of the Roland VG-99, with MIDI and 24-bit PCM at 44.1
-        * kHz. In standard mode, the device has ID 0582:00b3, and offers
-        * 16-bit PCM at 44.1 kHz with no MIDI.
-        */
-       USB_DEVICE(0x0582, 0x00b2),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "VG-99",
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0003,
-                                       .in_cables  = 0x0003
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       /* Roland SonicCell */
-       USB_DEVICE(0x0582, 0x00c2),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "SonicCell",
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
 },
 {
        /* Edirol M-16DX */
-       /* FIXME: This quirk gives a good-working capture stream but the
-        *        playback seems problematic because of lacking of sync
-        *        with capture stream.  It needs to sync with the capture
-        *        clock.  As now, you'll get frequent sound distortions
-        *        via the playback.
-        */
        USB_DEVICE(0x0582, 0x00c4),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                .ifnum = QUIRK_ANY_INTERFACE,
@@ -1698,35 +1539,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-{
-       /* BOSS GT-10 */
-       USB_DEVICE(0x0582, 0x00da),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
 {
        /* Advanced modes of the Edirol UA-25EX.
         * For the standard mode, UA-25EX has ID 0582:00e7, which
@@ -1757,42 +1569,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
-{
-       /* has ID 0x00ea when not in Advanced Driver mode */
-       USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "Roland", */
-               /* .product_name = "UA-1G", */
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       USB_DEVICE_VENDOR_SPEC(0x0582, 0x0104),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "Roland", */
-               /* .product_name = "UM-1G", */
-               .ifnum = 0,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x0001,
-                       .in_cables  = 0x0001
-               }
-       }
-},
 {
        /* Edirol UM-3G */
        USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108),
@@ -1806,92 +1582,49 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 {
-       /* Boss JS-8 Jam Station  */
-       USB_DEVICE(0x0582, 0x0109),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "BOSS", */
-               /* .product_name = "JS-8", */
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       /* has ID 0x0110 when not in Advanced Driver mode */
-       USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f),
+       /* only 44.1 kHz works at the moment */
+       USB_DEVICE(0x0582, 0x0120),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                /* .vendor_name = "Roland", */
-               /* .product_name = "A-PRO", */
-               .ifnum = 0,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x0003,
-                       .in_cables  = 0x0007
-               }
-       }
-},
-{
-       /* Roland GAIA SH-01 */
-       USB_DEVICE(0x0582, 0x0111),
-       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
-               .vendor_name = "Roland",
-               .product_name = "GAIA",
+               /* .product_name = "OCTO-CAPTURE", */
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
                .data = (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = &(const struct snd_usb_midi_endpoint_info) {
-                               .out_cables = 0x0003,
-                               .in_cables  = 0x0003
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 10,
+                                       .iface = 0,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x05,
+                                       .ep_attr = 0x05,
+                                       .rates = SNDRV_PCM_RATE_44100,
+                                       .rate_min = 44100,
+                                       .rate_max = 44100,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 44100 }
                                }
                        },
-                       {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       USB_DEVICE(0x0582, 0x0113),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "BOSS", */
-               /* .product_name = "ME-25", */
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
                        {
                                .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 12,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x85,
+                                       .ep_attr = 0x25,
+                                       .rates = SNDRV_PCM_RATE_44100,
+                                       .rate_min = 44100,
+                                       .rate_max = 44100,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
                        },
                        {
                                .ifnum = 2,
@@ -1902,30 +1635,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                }
                        },
                        {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       USB_DEVICE(0x0582, 0x0127),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "Roland", */
-               /* .product_name = "GR-55", */
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .ifnum = 3,
+                               .type = QUIRK_IGNORE_INTERFACE
                        },
                        {
-                               .ifnum = 2,
-                               .type = QUIRK_MIDI_STANDARD_INTERFACE
+                               .ifnum = 4,
+                               .type = QUIRK_IGNORE_INTERFACE
                        },
                        {
                                .ifnum = -1
@@ -1934,34 +1649,49 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 {
-       /* Added support for Roland UM-ONE which differs from UM-1 */
-       USB_DEVICE(0x0582, 0x012a),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "ROLAND", */
-               /* .product_name = "UM-ONE", */
-               .ifnum = 0,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const struct snd_usb_midi_endpoint_info) {
-                       .out_cables = 0x0001,
-                       .in_cables  = 0x0003
-               }
-       }
-},
-{
-       USB_DEVICE(0x0582, 0x011e),
+       /* only 44.1 kHz works at the moment */
+       USB_DEVICE(0x0582, 0x012f),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "BOSS", */
-               /* .product_name = "BR-800", */
+               /* .vendor_name = "Roland", */
+               /* .product_name = "QUAD-CAPTURE", */
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
                .data = (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 0,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 4,
+                                       .iface = 0,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x05,
+                                       .ep_attr = 0x05,
+                                       .rates = SNDRV_PCM_RATE_44100,
+                                       .rate_min = 44100,
+                                       .rate_max = 44100,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
                        },
                        {
                                .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 6,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x85,
+                                       .ep_attr = 0x25,
+                                       .rates = SNDRV_PCM_RATE_44100,
+                                       .rate_min = 44100,
+                                       .rate_max = 44100,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 44100 }
+                               }
                        },
                        {
                                .ifnum = 2,
@@ -1972,38 +1702,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                }
                        },
                        {
-                               .ifnum = -1
-                       }
-               }
-       }
-},
-{
-       USB_DEVICE(0x0582, 0x0130),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "BOSS", */
-               /* .product_name = "MICRO BR-80", */
-               .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 0,
+                               .ifnum = 3,
                                .type = QUIRK_IGNORE_INTERFACE
                        },
                        {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 3,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
+                               .ifnum = 4,
+                               .type = QUIRK_IGNORE_INTERFACE
                        },
                        {
                                .ifnum = -1
@@ -2011,34 +1715,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+/* this catches most recent vendor-specific Roland devices */
 {
-       USB_DEVICE(0x0582, 0x014d),
-       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               /* .vendor_name = "BOSS", */
-               /* .product_name = "GT-100", */
+       .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+                      USB_DEVICE_ID_MATCH_INT_CLASS,
+       .idVendor = 0x0582,
+       .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
                .ifnum = QUIRK_ANY_INTERFACE,
-               .type = QUIRK_COMPOSITE,
-               .data = (const struct snd_usb_audio_quirk[]) {
-                       {
-                               .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 2,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
-                       },
-                       {
-                               .ifnum = 3,
-                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-                               .data = & (const struct snd_usb_midi_endpoint_info) {
-                                       .out_cables = 0x0001,
-                                       .in_cables  = 0x0001
-                               }
-                       },
-                       {
-                               .ifnum = -1
-                       }
-               }
+               .type = QUIRK_AUTODETECT
        }
 },
 
@@ -3434,4 +3119,16 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+{
+       /*
+        * The original product_name is "USB Sound Device", however this name
+        * is also used by the CM106 based cards, so make it unique.
+        */
+       USB_DEVICE(0x0d8c, 0x0103),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .product_name = "Audio Advantage MicroII",
+               .ifnum = QUIRK_NO_INTERFACE
+       }
+},
+
 #undef USB_DEVICE_VENDOR_SPEC
index 3879eae7e8742f749710da7d795d66f0f473c6fa..5b01330b84529bfe9ebcdf43804e892982a830ab 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
+#include <linux/usb/midi.h>
 
 #include <sound/control.h>
 #include <sound/core.h>
@@ -175,6 +176,212 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
        return 0;
 }
 
+static int create_auto_pcm_quirk(struct snd_usb_audio *chip,
+                                struct usb_interface *iface,
+                                struct usb_driver *driver)
+{
+       struct usb_host_interface *alts;
+       struct usb_interface_descriptor *altsd;
+       struct usb_endpoint_descriptor *epd;
+       struct uac1_as_header_descriptor *ashd;
+       struct uac_format_type_i_discrete_descriptor *fmtd;
+
+       /*
+        * Most Roland/Yamaha audio streaming interfaces have more or less
+        * standard descriptors, but older devices might lack descriptors, and
+        * future ones might change, so ensure that we fail silently if the
+        * interface doesn't look exactly right.
+        */
+
+       /* must have a non-zero altsetting for streaming */
+       if (iface->num_altsetting < 2)
+               return -ENODEV;
+       alts = &iface->altsetting[1];
+       altsd = get_iface_desc(alts);
+
+       /* must have an isochronous endpoint for streaming */
+       if (altsd->bNumEndpoints < 1)
+               return -ENODEV;
+       epd = get_endpoint(alts, 0);
+       if (!usb_endpoint_xfer_isoc(epd))
+               return -ENODEV;
+
+       /* must have format descriptors */
+       ashd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
+                                      UAC_AS_GENERAL);
+       fmtd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
+                                      UAC_FORMAT_TYPE);
+       if (!ashd || ashd->bLength < 7 ||
+           !fmtd || fmtd->bLength < 8)
+               return -ENODEV;
+
+       return create_standard_audio_quirk(chip, iface, driver, NULL);
+}
+
+static int create_yamaha_midi_quirk(struct snd_usb_audio *chip,
+                                   struct usb_interface *iface,
+                                   struct usb_driver *driver,
+                                   struct usb_host_interface *alts)
+{
+       static const struct snd_usb_audio_quirk yamaha_midi_quirk = {
+               .type = QUIRK_MIDI_YAMAHA
+       };
+       struct usb_midi_in_jack_descriptor *injd;
+       struct usb_midi_out_jack_descriptor *outjd;
+
+       /* must have some valid jack descriptors */
+       injd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
+                                      NULL, USB_MS_MIDI_IN_JACK);
+       outjd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
+                                       NULL, USB_MS_MIDI_OUT_JACK);
+       if (!injd && !outjd)
+               return -ENODEV;
+       if (injd && (injd->bLength < 5 ||
+                    (injd->bJackType != USB_MS_EMBEDDED &&
+                     injd->bJackType != USB_MS_EXTERNAL)))
+               return -ENODEV;
+       if (outjd && (outjd->bLength < 6 ||
+                     (outjd->bJackType != USB_MS_EMBEDDED &&
+                      outjd->bJackType != USB_MS_EXTERNAL)))
+               return -ENODEV;
+       return create_any_midi_quirk(chip, iface, driver, &yamaha_midi_quirk);
+}
+
+static int create_roland_midi_quirk(struct snd_usb_audio *chip,
+                                   struct usb_interface *iface,
+                                   struct usb_driver *driver,
+                                   struct usb_host_interface *alts)
+{
+       static const struct snd_usb_audio_quirk roland_midi_quirk = {
+               .type = QUIRK_MIDI_ROLAND
+       };
+       u8 *roland_desc = NULL;
+
+       /* might have a vendor-specific descriptor <06 24 F1 02 ...> */
+       for (;;) {
+               roland_desc = snd_usb_find_csint_desc(alts->extra,
+                                                     alts->extralen,
+                                                     roland_desc, 0xf1);
+               if (!roland_desc)
+                       return -ENODEV;
+               if (roland_desc[0] < 6 || roland_desc[3] != 2)
+                       continue;
+               return create_any_midi_quirk(chip, iface, driver,
+                                            &roland_midi_quirk);
+       }
+}
+
+static int create_std_midi_quirk(struct snd_usb_audio *chip,
+                                struct usb_interface *iface,
+                                struct usb_driver *driver,
+                                struct usb_host_interface *alts)
+{
+       struct usb_ms_header_descriptor *mshd;
+       struct usb_ms_endpoint_descriptor *msepd;
+
+       /* must have the MIDIStreaming interface header descriptor*/
+       mshd = (struct usb_ms_header_descriptor *)alts->extra;
+       if (alts->extralen < 7 ||
+           mshd->bLength < 7 ||
+           mshd->bDescriptorType != USB_DT_CS_INTERFACE ||
+           mshd->bDescriptorSubtype != USB_MS_HEADER)
+               return -ENODEV;
+       /* must have the MIDIStreaming endpoint descriptor*/
+       msepd = (struct usb_ms_endpoint_descriptor *)alts->endpoint[0].extra;
+       if (alts->endpoint[0].extralen < 4 ||
+           msepd->bLength < 4 ||
+           msepd->bDescriptorType != USB_DT_CS_ENDPOINT ||
+           msepd->bDescriptorSubtype != UAC_MS_GENERAL ||
+           msepd->bNumEmbMIDIJack < 1 ||
+           msepd->bNumEmbMIDIJack > 16)
+               return -ENODEV;
+
+       return create_any_midi_quirk(chip, iface, driver, NULL);
+}
+
+static int create_auto_midi_quirk(struct snd_usb_audio *chip,
+                                 struct usb_interface *iface,
+                                 struct usb_driver *driver)
+{
+       struct usb_host_interface *alts;
+       struct usb_interface_descriptor *altsd;
+       struct usb_endpoint_descriptor *epd;
+       int err;
+
+       alts = &iface->altsetting[0];
+       altsd = get_iface_desc(alts);
+
+       /* must have at least one bulk/interrupt endpoint for streaming */
+       if (altsd->bNumEndpoints < 1)
+               return -ENODEV;
+       epd = get_endpoint(alts, 0);
+       if (!usb_endpoint_xfer_bulk(epd) ||
+           !usb_endpoint_xfer_int(epd))
+               return -ENODEV;
+
+       switch (USB_ID_VENDOR(chip->usb_id)) {
+       case 0x0499: /* Yamaha */
+               err = create_yamaha_midi_quirk(chip, iface, driver, alts);
+               if (err < 0 && err != -ENODEV)
+                       return err;
+               break;
+       case 0x0582: /* Roland */
+               err = create_roland_midi_quirk(chip, iface, driver, alts);
+               if (err < 0 && err != -ENODEV)
+                       return err;
+               break;
+       }
+
+       return create_std_midi_quirk(chip, iface, driver, alts);
+}
+
+static int create_autodetect_quirk(struct snd_usb_audio *chip,
+                                  struct usb_interface *iface,
+                                  struct usb_driver *driver)
+{
+       int err;
+
+       err = create_auto_pcm_quirk(chip, iface, driver);
+       if (err == -ENODEV)
+               err = create_auto_midi_quirk(chip, iface, driver);
+       return err;
+}
+
+static int create_autodetect_quirks(struct snd_usb_audio *chip,
+                                   struct usb_interface *iface,
+                                   struct usb_driver *driver,
+                                   const struct snd_usb_audio_quirk *quirk)
+{
+       int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
+       int ifcount, ifnum, err;
+
+       err = create_autodetect_quirk(chip, iface, driver);
+       if (err < 0)
+               return err;
+
+       /*
+        * ALSA PCM playback/capture devices cannot be registered in two steps,
+        * so we have to claim the other corresponding interface here.
+        */
+       ifcount = chip->dev->actconfig->desc.bNumInterfaces;
+       for (ifnum = 0; ifnum < ifcount; ifnum++) {
+               if (ifnum == probed_ifnum || quirk->ifnum >= 0)
+                       continue;
+               iface = usb_ifnum_to_if(chip->dev, ifnum);
+               if (!iface ||
+                   usb_interface_claimed(iface) ||
+                   get_iface_desc(iface->altsetting)->bInterfaceClass !=
+                                                       USB_CLASS_VENDOR_SPEC)
+                       continue;
+
+               err = create_autodetect_quirk(chip, iface, driver);
+               if (err >= 0)
+                       usb_driver_claim_interface(driver, iface, (void *)-1L);
+       }
+
+       return 0;
+}
+
 /*
  * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.  
  * The only way to detect the sample rate is by looking at wMaxPacketSize.
@@ -303,9 +510,11 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
        static const quirk_func_t quirk_funcs[] = {
                [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
                [QUIRK_COMPOSITE] = create_composite_quirk,
+               [QUIRK_AUTODETECT] = create_autodetect_quirks,
                [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
                [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
                [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
+               [QUIRK_MIDI_ROLAND] = create_any_midi_quirk,
                [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
                [QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
                [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
index 7db2f8958e7942e223f3b48f8df2a922cfde1258..c4339f97226bddea9db02c578e6fb5774d1d5a0c 100644 (file)
@@ -493,10 +493,10 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                altsd = get_iface_desc(alts);
                protocol = altsd->bInterfaceProtocol;
                /* skip invalid one */
-               if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
+               if (((altsd->bInterfaceClass != USB_CLASS_AUDIO ||
+                     (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
+                      altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC)) &&
                     altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
-                   (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
-                    altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
                    altsd->bNumEndpoints < 1 ||
                    le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0)
                        continue;
@@ -512,6 +512,15 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
                        continue;
 
+               /*
+                * Roland audio streaming interfaces are marked with protocols
+                * 0/1/2, but are UAC 1 compatible.
+                */
+               if (USB_ID_VENDOR(chip->usb_id) == 0x0582 &&
+                   altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
+                   protocol <= 2)
+                       protocol = UAC_VERSION_1;
+
                chconfig = 0;
                /* get audio formats */
                switch (protocol) {
@@ -635,6 +644,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
                fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
                fp->datainterval = snd_usb_parse_datainterval(chip, alts);
+               fp->protocol = protocol;
                fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
                fp->channels = num_channels;
                if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
@@ -676,7 +686,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
                }
 
                /* ok, let's parse further... */
-               if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) {
+               if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream) < 0) {
                        kfree(fp->rate_table);
                        kfree(fp->chmap);
                        kfree(fp);
index bc43bcaddf4d5ade6c4c32794c324c565b7ab7ff..caabe9b3af49250460d9a3b7e44e5896fea64c9a 100644 (file)
@@ -72,9 +72,11 @@ struct snd_usb_audio {
 enum quirk_type {
        QUIRK_IGNORE_INTERFACE,
        QUIRK_COMPOSITE,
+       QUIRK_AUTODETECT,
        QUIRK_MIDI_STANDARD_INTERFACE,
        QUIRK_MIDI_FIXED_ENDPOINT,
        QUIRK_MIDI_YAMAHA,
+       QUIRK_MIDI_ROLAND,
        QUIRK_MIDI_MIDIMAN,
        QUIRK_MIDI_NOVATION,
        QUIRK_MIDI_RAW_BYTES,
index 9af7c1f17413a3cfb4910c56cce7c6a5cc880864..1f9bbd55553fc79bd539b8ad17f369be5beed267 100644 (file)
 MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
 MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007) }}");
+MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604),"NAME_ALLCAPS"(0x8001)(0x8005)(0x8007)}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
index b37653247ef4e035b096153253b69ca0fd1e9a8b..4967fe9c938df0079a4f5d63881b15b627673094 100644 (file)
@@ -695,9 +695,6 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate)
                        ((char*)(usbdata + i))[1] = ra[i].c2;
                        usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4),
                                          usbdata + i, 2, i_usX2Y_04Int, usX2Y);
-#ifdef OLD_USB
-                       us->urb[i]->transfer_flags = USB_QUEUE_BULK;
-#endif
                }
                us->submitted = 0;
                us->len =       NOOF_SETRATE_URBS;
index 926cbf3efc7f68132d7356cee5a6d5f48ea20cf8..2c5a19733357cd31654fdcf2bc9f0451c1c7be87 100644 (file)
@@ -1,5 +1,8 @@
 include ../../scripts/Makefile.include
 
+CC = $(CROSS_COMPILE)gcc
+AR = $(CROSS_COMPILE)ar
+
 # guard against environment variables
 LIB_H=
 LIB_OBJS=
index fae174dc7d01ebc9ab5e30e484a1f86154069b29..5032a142853ec40d4d4b95e17ec6bf15675e9d76 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 This command runs runs perf-buildid-list --with-hits, and collects the files
-with the buildids found so that analisys of perf.data contents can be possible
+with the buildids found so that analysis of perf.data contents can be possible
 on another machine.
 
 
index 7d5f4f38aa52a2b36b006cb2ed403f4ff704532e..66dab7410c1d352f3583f541de5d1160cffa9085 100644 (file)
@@ -210,6 +210,10 @@ OPTIONS
        Demangle symbol names to human readable form. It's enabled by default,
        disable with --no-demangle.
 
+--percent-limit::
+       Do not show entries which have an overhead under that percent.
+       (Default: 0).
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-annotate[1]
index 9f1a2fe5475794297027126d80d46f277fb05ee0..7fdd1909e37601c7bfeb074800433bec3e8aa4ca 100644 (file)
@@ -155,6 +155,10 @@ Default is to monitor all CPUS.
 
        Default: fractal,0.5,callee.
 
+--percent-limit::
+       Do not show entries which have an overhead under that percent.
+       (Default: 0).
+
 INTERACTIVE PROMPTING KEYS
 --------------------------
 
index b0f164b133d9bd2b749290851a5d3bddf4a86688..203cb0eecff2baf1419cdd7339d424cef92df505 100644 (file)
@@ -51,189 +51,63 @@ include config/utilities.mak
 # Define NO_BACKTRACE if you do not want stack backtrace debug feature
 #
 # Define NO_LIBNUMA if you do not want numa perf benchmark
+#
+# Define NO_LIBAUDIT if you do not want libaudit support
+#
+# Define NO_LIBBIONIC if you do not want bionic support
 
-$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
-       @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
-
-uname_M := $(shell uname -m 2>/dev/null || echo not)
-
-ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
-                                 -e s/arm.*/arm/ -e s/sa110/arm/ \
-                                 -e s/s390x/s390/ -e s/parisc64/parisc/ \
-                                 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-                                 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
-NO_PERF_REGS := 1
-
-CC = $(CROSS_COMPILE)gcc
-AR = $(CROSS_COMPILE)ar
-
-# Additional ARCH settings for x86
-ifeq ($(ARCH),i386)
-       override ARCH := x86
-       NO_PERF_REGS := 0
-       LIBUNWIND_LIBS = -lunwind -lunwind-x86
-endif
-ifeq ($(ARCH),x86_64)
-       override ARCH := x86
-       IS_X86_64 := 0
-       ifeq (, $(findstring m32,$(EXTRA_CFLAGS)))
-               IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
-       endif
-       ifeq (${IS_X86_64}, 1)
-               RAW_ARCH := x86_64
-               ARCH_CFLAGS := -DARCH_X86_64
-               ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
-       endif
-       NO_PERF_REGS := 0
-       LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
-endif
-
-# Treat warnings as errors unless directed not to
-ifneq ($(WERROR),0)
-       CFLAGS_WERROR := -Werror
-endif
-
-ifeq ("$(origin DEBUG)", "command line")
-  PERF_DEBUG = $(DEBUG)
-endif
-ifndef PERF_DEBUG
-  CFLAGS_OPTIMIZE = -O6
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
 endif
 
-ifdef PARSER_DEBUG
-       PARSER_DEBUG_BISON  := -t
-       PARSER_DEBUG_FLEX   := -d
-       PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
+ifneq ($(objtree),)
+#$(info Determined 'objtree' to be $(objtree))
 endif
 
-ifdef NO_NEWT
-       NO_SLANG=1
+ifneq ($(OUTPUT),)
+#$(info Determined 'OUTPUT' to be $(OUTPUT))
 endif
 
-CFLAGS = -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
-EXTLIBS = -lpthread -lrt -lelf -lm
-ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
-ALL_LDFLAGS = $(LDFLAGS)
-STRIP ?= strip
-
-# Among the variables below, these:
-#   perfexecdir
-#   template_dir
-#   mandir
-#   infodir
-#   htmldir
-#   ETC_PERFCONFIG (but not sysconfdir)
-# can be specified as a relative path some/where/else;
-# this is interpreted as relative to $(prefix) and "perf" at
-# runtime figures out where they are based on the path to the executable.
-# This can help installing the suite in a relocatable way.
-
-# Make the path relative to DESTDIR, not to prefix
-ifndef DESTDIR
-prefix = $(HOME)
-endif
-bindir_relative = bin
-bindir = $(prefix)/$(bindir_relative)
-mandir = share/man
-infodir = share/info
-perfexecdir = libexec/perf-core
-sharedir = $(prefix)/share
-template_dir = share/perf-core/templates
-htmldir = share/doc/perf-doc
-ifeq ($(prefix),/usr)
-sysconfdir = /etc
-ETC_PERFCONFIG = $(sysconfdir)/perfconfig
-else
-sysconfdir = $(prefix)/etc
-ETC_PERFCONFIG = etc/perfconfig
-endif
-lib = lib
+$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
+       @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
 
-export prefix bindir sharedir sysconfdir
+CC = $(CROSS_COMPILE)gcc
+AR = $(CROSS_COMPILE)ar
 
-RM = rm -f
-MKDIR = mkdir
-FIND = find
+RM      = rm -f
+MKDIR   = mkdir
+FIND    = find
 INSTALL = install
-FLEX = flex
-BISON= bison
-
-# sparse is architecture-neutral, which means that we need to tell it
-# explicitly what architecture to check for. Fix this up for yours..
-SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
-
-ifneq ($(MAKECMDGOALS),clean)
-ifneq ($(MAKECMDGOALS),tags)
--include config/feature-tests.mak
-
-ifeq ($(call get-executable,$(FLEX)),)
-       dummy := $(error Error: $(FLEX) is missing on this system, please install it)
-endif
-
-ifeq ($(call get-executable,$(BISON)),)
-       dummy := $(error Error: $(BISON) is missing on this system, please install it)
-endif
+FLEX    = flex
+BISON   = bison
+STRIP   = strip
 
-ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
-       CFLAGS := $(CFLAGS) -fstack-protector-all
-endif
+LK_DIR          = $(srctree)/tools/lib/lk/
+TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
 
-ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y)
-       CFLAGS := $(CFLAGS) -Wstack-protector
-endif
+# include config/Makefile by default and rule out
+# non-config cases
+config := 1
 
-ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y)
-       CFLAGS := $(CFLAGS) -Wvolatile-register-var
-endif
+NON_CONFIG_TARGETS := clean TAGS tags cscope help
 
-ifndef PERF_DEBUG
-       ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y)
-               CFLAGS := $(CFLAGS) -D_FORTIFY_SOURCE=2
-       endif
+ifdef MAKECMDGOALS
+ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
+  config := 0
 endif
-
-### --- END CONFIGURATION SECTION ---
-
-ifeq ($(srctree),)
-srctree := $(patsubst %/,%,$(dir $(shell pwd)))
-srctree := $(patsubst %/,%,$(dir $(srctree)))
-#$(info Determined 'srctree' to be $(srctree))
 endif
 
-ifneq ($(objtree),)
-#$(info Determined 'objtree' to be $(objtree))
+ifeq ($(config),1)
+include config/Makefile
 endif
 
-ifneq ($(OUTPUT),)
-#$(info Determined 'OUTPUT' to be $(OUTPUT))
-endif
+export prefix bindir sharedir sysconfdir
 
-BASIC_CFLAGS = \
-       -Iutil/include \
-       -Iarch/$(ARCH)/include \
-       $(if $(objtree),-I$(objtree)/arch/$(ARCH)/include/generated/uapi) \
-       -I$(srctree)/arch/$(ARCH)/include/uapi \
-       -I$(srctree)/arch/$(ARCH)/include \
-       $(if $(objtree),-I$(objtree)/include/generated/uapi) \
-       -I$(srctree)/include/uapi \
-       -I$(srctree)/include \
-       -I$(OUTPUT)util \
-       -Iutil \
-       -I. \
-       -I$(TRACE_EVENT_DIR) \
-       -I../lib/ \
-       -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
-
-BASIC_LDFLAGS =
-
-ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
-       BIONIC := 1
-       EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
-       EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
-       BASIC_CFLAGS += -I.
-endif
-endif # MAKECMDGOALS != tags
-endif # MAKECMDGOALS != clean
+# sparse is architecture-neutral, which means that we need to tell it
+# explicitly what architecture to check for. Fix this up for yours..
+SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
 
 # Guard against environment variables
 BUILTIN_OBJS =
@@ -247,20 +121,17 @@ SCRIPT_SH += perf-archive.sh
 grep-libs = $(filter -l%,$(1))
 strip-libs = $(filter-out -l%,$(1))
 
-LK_DIR = ../lib/lk/
-TRACE_EVENT_DIR = ../lib/traceevent/
-
 LK_PATH=$(LK_DIR)
 
 ifneq ($(OUTPUT),)
-       TE_PATH=$(OUTPUT)
+  TE_PATH=$(OUTPUT)
 ifneq ($(subdir),)
-       LK_PATH=$(OUTPUT)$(LK_DIR)
+  LK_PATH=$(OUTPUT)$(LK_DIR)
 else
-       LK_PATH=$(OUTPUT)
+  LK_PATH=$(OUTPUT)
 endif
 else
-       TE_PATH=$(TRACE_EVENT_DIR)
+  TE_PATH=$(TRACE_EVENT_DIR)
 endif
 
 LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
@@ -278,10 +149,10 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
 python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
 
 PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
-PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT)
+PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK)
 
 $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
-       $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
+       $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
          --quiet build_ext; \
        mkdir -p $(OUTPUT)python && \
        cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
@@ -296,8 +167,6 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
 #
 PROGRAMS += $(OUTPUT)perf
 
-LANG_BINDINGS =
-
 # what 'all' will build and 'install' will install, in perfexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
 
@@ -306,10 +175,10 @@ OTHER_PROGRAMS = $(OUTPUT)perf
 
 # Set paths to tools early so that they can be used for version tests.
 ifndef SHELL_PATH
-       SHELL_PATH = /bin/sh
+  SHELL_PATH = /bin/sh
 endif
 ifndef PERL_PATH
-       PERL_PATH = /usr/bin/perl
+  PERL_PATH = /usr/bin/perl
 endif
 
 export PERL_PATH
@@ -557,79 +426,14 @@ BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
 
 PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
 
-#
-# Platform specific tweaks
-#
-ifneq ($(MAKECMDGOALS),clean)
-ifneq ($(MAKECMDGOALS),tags)
-
 # We choose to avoid "if .. else if .. else .. endif endif"
 # because maintaining the nesting to match is a pain.  If
 # we had "elif" things would have been much nicer...
 
-ifdef NO_LIBELF
-       NO_DWARF := 1
-       NO_DEMANGLE := 1
-       NO_LIBUNWIND := 1
-else
-FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
-ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
-       FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
-       ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
-               LIBC_SUPPORT := 1
-       endif
-       ifeq ($(BIONIC),1)
-               LIBC_SUPPORT := 1
-       endif
-       ifeq ($(LIBC_SUPPORT),1)
-               msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
-
-               NO_LIBELF := 1
-               NO_DWARF := 1
-               NO_DEMANGLE := 1
-       else
-               msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
-       endif
-else
-       # for linking with debug library, run like:
-       # make DEBUG=1 LIBDW_DIR=/opt/libdw/
-       ifdef LIBDW_DIR
-               LIBDW_CFLAGS  := -I$(LIBDW_DIR)/include
-               LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
-       endif
-
-       FLAGS_DWARF=$(ALL_CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
-       ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
-               msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
-               NO_DWARF := 1
-       endif # Dwarf support
-endif # SOURCE_LIBELF
-endif # NO_LIBELF
-
-# There's only x86 (both 32 and 64) support for CFI unwind so far
-ifneq ($(ARCH),x86)
-       NO_LIBUNWIND := 1
-endif
-
-ifndef NO_LIBUNWIND
-# for linking with debug library, run like:
-# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
-ifdef LIBUNWIND_DIR
-       LIBUNWIND_CFLAGS  := -I$(LIBUNWIND_DIR)/include
-       LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
-endif
-
-FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
-ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
-       msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
-       NO_LIBUNWIND := 1
-endif # Libunwind support
-endif # NO_LIBUNWIND
-
 -include arch/$(ARCH)/Makefile
 
 ifneq ($(OUTPUT),)
-       BASIC_CFLAGS += -I$(OUTPUT)
+  CFLAGS += -I$(OUTPUT)
 endif
 
 ifdef NO_LIBELF
@@ -647,281 +451,74 @@ BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
 LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
 
 else # NO_LIBELF
-BASIC_CFLAGS += -DLIBELF_SUPPORT
-
-FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
-ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
-       BASIC_CFLAGS += -DLIBELF_MMAP
-endif
-
 ifndef NO_DWARF
-ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
-       msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
-else
-       BASIC_CFLAGS := -DDWARF_SUPPORT $(LIBDW_CFLAGS) $(BASIC_CFLAGS)
-       BASIC_LDFLAGS := $(LIBDW_LDFLAGS) $(BASIC_LDFLAGS)
-       EXTLIBS += -lelf -ldw
-       LIB_OBJS += $(OUTPUT)util/probe-finder.o
-       LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
-endif # PERF_HAVE_DWARF_REGS
+  LIB_OBJS += $(OUTPUT)util/probe-finder.o
+  LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
 endif # NO_DWARF
 endif # NO_LIBELF
 
 ifndef NO_LIBUNWIND
-       BASIC_CFLAGS += -DLIBUNWIND_SUPPORT
-       EXTLIBS += $(LIBUNWIND_LIBS)
-       BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS)
-       BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS)
-       LIB_OBJS += $(OUTPUT)util/unwind.o
+  LIB_OBJS += $(OUTPUT)util/unwind.o
 endif
 
 ifndef NO_LIBAUDIT
-       FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit
-       ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
-               msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
-       else
-               BASIC_CFLAGS += -DLIBAUDIT_SUPPORT
-               BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
-               EXTLIBS += -laudit
-       endif
+  BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
 endif
 
 ifndef NO_SLANG
-       FLAGS_SLANG=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang
-       ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y)
-               msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev);
-       else
-               # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
-               BASIC_CFLAGS += -I/usr/include/slang
-               BASIC_CFLAGS += -DSLANG_SUPPORT
-               EXTLIBS += -lslang
-               LIB_OBJS += $(OUTPUT)ui/browser.o
-               LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
-               LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
-               LIB_OBJS += $(OUTPUT)ui/browsers/map.o
-               LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
-               LIB_OBJS += $(OUTPUT)ui/tui/setup.o
-               LIB_OBJS += $(OUTPUT)ui/tui/util.o
-               LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
-               LIB_OBJS += $(OUTPUT)ui/tui/progress.o
-               LIB_H += ui/browser.h
-               LIB_H += ui/browsers/map.h
-               LIB_H += ui/keysyms.h
-               LIB_H += ui/libslang.h
-       endif
+  LIB_OBJS += $(OUTPUT)ui/browser.o
+  LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
+  LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
+  LIB_OBJS += $(OUTPUT)ui/browsers/map.o
+  LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
+  LIB_OBJS += $(OUTPUT)ui/tui/setup.o
+  LIB_OBJS += $(OUTPUT)ui/tui/util.o
+  LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
+  LIB_OBJS += $(OUTPUT)ui/tui/progress.o
+  LIB_H += ui/browser.h
+  LIB_H += ui/browsers/map.h
+  LIB_H += ui/keysyms.h
+  LIB_H += ui/libslang.h
 endif
 
 ifndef NO_GTK2
-       FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
-       ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y)
-               msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
-       else
-               ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y)
-                       BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
-               endif
-               BASIC_CFLAGS += -DGTK2_SUPPORT
-               BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
-               EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
-               LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
-               LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
-               LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
-               LIB_OBJS += $(OUTPUT)ui/gtk/util.o
-               LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
-               LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
-               LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
-       endif
+  LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
+  LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
+  LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
+  LIB_OBJS += $(OUTPUT)ui/gtk/util.o
+  LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
+  LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
+  LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
 endif
 
-ifdef NO_LIBPERL
-       BASIC_CFLAGS += -DNO_LIBPERL
-else
-       PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
-       PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
-       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)
-
-       ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
-               BASIC_CFLAGS += -DNO_LIBPERL
-       else
-               ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
-               EXTLIBS += $(PERL_EMBED_LIBADD)
-               LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
-               LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
-       endif
+ifndef NO_LIBPERL
+  LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
+  LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
 endif
 
-disable-python = $(eval $(disable-python_code))
-define disable-python_code
-  BASIC_CFLAGS += -DNO_LIBPYTHON
-  $(if $(1),$(warning No $(1) was found))
-  $(warning Python support will not be built)
-endef
-
-override PYTHON := \
-  $(call get-executable-or-default,PYTHON,python)
-
-ifndef PYTHON
-  $(call disable-python,python interpreter)
-else
-
-  PYTHON_WORD := $(call shell-wordify,$(PYTHON))
-
-  ifdef NO_LIBPYTHON
-    $(call disable-python)
-  else
-
-    override PYTHON_CONFIG := \
-      $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
-
-    ifndef PYTHON_CONFIG
-      $(call disable-python,python-config tool)
-    else
-
-      PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
-
-      PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
-      PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
-      PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
-      PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
-      FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
-
-      ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
-        $(call disable-python,Python.h (for Python 2.x))
-      else
-
-        ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
-          $(warning Python 3 is not yet supported; please set)
-          $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
-          $(warning If you also have Python 2 installed, then)
-          $(warning try something like:)
-          $(warning $(and ,))
-          $(warning $(and ,)  make PYTHON=python2)
-          $(warning $(and ,))
-          $(warning Otherwise, disable Python support entirely:)
-          $(warning $(and ,))
-          $(warning $(and ,)  make NO_LIBPYTHON=1)
-          $(warning $(and ,))
-          $(error   $(and ,))
-        else
-          ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
-          EXTLIBS += $(PYTHON_EMBED_LIBADD)
-          LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
-          LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
-          LANG_BINDINGS += $(OUTPUT)python/perf.so
-        endif
-
-      endif
-    endif
-  endif
-endif
-
-ifdef NO_DEMANGLE
-       BASIC_CFLAGS += -DNO_DEMANGLE
-else
-        ifdef HAVE_CPLUS_DEMANGLE
-               EXTLIBS += -liberty
-               BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
-        else
-               FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
-               has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
-               ifeq ($(has_bfd),y)
-                       EXTLIBS += -lbfd
-               else
-                       FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
-                       has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
-                       ifeq ($(has_bfd_iberty),y)
-                               EXTLIBS += -lbfd -liberty
-                       else
-                               FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
-                               has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
-                               ifeq ($(has_bfd_iberty_z),y)
-                                       EXTLIBS += -lbfd -liberty -lz
-                               else
-                                       FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
-                                       has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
-                                       ifeq ($(has_cplus_demangle),y)
-                                               EXTLIBS += -liberty
-                                               BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
-                                       else
-                                               msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
-                                               BASIC_CFLAGS += -DNO_DEMANGLE
-                                       endif
-                               endif
-                       endif
-               endif
-       endif
+ifndef NO_LIBPYTHON
+  LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
+  LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
 endif
 
 ifeq ($(NO_PERF_REGS),0)
-       ifeq ($(ARCH),x86)
-               LIB_H += arch/x86/include/perf_regs.h
-       endif
-       BASIC_CFLAGS += -DHAVE_PERF_REGS
-endif
-
-ifndef NO_STRLCPY
-       ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
-               BASIC_CFLAGS += -DHAVE_STRLCPY
-       endif
-endif
-
-ifndef NO_ON_EXIT
-       ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
-               BASIC_CFLAGS += -DHAVE_ON_EXIT
-       endif
-endif
-
-ifndef NO_BACKTRACE
-       ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
-               BASIC_CFLAGS += -DBACKTRACE_SUPPORT
-       endif
+  ifeq ($(ARCH),x86)
+    LIB_H += arch/x86/include/perf_regs.h
+  endif
 endif
 
 ifndef NO_LIBNUMA
-       FLAGS_LIBNUMA = $(ALL_CFLAGS) $(ALL_LDFLAGS) -lnuma
-       ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
-               msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
-       else
-               BASIC_CFLAGS += -DLIBNUMA_SUPPORT
-               BUILTIN_OBJS += $(OUTPUT)bench/numa.o
-               EXTLIBS += -lnuma
-       endif
+  BUILTIN_OBJS += $(OUTPUT)bench/numa.o
 endif
 
 ifdef ASCIIDOC8
-       export ASCIIDOC8
+  export ASCIIDOC8
 endif
 
-endif # MAKECMDGOALS != tags
-endif # MAKECMDGOALS != clean
-
-# Shell quote (do not use $(call) to accommodate ancient setups);
-
-ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
-
-DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
-bindir_SQ = $(subst ','\'',$(bindir))
-bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
-mandir_SQ = $(subst ','\'',$(mandir))
-infodir_SQ = $(subst ','\'',$(infodir))
-perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
-template_dir_SQ = $(subst ','\'',$(template_dir))
-htmldir_SQ = $(subst ','\'',$(htmldir))
-prefix_SQ = $(subst ','\'',$(prefix))
-sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
-
-SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
-
 LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
 
-ALL_CFLAGS += $(BASIC_CFLAGS)
-ALL_CFLAGS += $(ARCH_CFLAGS)
-ALL_LDFLAGS += $(BASIC_LDFLAGS)
-
 export INSTALL SHELL_PATH
 
-
 ### Build rules
 
 SHELL = $(SHELL_PATH)
@@ -939,20 +536,20 @@ strip: $(PROGRAMS) $(OUTPUT)perf
 $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
                '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
-               $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
+               $(CFLAGS) -c $(filter %.c,$^) -o $@
 
 $(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
-       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
+       $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \
                $(BUILTIN_OBJS) $(LIBS) -o $@
 
 $(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
                '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
                '-DPERF_MAN_PATH="$(mandir_SQ)"' \
                '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
 
 $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
                '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
                '-DPERF_MAN_PATH="$(mandir_SQ)"' \
                '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
@@ -977,77 +574,77 @@ $(OUTPUT)perf.o perf.spec \
 # over the general rule for .o
 
 $(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -w $<
+       $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $<
 
 $(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
+       $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
 
 $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
 $(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $<
+       $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
 $(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $<
+       $(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $<
 $(OUTPUT)%.o: %.S
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
 $(OUTPUT)%.s: %.S
-       $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $<
+       $(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
 
 $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
                '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
                '-DPREFIX="$(prefix_SQ)"' \
                $<
 
 $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
                '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
                $<
 
 $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
                -DPYTHONPATH='"$(OUTPUT)python"' \
                -DPYTHON='"$(PYTHON_WORD)"' \
                $<
 
 $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
 $(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
 $(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
 $(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
 $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
 $(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
 $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
 $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
 
 $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
 
 $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
 
 $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
 
 $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
 
 $(OUTPUT)perf-%: %.o $(PERFLIBS)
-       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+       $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
 
 $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
 $(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
@@ -1134,7 +731,7 @@ cscope:
        $(FIND) . -name '*.[hcS]' -print | xargs cscope -b
 
 ### Detect prefix changes
-TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
+TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
              $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
 
 $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
@@ -1155,7 +752,7 @@ check: $(OUTPUT)common-cmds.h
        then \
                for i in *.c */*.c; \
                do \
-                       sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
+                       sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
                done; \
        else \
                exit 1; \
@@ -1163,13 +760,6 @@ check: $(OUTPUT)common-cmds.h
 
 ### Installation rules
 
-ifneq ($(filter /%,$(firstword $(perfexecdir))),)
-perfexec_instdir = $(perfexecdir)
-else
-perfexec_instdir = $(prefix)/$(perfexecdir)
-endif
-perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
-
 install-bin: all
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
        $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
index 2d0462d89a972ffde8d1ef24e1c9262c45cb3ac7..da8f8eb383a0bea2b7ddefe923836969acbd65fe 100644 (file)
@@ -323,13 +323,20 @@ static void hists__baseline_only(struct hists *hists)
 
 static void hists__precompute(struct hists *hists)
 {
-       struct rb_node *next = rb_first(&hists->entries);
+       struct rb_root *root;
+       struct rb_node *next;
+
+       if (sort__need_collapse)
+               root = &hists->entries_collapsed;
+       else
+               root = hists->entries_in;
 
+       next = rb_first(root);
        while (next != NULL) {
-               struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
+               struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
                struct hist_entry *pair = hist_entry__next_pair(he);
 
-               next = rb_next(&he->rb_node);
+               next = rb_next(&he->rb_node_in);
                if (!pair)
                        continue;
 
@@ -457,7 +464,7 @@ static void hists__process(struct hists *old, struct hists *new)
                hists__output_resort(new);
        }
 
-       hists__fprintf(new, true, 0, 0, stdout);
+       hists__fprintf(new, true, 0, 0, 0, stdout);
 }
 
 static int __cmd_diff(void)
@@ -611,9 +618,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
 
        setup_pager();
 
-       sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
-       sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL);
-       sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL);
+       sort__setup_elide(NULL);
 
        return __cmd_diff();
 }
index 533501e2b07cd4f2bbb8a13019f675507e11c5dc..24b78aecc9287bb018c26ac2668cacab20a3b789 100644 (file)
@@ -328,6 +328,7 @@ static int kvm_events_hash_fn(u64 key)
 static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
 {
        int old_max_vcpu = event->max_vcpu;
+       void *prev;
 
        if (vcpu_id < event->max_vcpu)
                return true;
@@ -335,9 +336,11 @@ static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
        while (event->max_vcpu <= vcpu_id)
                event->max_vcpu += DEFAULT_VCPU_NUM;
 
+       prev = event->vcpu;
        event->vcpu = realloc(event->vcpu,
                              event->max_vcpu * sizeof(*event->vcpu));
        if (!event->vcpu) {
+               free(prev);
                pr_err("Not enough memory\n");
                return false;
        }
index cdf58ecc04b106a5b783d4f17b69ae1ef7528f4a..fff985cf38522cc0cb3a442de32e545529861514 100644 (file)
@@ -198,7 +198,6 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
                return;
 
        signal(signr, SIG_DFL);
-       kill(getpid(), signr);
 }
 
 static bool perf_evlist__equal(struct perf_evlist *evlist,
@@ -404,6 +403,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
        signal(SIGCHLD, sig_handler);
        signal(SIGINT, sig_handler);
        signal(SIGUSR1, sig_handler);
+       signal(SIGTERM, sig_handler);
 
        if (!output_name) {
                if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
index bd0ca81eeaca9616277e4af6c30a8be892b0eb45..ca98d34cd58b533491a255c8349795f581afce17 100644 (file)
@@ -52,6 +52,7 @@ struct perf_report {
        symbol_filter_t         annotate_init;
        const char              *cpu_list;
        const char              *symbol_filter_str;
+       float                   min_percent;
        DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 };
 
@@ -61,6 +62,11 @@ static int perf_report_config(const char *var, const char *value, void *cb)
                symbol_conf.event_group = perf_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "report.percent-limit")) {
+               struct perf_report *rep = cb;
+               rep->min_percent = strtof(value, NULL);
+               return 0;
+       }
 
        return perf_default_config(var, value, cb);
 }
@@ -187,6 +193,9 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
        for (i = 0; i < sample->branch_stack->nr; i++) {
                if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
                        continue;
+
+               err = -ENOMEM;
+
                /*
                 * The report shows the percentage of total branches captured
                 * and not events sampled. Thus we use a pseudo period of 1.
@@ -195,7 +204,6 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
                                &bi[i], 1, 1);
                if (he) {
                        struct annotation *notes;
-                       err = -ENOMEM;
                        bx = he->branch_info;
                        if (bx->from.sym && use_browser == 1 && sort__has_sym) {
                                notes = symbol__annotation(bx->from.sym);
@@ -226,11 +234,12 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
                        }
                        evsel->hists.stats.total_period += 1;
                        hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
-                       err = 0;
                } else
-                       return -ENOMEM;
+                       goto out;
        }
+       err = 0;
 out:
+       free(bi);
        return err;
 }
 
@@ -294,6 +303,7 @@ static int process_sample_event(struct perf_tool *tool,
 {
        struct perf_report *rep = container_of(tool, struct perf_report, tool);
        struct addr_location al;
+       int ret;
 
        if (perf_event__preprocess_sample(event, machine, &al, sample,
                                          rep->annotate_init) < 0) {
@@ -308,28 +318,25 @@ static int process_sample_event(struct perf_tool *tool,
        if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
                return 0;
 
-       if (sort__branch_mode == 1) {
-               if (perf_report__add_branch_hist_entry(tool, &al, sample,
-                                                      evsel, machine)) {
+       if (sort__mode == SORT_MODE__BRANCH) {
+               ret = perf_report__add_branch_hist_entry(tool, &al, sample,
+                                                        evsel, machine);
+               if (ret < 0)
                        pr_debug("problem adding lbr entry, skipping event\n");
-                       return -1;
-               }
        } else if (rep->mem_mode == 1) {
-               if (perf_report__add_mem_hist_entry(tool, &al, sample,
-                                                   evsel, machine, event)) {
+               ret = perf_report__add_mem_hist_entry(tool, &al, sample,
+                                                     evsel, machine, event);
+               if (ret < 0)
                        pr_debug("problem adding mem entry, skipping event\n");
-                       return -1;
-               }
        } else {
                if (al.map != NULL)
                        al.map->dso->hit = 1;
 
-               if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
+               ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine);
+               if (ret < 0)
                        pr_debug("problem incrementing symbol period, skipping event\n");
-                       return -1;
-               }
        }
-       return 0;
+       return ret;
 }
 
 static int process_read_event(struct perf_tool *tool,
@@ -384,7 +391,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
                        }
        }
 
-       if (sort__branch_mode == 1) {
+       if (sort__mode == SORT_MODE__BRANCH) {
                if (!self->fd_pipe &&
                    !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
                        ui__error("Selected -b but no branch data. "
@@ -455,7 +462,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
                        continue;
 
                hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
-               hists__fprintf(hists, true, 0, 0, stdout);
+               hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
                fprintf(stdout, "\n\n");
        }
 
@@ -574,8 +581,8 @@ static int __cmd_report(struct perf_report *rep)
        if (use_browser > 0) {
                if (use_browser == 1) {
                        ret = perf_evlist__tui_browse_hists(session->evlist,
-                                                       help,
-                                                       NULL,
+                                                       help, NULL,
+                                                       rep->min_percent,
                                                        &session->header.env);
                        /*
                         * Usually "ret" is the last pressed key, and we only
@@ -586,7 +593,7 @@ static int __cmd_report(struct perf_report *rep)
 
                } else if (use_browser == 2) {
                        perf_evlist__gtk_browse_hists(session->evlist, help,
-                                                     NULL);
+                                                     NULL, rep->min_percent);
                }
        } else
                perf_evlist__tty_browse_hists(session->evlist, rep, help);
@@ -691,7 +698,19 @@ static int
 parse_branch_mode(const struct option *opt __maybe_unused,
                  const char *str __maybe_unused, int unset)
 {
-       sort__branch_mode = !unset;
+       int *branch_mode = opt->value;
+
+       *branch_mode = !unset;
+       return 0;
+}
+
+static int
+parse_percent_limit(const struct option *opt, const char *str,
+                   int unset __maybe_unused)
+{
+       struct perf_report *rep = opt->value;
+
+       rep->min_percent = strtof(str, NULL);
        return 0;
 }
 
@@ -700,6 +719,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        struct perf_session *session;
        struct stat st;
        bool has_br_stack = false;
+       int branch_mode = -1;
        int ret = -1;
        char callchain_default_opt[] = "fractal,0.5,callee";
        const char * const report_usage[] = {
@@ -796,17 +816,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                    "Show a column with the sum of periods"),
        OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
                    "Show event group information together"),
-       OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
+       OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
                    "use branch records for histogram filling", parse_branch_mode),
        OPT_STRING(0, "objdump", &objdump_path, "path",
                   "objdump binary to use for disassembly and annotations"),
        OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
                    "Disable symbol demangling"),
        OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
+       OPT_CALLBACK(0, "percent-limit", &report, "percent",
+                    "Don't show entries under that percent", parse_percent_limit),
        OPT_END()
        };
 
-       perf_config(perf_report_config, NULL);
+       perf_config(perf_report_config, &report);
 
        argc = parse_options(argc, argv, options, report_usage, 0);
 
@@ -846,11 +868,11 @@ repeat:
        has_br_stack = perf_header__has_feat(&session->header,
                                             HEADER_BRANCH_STACK);
 
-       if (sort__branch_mode == -1 && has_br_stack)
-               sort__branch_mode = 1;
+       if (branch_mode == -1 && has_br_stack)
+               sort__mode = SORT_MODE__BRANCH;
 
-       /* sort__branch_mode could be 0 if --no-branch-stack */
-       if (sort__branch_mode == 1) {
+       /* sort__mode could be NORMAL if --no-branch-stack */
+       if (sort__mode == SORT_MODE__BRANCH) {
                /*
                 * if no sort_order is provided, then specify
                 * branch-mode specific order
@@ -861,10 +883,12 @@ repeat:
 
        }
        if (report.mem_mode) {
-               if (sort__branch_mode == 1) {
+               if (sort__mode == SORT_MODE__BRANCH) {
                        fprintf(stderr, "branch and mem mode incompatible\n");
                        goto error;
                }
+               sort__mode = SORT_MODE__MEMORY;
+
                /*
                 * if no sort_order is provided, then specify
                 * branch-mode specific order
@@ -929,25 +953,7 @@ repeat:
                report.symbol_filter_str = argv[0];
        }
 
-       sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
-
-       if (sort__branch_mode == 1) {
-               sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout);
-               sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout);
-               sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
-               sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
-       } else {
-               if (report.mem_mode) {
-                       sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "symbol_daddr", stdout);
-                       sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso_daddr", stdout);
-                       sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "mem", stdout);
-                       sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "local_weight", stdout);
-                       sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "tlb", stdout);
-                       sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "snoop", stdout);
-               }
-               sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
-               sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
-       }
+       sort__setup_elide(stdout);
 
        ret = __cmd_report(&report);
        if (ret == K_SWITCH_INPUT_DATA) {
index 67bdb9f14ad61ea765476113ffb61d0f50a57e05..f036af9b6f09f00e52debecafe09a1c930d3ad12 100644 (file)
 
 static volatile int done;
 
+#define HEADER_LINE_NR  5
+
 static void perf_top__update_print_entries(struct perf_top *top)
 {
-       if (top->print_entries > 9)
-               top->print_entries -= 9;
+       top->print_entries = top->winsize.ws_row - HEADER_LINE_NR;
 }
 
 static void perf_top__sig_winch(int sig __maybe_unused,
@@ -82,13 +83,6 @@ static void perf_top__sig_winch(int sig __maybe_unused,
        struct perf_top *top = arg;
 
        get_term_dimensions(&top->winsize);
-       if (!top->print_entries
-           || (top->print_entries+4) > top->winsize.ws_row) {
-               top->print_entries = top->winsize.ws_row;
-       } else {
-               top->print_entries += 4;
-               top->winsize.ws_row = top->print_entries;
-       }
        perf_top__update_print_entries(top);
 }
 
@@ -251,8 +245,11 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
 {
        struct hist_entry *he;
 
+       pthread_mutex_lock(&evsel->hists.lock);
        he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
                                sample->weight);
+       pthread_mutex_unlock(&evsel->hists.lock);
+
        if (he == NULL)
                return NULL;
 
@@ -290,16 +287,17 @@ static void perf_top__print_sym_table(struct perf_top *top)
                return;
        }
 
-       hists__collapse_resort_threaded(&top->sym_evsel->hists);
-       hists__output_resort_threaded(&top->sym_evsel->hists);
-       hists__decay_entries_threaded(&top->sym_evsel->hists,
-                                     top->hide_user_symbols,
-                                     top->hide_kernel_symbols);
+       hists__collapse_resort(&top->sym_evsel->hists);
+       hists__output_resort(&top->sym_evsel->hists);
+       hists__decay_entries(&top->sym_evsel->hists,
+                            top->hide_user_symbols,
+                            top->hide_kernel_symbols);
        hists__output_recalc_col_len(&top->sym_evsel->hists,
-                                    top->winsize.ws_row - 3);
+                                    top->print_entries - printed);
        putchar('\n');
        hists__fprintf(&top->sym_evsel->hists, false,
-                      top->winsize.ws_row - 4 - printed, win_width, stdout);
+                      top->print_entries - printed, win_width,
+                      top->min_percent, stdout);
 }
 
 static void prompt_integer(int *target, const char *msg)
@@ -477,7 +475,6 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
                                perf_top__sig_winch(SIGWINCH, NULL, top);
                                sigaction(SIGWINCH, &act, NULL);
                        } else {
-                               perf_top__sig_winch(SIGWINCH, NULL, top);
                                signal(SIGWINCH, SIG_DFL);
                        }
                        break;
@@ -556,11 +553,11 @@ static void perf_top__sort_new_samples(void *arg)
        if (t->evlist->selected != NULL)
                t->sym_evsel = t->evlist->selected;
 
-       hists__collapse_resort_threaded(&t->sym_evsel->hists);
-       hists__output_resort_threaded(&t->sym_evsel->hists);
-       hists__decay_entries_threaded(&t->sym_evsel->hists,
-                                     t->hide_user_symbols,
-                                     t->hide_kernel_symbols);
+       hists__collapse_resort(&t->sym_evsel->hists);
+       hists__output_resort(&t->sym_evsel->hists);
+       hists__decay_entries(&t->sym_evsel->hists,
+                            t->hide_user_symbols,
+                            t->hide_kernel_symbols);
 }
 
 static void *display_thread_tui(void *arg)
@@ -584,7 +581,7 @@ static void *display_thread_tui(void *arg)
        list_for_each_entry(pos, &top->evlist->entries, node)
                pos->hists.uid_filter_str = top->record_opts.target.uid_str;
 
-       perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
+       perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
                                      &top->session->header.env);
 
        done = 1;
@@ -794,7 +791,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
                                return;
                }
 
-               if (top->sort_has_symbols)
+               if (sort__has_sym)
                        perf_top__record_precise_ip(top, he, evsel->idx, ip);
        }
 
@@ -912,9 +909,9 @@ out_err:
        return -1;
 }
 
-static int perf_top__setup_sample_type(struct perf_top *top)
+static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused)
 {
-       if (!top->sort_has_symbols) {
+       if (!sort__has_sym) {
                if (symbol_conf.use_callchain) {
                        ui__error("Selected -g but \"sym\" not present in --sort/-s.");
                        return -EINVAL;
@@ -1025,6 +1022,16 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
        return record_parse_callchain_opt(opt, arg, unset);
 }
 
+static int
+parse_percent_limit(const struct option *opt, const char *arg,
+                   int unset __maybe_unused)
+{
+       struct perf_top *top = opt->value;
+
+       top->min_percent = strtof(arg, NULL);
+       return 0;
+}
+
 int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        int status;
@@ -1110,6 +1117,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
                   "Specify disassembler style (e.g. -M intel for intel syntax)"),
        OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
+       OPT_CALLBACK(0, "percent-limit", &top, "percent",
+                    "Don't show entries under that percent", parse_percent_limit),
        OPT_END()
        };
        const char * const top_usage[] = {
@@ -1133,6 +1142,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (setup_sorting() < 0)
                usage_with_options(top_usage, options);
 
+       /* display thread wants entries to be collapsed in a different tree */
+       sort__need_collapse = 1;
+
        if (top.use_stdio)
                use_browser = 0;
        else if (top.use_tui)
@@ -1200,15 +1212,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (symbol__init() < 0)
                return -1;
 
-       sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
-       sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
-       sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
-
-       /*
-        * Avoid annotation data structures overhead when symbols aren't on the
-        * sort list.
-        */
-       top.sort_has_symbols = sort_sym.list.next != NULL;
+       sort__setup_elide(stdout);
 
        get_term_dimensions(&top.winsize);
        if (top.print_entries == 0) {
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
new file mode 100644 (file)
index 0000000..f139dcd
--- /dev/null
@@ -0,0 +1,477 @@
+uname_M := $(shell uname -m 2>/dev/null || echo not)
+
+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+                                  -e s/arm.*/arm/ -e s/sa110/arm/ \
+                                  -e s/s390x/s390/ -e s/parisc64/parisc/ \
+                                  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
+                                  -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
+NO_PERF_REGS := 1
+CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
+
+# Additional ARCH settings for x86
+ifeq ($(ARCH),i386)
+  override ARCH := x86
+  NO_PERF_REGS := 0
+  LIBUNWIND_LIBS = -lunwind -lunwind-x86
+endif
+
+ifeq ($(ARCH),x86_64)
+  override ARCH := x86
+  IS_X86_64 := 0
+  ifeq (, $(findstring m32,$(CFLAGS)))
+    IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
+  endif
+  ifeq (${IS_X86_64}, 1)
+    RAW_ARCH := x86_64
+    CFLAGS += -DARCH_X86_64
+    ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
+  endif
+  NO_PERF_REGS := 0
+  LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
+endif
+
+ifeq ($(NO_PERF_REGS),0)
+  CFLAGS += -DHAVE_PERF_REGS
+endif
+
+ifeq ($(src-perf),)
+src-perf := $(srctree)/tools/perf
+endif
+
+ifeq ($(obj-perf),)
+obj-perf := $(objtree)
+endif
+
+ifneq ($(obj-perf),)
+obj-perf := $(abspath $(obj-perf))/
+endif
+
+# include ARCH specific config
+-include $(src-perf)/arch/$(ARCH)/Makefile
+
+include $(src-perf)/config/feature-tests.mak
+include $(src-perf)/config/utilities.mak
+
+ifeq ($(call get-executable,$(FLEX)),)
+  dummy := $(error Error: $(FLEX) is missing on this system, please install it)
+endif
+
+ifeq ($(call get-executable,$(BISON)),)
+  dummy := $(error Error: $(BISON) is missing on this system, please install it)
+endif
+
+# Treat warnings as errors unless directed not to
+ifneq ($(WERROR),0)
+  CFLAGS += -Werror
+endif
+
+ifeq ("$(origin DEBUG)", "command line")
+  PERF_DEBUG = $(DEBUG)
+endif
+ifndef PERF_DEBUG
+  CFLAGS += -O6
+endif
+
+ifdef PARSER_DEBUG
+  PARSER_DEBUG_BISON := -t
+  PARSER_DEBUG_FLEX  := -d
+  CFLAGS             += -DPARSER_DEBUG
+endif
+
+CFLAGS += -fno-omit-frame-pointer
+CFLAGS += -ggdb3
+CFLAGS += -funwind-tables
+CFLAGS += -Wall
+CFLAGS += -Wextra
+CFLAGS += -std=gnu99
+
+EXTLIBS = -lpthread -lrt -lelf -lm
+
+ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
+  CFLAGS += -fstack-protector-all
+endif
+
+ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y)
+  CFLAGS += -Wstack-protector
+endif
+
+ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y)
+  CFLAGS += -Wvolatile-register-var
+endif
+
+ifndef PERF_DEBUG
+  ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y)
+    CFLAGS += -D_FORTIFY_SOURCE=2
+  endif
+endif
+
+CFLAGS += -I$(src-perf)/util/include
+CFLAGS += -I$(src-perf)/arch/$(ARCH)/include
+CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi
+CFLAGS += -I$(srctree)/arch/$(ARCH)/include
+CFLAGS += -I$(srctree)/include/uapi
+CFLAGS += -I$(srctree)/include
+
+# $(obj-perf)      for generated common-cmds.h
+# $(obj-perf)/util for generated bison/flex headers
+ifneq ($(OUTPUT),)
+CFLAGS += -I$(obj-perf)/util
+CFLAGS += -I$(obj-perf)
+endif
+
+CFLAGS += -I$(src-perf)/util
+CFLAGS += -I$(src-perf)
+CFLAGS += -I$(TRACE_EVENT_DIR)
+CFLAGS += -I$(srctree)/tools/lib/
+
+CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+
+ifndef NO_BIONIC
+ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
+  BIONIC := 1
+  EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
+  EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
+endif
+endif # NO_BIONIC
+
+ifdef NO_LIBELF
+  NO_DWARF := 1
+  NO_DEMANGLE := 1
+  NO_LIBUNWIND := 1
+else
+FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
+ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
+  FLAGS_GLIBC=$(CFLAGS) $(LDFLAGS)
+  ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
+    LIBC_SUPPORT := 1
+  endif
+  ifeq ($(BIONIC),1)
+    LIBC_SUPPORT := 1
+  endif
+  ifeq ($(LIBC_SUPPORT),1)
+    msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
+
+    NO_LIBELF := 1
+    NO_DWARF := 1
+    NO_DEMANGLE := 1
+  else
+    msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
+  endif
+else
+  # for linking with debug library, run like:
+  # make DEBUG=1 LIBDW_DIR=/opt/libdw/
+  ifdef LIBDW_DIR
+    LIBDW_CFLAGS  := -I$(LIBDW_DIR)/include
+    LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
+  endif
+
+  FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS)
+  ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
+    msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
+    NO_DWARF := 1
+  endif # Dwarf support
+endif # SOURCE_LIBELF
+endif # NO_LIBELF
+
+ifndef NO_LIBELF
+CFLAGS += -DLIBELF_SUPPORT
+FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
+ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
+  CFLAGS += -DLIBELF_MMAP
+endif
+
+# include ARCH specific config
+-include $(src-perf)/arch/$(ARCH)/Makefile
+
+ifndef NO_DWARF
+ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
+  msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
+  NO_DWARF := 1
+else
+  CFLAGS += -DDWARF_SUPPORT $(LIBDW_CFLAGS)
+  LDFLAGS += $(LIBDW_LDFLAGS)
+  EXTLIBS += -lelf -ldw
+endif # PERF_HAVE_DWARF_REGS
+endif # NO_DWARF
+
+endif # NO_LIBELF
+
+ifndef NO_LIBELF
+CFLAGS += -DLIBELF_SUPPORT
+FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
+ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
+  CFLAGS += -DLIBELF_MMAP
+endif # try-cc
+endif # NO_LIBELF
+
+# There's only x86 (both 32 and 64) support for CFI unwind so far
+ifneq ($(ARCH),x86)
+  NO_LIBUNWIND := 1
+endif
+
+ifndef NO_LIBUNWIND
+# for linking with debug library, run like:
+# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
+ifdef LIBUNWIND_DIR
+  LIBUNWIND_CFLAGS  := -I$(LIBUNWIND_DIR)/include
+  LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
+endif
+
+FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(CFLAGS) $(LIBUNWIND_LDFLAGS) $(LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
+ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
+  msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
+  NO_LIBUNWIND := 1
+endif # Libunwind support
+endif # NO_LIBUNWIND
+
+ifndef NO_LIBUNWIND
+  CFLAGS += -DLIBUNWIND_SUPPORT
+  EXTLIBS += $(LIBUNWIND_LIBS)
+  CFLAGS += $(LIBUNWIND_CFLAGS)
+  LDFLAGS += $(LIBUNWIND_LDFLAGS)
+endif # NO_LIBUNWIND
+
+ifndef NO_LIBAUDIT
+  FLAGS_LIBAUDIT = $(CFLAGS) $(LDFLAGS) -laudit
+  ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
+    msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
+    NO_LIBAUDIT := 1
+  else
+    CFLAGS += -DLIBAUDIT_SUPPORT
+    EXTLIBS += -laudit
+  endif
+endif
+
+ifdef NO_NEWT
+  NO_SLANG=1
+endif
+
+ifndef NO_SLANG
+  FLAGS_SLANG=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang
+  ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y)
+    msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev);
+    NO_SLANG := 1
+  else
+    # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
+    CFLAGS += -I/usr/include/slang
+    CFLAGS += -DSLANG_SUPPORT
+    EXTLIBS += -lslang
+  endif
+endif
+
+ifndef NO_GTK2
+  FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
+  ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y)
+    msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
+    NO_GTK2 := 1
+  else
+    ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y)
+      CFLAGS += -DHAVE_GTK_INFO_BAR
+    endif
+    CFLAGS += -DGTK2_SUPPORT
+    CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
+    EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
+  endif
+endif
+
+grep-libs  = $(filter -l%,$(1))
+strip-libs = $(filter-out -l%,$(1))
+
+ifdef NO_LIBPERL
+  CFLAGS += -DNO_LIBPERL
+else
+  PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
+  PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
+  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)
+
+  ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
+    CFLAGS += -DNO_LIBPERL
+    NO_LIBPERL := 1
+  else
+    LDFLAGS += $(PERL_EMBED_LDFLAGS)
+    EXTLIBS += $(PERL_EMBED_LIBADD)
+  endif
+endif
+
+disable-python = $(eval $(disable-python_code))
+define disable-python_code
+  CFLAGS += -DNO_LIBPYTHON
+  $(if $(1),$(warning No $(1) was found))
+  $(warning Python support will not be built)
+  NO_LIBPYTHON := 1
+endef
+
+override PYTHON := \
+  $(call get-executable-or-default,PYTHON,python)
+
+ifndef PYTHON
+  $(call disable-python,python interpreter)
+else
+
+  PYTHON_WORD := $(call shell-wordify,$(PYTHON))
+
+  ifdef NO_LIBPYTHON
+    $(call disable-python)
+  else
+
+    override PYTHON_CONFIG := \
+      $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
+
+    ifndef PYTHON_CONFIG
+      $(call disable-python,python-config tool)
+    else
+
+      PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
+
+      PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
+      PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
+      PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
+      PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
+      FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
+
+      ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
+        $(call disable-python,Python.h (for Python 2.x))
+      else
+
+        ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
+          $(warning Python 3 is not yet supported; please set)
+          $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
+          $(warning If you also have Python 2 installed, then)
+          $(warning try something like:)
+          $(warning $(and ,))
+          $(warning $(and ,)  make PYTHON=python2)
+          $(warning $(and ,))
+          $(warning Otherwise, disable Python support entirely:)
+          $(warning $(and ,))
+          $(warning $(and ,)  make NO_LIBPYTHON=1)
+          $(warning $(and ,))
+          $(error   $(and ,))
+        else
+          LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
+          EXTLIBS += $(PYTHON_EMBED_LIBADD)
+          LANG_BINDINGS += $(obj-perf)python/perf.so
+        endif
+      endif
+    endif
+  endif
+endif
+
+ifdef NO_DEMANGLE
+  CFLAGS += -DNO_DEMANGLE
+else
+  ifdef HAVE_CPLUS_DEMANGLE
+    EXTLIBS += -liberty
+    CFLAGS += -DHAVE_CPLUS_DEMANGLE
+  else
+    FLAGS_BFD=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
+    has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
+    ifeq ($(has_bfd),y)
+      EXTLIBS += -lbfd
+    else
+      FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
+      has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
+      ifeq ($(has_bfd_iberty),y)
+        EXTLIBS += -lbfd -liberty
+      else
+        FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
+        has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
+        ifeq ($(has_bfd_iberty_z),y)
+          EXTLIBS += -lbfd -liberty -lz
+        else
+          FLAGS_CPLUS_DEMANGLE=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -liberty
+          has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
+          ifeq ($(has_cplus_demangle),y)
+            EXTLIBS += -liberty
+            CFLAGS += -DHAVE_CPLUS_DEMANGLE
+          else
+            msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
+            CFLAGS += -DNO_DEMANGLE
+          endif
+        endif
+      endif
+    endif
+  endif
+endif
+
+ifndef NO_STRLCPY
+  ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
+    CFLAGS += -DHAVE_STRLCPY
+  endif
+endif
+
+ifndef NO_ON_EXIT
+  ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
+    CFLAGS += -DHAVE_ON_EXIT
+  endif
+endif
+
+ifndef NO_BACKTRACE
+  ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
+    CFLAGS += -DBACKTRACE_SUPPORT
+  endif
+endif
+
+ifndef NO_LIBNUMA
+  FLAGS_LIBNUMA = $(CFLAGS) $(LDFLAGS) -lnuma
+  ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
+    msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
+    NO_LIBNUMA := 1
+  else
+    CFLAGS += -DLIBNUMA_SUPPORT
+    EXTLIBS += -lnuma
+  endif
+endif
+
+# Among the variables below, these:
+#   perfexecdir
+#   template_dir
+#   mandir
+#   infodir
+#   htmldir
+#   ETC_PERFCONFIG (but not sysconfdir)
+# can be specified as a relative path some/where/else;
+# this is interpreted as relative to $(prefix) and "perf" at
+# runtime figures out where they are based on the path to the executable.
+# This can help installing the suite in a relocatable way.
+
+# Make the path relative to DESTDIR, not to prefix
+ifndef DESTDIR
+prefix = $(HOME)
+endif
+bindir_relative = bin
+bindir = $(prefix)/$(bindir_relative)
+mandir = share/man
+infodir = share/info
+perfexecdir = libexec/perf-core
+sharedir = $(prefix)/share
+template_dir = share/perf-core/templates
+htmldir = share/doc/perf-doc
+ifeq ($(prefix),/usr)
+sysconfdir = /etc
+ETC_PERFCONFIG = $(sysconfdir)/perfconfig
+else
+sysconfdir = $(prefix)/etc
+ETC_PERFCONFIG = etc/perfconfig
+endif
+lib = lib
+
+# Shell quote (do not use $(call) to accommodate ancient setups);
+ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
+DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
+bindir_SQ = $(subst ','\'',$(bindir))
+mandir_SQ = $(subst ','\'',$(mandir))
+infodir_SQ = $(subst ','\'',$(infodir))
+perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
+template_dir_SQ = $(subst ','\'',$(template_dir))
+htmldir_SQ = $(subst ','\'',$(htmldir))
+prefix_SQ = $(subst ','\'',$(prefix))
+sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
+
+ifneq ($(filter /%,$(firstword $(perfexecdir))),)
+perfexec_instdir = $(perfexecdir)
+else
+perfexec_instdir = $(prefix)/$(perfexecdir)
+endif
+perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
index b4fc835de6074fc242e438e901cdc8463742268e..e9bd6391f2aeb09d2f29445a8f55052b0845c419 100644 (file)
@@ -27,8 +27,8 @@ watermark=0
 precise_ip=0
 mmap_data=0
 sample_id_all=1
-exclude_host=0
-exclude_guest=1
+exclude_host=0|1
+exclude_guest=0|1
 exclude_callchain_kernel=0
 exclude_callchain_user=0
 wakeup_events=0
index 748ee949a204c2d7a27796ae4d3d2e8c94b09676..91cd48b399f3b8006f67fa5711eff84129bee2d3 100644 (file)
@@ -27,8 +27,8 @@ watermark=0
 precise_ip=0
 mmap_data=0
 sample_id_all=0
-exclude_host=0
-exclude_guest=1
+exclude_host=0|1
+exclude_guest=0|1
 exclude_callchain_kernel=0
 exclude_callchain_user=0
 wakeup_events=0
index 6627c3e7534a5c0dd29bebe293a771fc2175b903..716e143b5291196480afee1a7fa14961a8d52a99 100644 (file)
@@ -4,5 +4,8 @@ args    = -d kill >/dev/null 2>&1
 
 [event:base-record]
 sample_period=4000
-sample_type=271
+
+# sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
+# PERF_SAMPLE_ADDR | PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC
+sample_type=33039
 mmap_data=1
index 68daa289e94c84f2f6dc6968c236bf5fce683c46..aba095489193bb6e224ff11f3f2ee03968df8711 100644 (file)
@@ -4,6 +4,12 @@
  * (git://github.com/deater/perf_event_tests)
  */
 
+/*
+ * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
+ * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
+ */
+#define __SANE_USERSPACE_TYPES__
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
index fe7ed28815f8910e3430899dd0cbbcf0bc440020..44ac82179708b50d6ab559cb9258c8334ab70fff 100644 (file)
@@ -3,6 +3,12 @@
  * perf_event_tests (git://github.com/deater/perf_event_tests)
  */
 
+/*
+ * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
+ * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
+ */
+#define __SANE_USERSPACE_TYPES__
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
index 0918ada4cc41849686f040b225104148320a8b4e..35b45f1466b52e1ac934c99ccc1af1447539ce30 100644 (file)
@@ -70,7 +70,7 @@ static struct test {
                .func = test__attr,
        },
        {
-               .desc = "Test matching and linking mutliple hists",
+               .desc = "Test matching and linking multiple hists",
                .func = test__hists_link,
        },
        {
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
new file mode 100644 (file)
index 0000000..c441a28
--- /dev/null
@@ -0,0 +1,138 @@
+PERF := .
+MK   := Makefile
+
+# standard single make variable specified
+make_clean_all      := clean all
+make_python_perf_so := python/perf.so
+make_debug          := DEBUG=1
+make_no_libperl     := NO_LIBPERL=1
+make_no_libpython   := NO_LIBPYTHON=1
+make_no_scripts     := NO_LIBPYTHON=1 NO_LIBPERL=1
+make_no_newt        := NO_NEWT=1
+make_no_slang       := NO_SLANG=1
+make_no_gtk2        := NO_GTK2=1
+make_no_ui          := NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
+make_no_demangle    := NO_DEMANGLE=1
+make_no_libelf      := NO_LIBELF=1
+make_no_libunwind   := NO_LIBUNWIND=1
+make_no_backtrace   := NO_BACKTRACE=1
+make_no_libnuma     := NO_LIBNUMA=1
+make_no_libaudit    := NO_LIBAUDIT=1
+make_no_libbionic   := NO_LIBBIONIC=1
+make_tags           := tags
+make_cscope         := cscope
+make_help           := help
+make_doc            := doc
+make_perf_o         := perf.o
+make_util_map_o     := util/map.o
+
+# all the NO_* variable combined
+make_minimal        := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
+make_minimal        += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
+make_minimal        += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
+
+# $(run) contains all available tests
+run := make_pure
+run += make_clean_all
+run += make_python_perf_so
+run += make_debug
+run += make_no_libperl
+run += make_no_libpython
+run += make_no_scripts
+run += make_no_newt
+run += make_no_slang
+run += make_no_gtk2
+run += make_no_ui
+run += make_no_demangle
+run += make_no_libelf
+run += make_no_libunwind
+run += make_no_backtrace
+run += make_no_libnuma
+run += make_no_libaudit
+run += make_no_libbionic
+run += make_tags
+run += make_cscope
+run += make_help
+run += make_doc
+run += make_perf_o
+run += make_util_map_o
+run += make_minimal
+
+# $(run_O) contains same portion of $(run) tests with '_O' attached
+# to distinguish O=... tests
+run_O := $(addsuffix _O,$(run))
+
+# disable some tests for O=...
+run_O := $(filter-out make_python_perf_so_O,$(run_O))
+
+# define test for each compile as 'test_NAME' variable
+# with the test itself as a value
+test_make_tags   = test -f tags
+test_make_cscope = test -f cscope.out
+
+test_make_tags_O   := $(test_make_tags)
+test_make_cscope_O := $(test_make_cscope)
+
+test_ok          := true
+test_make_help   := $(test_ok)
+test_make_doc    := $(test_ok)
+test_make_help_O := $(test_ok)
+test_make_doc_O  := $(test_ok)
+
+test_make_python_perf_so := test -f $(PERF)/python/perf.so
+
+test_make_perf_o     := test -f $(PERF)/perf.o
+test_make_util_map_o := test -f $(PERF)/util/map.o
+
+# Kbuild tests only
+#test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so
+#test_make_perf_o_O         := test -f $$TMP/tools/perf/perf.o
+#test_make_util_map_o_O     := test -f $$TMP/tools/perf/util/map.o
+
+test_make_perf_o_O     := true
+test_make_util_map_o_O := true
+
+test_default = test -x $(PERF)/perf
+test = $(if $(test_$1),$(test_$1),$(test_default))
+
+test_default_O = test -x $$TMP/perf
+test_O = $(if $(test_$1),$(test_$1),$(test_default_O))
+
+all:
+
+ifdef DEBUG
+d := $(info run   $(run))
+d := $(info run_O $(run_O))
+endif
+
+MAKEFLAGS := --no-print-directory
+
+clean := @(cd $(PERF); make -s -f $(MK) clean >/dev/null)
+
+$(run):
+       $(call clean)
+       @cmd="cd $(PERF) && make -f $(MK) $($@)"; \
+       echo "- $@: $$cmd" && echo $$cmd > $@ && \
+       ( eval $$cmd ) >> $@ 2>&1; \
+       echo "  test: $(call test,$@)"; \
+       $(call test,$@) && \
+       rm -f $@
+
+$(run_O):
+       $(call clean)
+       @TMP=$$(mktemp -d); \
+       cmd="cd $(PERF) && make -f $(MK) $($(patsubst %_O,%,$@)) O=$$TMP"; \
+       echo "- $@: $$cmd" && echo $$cmd > $@ && \
+       ( eval $$cmd ) >> $@ 2>&1 && \
+       echo "  test: $(call test_O,$@)"; \
+       $(call test_O,$@) && \
+       rm -f $@ && \
+       rm -rf $$TMP
+
+all: $(run) $(run_O)
+       @echo OK
+
+out: $(run_O)
+       @echo OK
+
+.PHONY: all $(run) $(run_O) clean
index d88a2d0acb6dd119fb0346ddacb8c412fc620689..fc0bd3843d34a1675cb2ada755c307e3c50c2771 100644 (file)
@@ -25,7 +25,8 @@ struct hist_browser {
        struct map_symbol   *selection;
        int                  print_seq;
        bool                 show_dso;
-       bool                 has_symbols;
+       float                min_pcnt;
+       u64                  nr_pcnt_entries;
 };
 
 extern void hist_browser__init_hpp(void);
@@ -309,6 +310,8 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
                "Or reduce the sampling frequency.");
 }
 
+static void hist_browser__update_pcnt_entries(struct hist_browser *hb);
+
 static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
                             struct hist_browser_timer *hbt)
 {
@@ -318,6 +321,8 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
 
        browser->b.entries = &browser->hists->entries;
        browser->b.nr_entries = browser->hists->nr_entries;
+       if (browser->min_pcnt)
+               browser->b.nr_entries = browser->nr_pcnt_entries;
 
        hist_browser__refresh_dimensions(browser);
        hists__browser_title(browser->hists, title, sizeof(title), ev_name);
@@ -330,9 +335,18 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
                key = ui_browser__run(&browser->b, delay_secs);
 
                switch (key) {
-               case K_TIMER:
+               case K_TIMER: {
+                       u64 nr_entries;
                        hbt->timer(hbt->arg);
-                       ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
+
+                       if (browser->min_pcnt) {
+                               hist_browser__update_pcnt_entries(browser);
+                               nr_entries = browser->nr_pcnt_entries;
+                       } else {
+                               nr_entries = browser->hists->nr_entries;
+                       }
+
+                       ui_browser__update_nr_entries(&browser->b, nr_entries);
 
                        if (browser->hists->stats.nr_lost_warned !=
                            browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
@@ -344,6 +358,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
                        hists__browser_title(browser->hists, title, sizeof(title), ev_name);
                        ui_browser__show_title(&browser->b, title);
                        continue;
+               }
                case 'D': { /* Debug */
                        static int seq;
                        struct hist_entry *h = rb_entry(browser->b.top,
@@ -796,10 +811,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
 
        for (nd = browser->top; nd; nd = rb_next(nd)) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+               float percent = h->stat.period * 100.0 /
+                                       hb->hists->stats.total_period;
 
                if (h->filtered)
                        continue;
 
+               if (percent < hb->min_pcnt)
+                       continue;
+
                row += hist_browser__show_entry(hb, h, row);
                if (row == browser->height)
                        break;
@@ -808,10 +828,18 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
        return row;
 }
 
-static struct rb_node *hists__filter_entries(struct rb_node *nd)
+static struct rb_node *hists__filter_entries(struct rb_node *nd,
+                                            struct hists *hists,
+                                            float min_pcnt)
 {
        while (nd != NULL) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+               float percent = h->stat.period * 100.0 /
+                                       hists->stats.total_period;
+
+               if (percent < min_pcnt)
+                       return NULL;
+
                if (!h->filtered)
                        return nd;
 
@@ -821,11 +849,16 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd)
        return NULL;
 }
 
-static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
+static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
+                                                 struct hists *hists,
+                                                 float min_pcnt)
 {
        while (nd != NULL) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-               if (!h->filtered)
+               float percent = h->stat.period * 100.0 /
+                                       hists->stats.total_period;
+
+               if (!h->filtered && percent >= min_pcnt)
                        return nd;
 
                nd = rb_prev(nd);
@@ -840,6 +873,9 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
        struct hist_entry *h;
        struct rb_node *nd;
        bool first = true;
+       struct hist_browser *hb;
+
+       hb = container_of(browser, struct hist_browser, b);
 
        if (browser->nr_entries == 0)
                return;
@@ -848,13 +884,15 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
 
        switch (whence) {
        case SEEK_SET:
-               nd = hists__filter_entries(rb_first(browser->entries));
+               nd = hists__filter_entries(rb_first(browser->entries),
+                                          hb->hists, hb->min_pcnt);
                break;
        case SEEK_CUR:
                nd = browser->top;
                goto do_offset;
        case SEEK_END:
-               nd = hists__filter_prev_entries(rb_last(browser->entries));
+               nd = hists__filter_prev_entries(rb_last(browser->entries),
+                                               hb->hists, hb->min_pcnt);
                first = false;
                break;
        default:
@@ -897,7 +935,8 @@ do_offset:
                                        break;
                                }
                        }
-                       nd = hists__filter_entries(rb_next(nd));
+                       nd = hists__filter_entries(rb_next(nd), hb->hists,
+                                                  hb->min_pcnt);
                        if (nd == NULL)
                                break;
                        --offset;
@@ -930,7 +969,8 @@ do_offset:
                                }
                        }
 
-                       nd = hists__filter_prev_entries(rb_prev(nd));
+                       nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
+                                                       hb->min_pcnt);
                        if (nd == NULL)
                                break;
                        ++offset;
@@ -1099,14 +1139,17 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
 
 static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
 {
-       struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries));
+       struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
+                                                  browser->hists,
+                                                  browser->min_pcnt);
        int printed = 0;
 
        while (nd) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
 
                printed += hist_browser__fprintf_entry(browser, h, fp);
-               nd = hists__filter_entries(rb_next(nd));
+               nd = hists__filter_entries(rb_next(nd), browser->hists,
+                                          browser->min_pcnt);
        }
 
        return printed;
@@ -1155,10 +1198,6 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
                browser->b.refresh = hist_browser__refresh;
                browser->b.seek = ui_browser__hists_seek;
                browser->b.use_navkeypressed = true;
-               if (sort__branch_mode == 1)
-                       browser->has_symbols = sort_sym_from.list.next != NULL;
-               else
-                       browser->has_symbols = sort_sym.list.next != NULL;
        }
 
        return browser;
@@ -1329,11 +1368,25 @@ close_file_and_continue:
        return ret;
 }
 
+static void hist_browser__update_pcnt_entries(struct hist_browser *hb)
+{
+       u64 nr_entries = 0;
+       struct rb_node *nd = rb_first(&hb->hists->entries);
+
+       while (nd) {
+               nr_entries++;
+               nd = hists__filter_entries(rb_next(nd), hb->hists,
+                                          hb->min_pcnt);
+       }
+
+       hb->nr_pcnt_entries = nr_entries;
+}
 
 static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                                    const char *helpline, const char *ev_name,
                                    bool left_exits,
                                    struct hist_browser_timer *hbt,
+                                   float min_pcnt,
                                    struct perf_session_env *env)
 {
        struct hists *hists = &evsel->hists;
@@ -1350,6 +1403,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
        if (browser == NULL)
                return -1;
 
+       if (min_pcnt) {
+               browser->min_pcnt = min_pcnt;
+               hist_browser__update_pcnt_entries(browser);
+       }
+
        fstack = pstack__new(2);
        if (fstack == NULL)
                goto out;
@@ -1386,7 +1444,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                         */
                        goto out_free_stack;
                case 'a':
-                       if (!browser->has_symbols) {
+                       if (!sort__has_sym) {
                                ui_browser__warning(&browser->b, delay_secs * 2,
                        "Annotation is only available for symbolic views, "
                        "include \"sym*\" in --sort to use it.");
@@ -1485,10 +1543,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                        continue;
                }
 
-               if (!browser->has_symbols)
+               if (!sort__has_sym)
                        goto add_exit_option;
 
-               if (sort__branch_mode == 1) {
+               if (sort__mode == SORT_MODE__BRANCH) {
                        bi = browser->he_selection->branch_info;
                        if (browser->selection != NULL &&
                            bi &&
@@ -1689,6 +1747,7 @@ struct perf_evsel_menu {
        struct ui_browser b;
        struct perf_evsel *selection;
        bool lost_events, lost_events_warned;
+       float min_pcnt;
        struct perf_session_env *env;
 };
 
@@ -1782,6 +1841,7 @@ browse_hists:
                        ev_name = perf_evsel__name(pos);
                        key = perf_evsel__hists_browse(pos, nr_events, help,
                                                       ev_name, true, hbt,
+                                                      menu->min_pcnt,
                                                       menu->env);
                        ui_browser__show_title(&menu->b, title);
                        switch (key) {
@@ -1843,6 +1903,7 @@ static bool filter_group_entries(struct ui_browser *self __maybe_unused,
 static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
                                           int nr_entries, const char *help,
                                           struct hist_browser_timer *hbt,
+                                          float min_pcnt,
                                           struct perf_session_env *env)
 {
        struct perf_evsel *pos;
@@ -1856,6 +1917,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
                        .nr_entries = nr_entries,
                        .priv       = evlist,
                },
+               .min_pcnt = min_pcnt,
                .env = env,
        };
 
@@ -1874,6 +1936,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
 
 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
                                  struct hist_browser_timer *hbt,
+                                 float min_pcnt,
                                  struct perf_session_env *env)
 {
        int nr_entries = evlist->nr_entries;
@@ -1885,7 +1948,8 @@ single_entry:
                const char *ev_name = perf_evsel__name(first);
 
                return perf_evsel__hists_browse(first, nr_entries, help,
-                                               ev_name, false, hbt, env);
+                                               ev_name, false, hbt, min_pcnt,
+                                               env);
        }
 
        if (symbol_conf.event_group) {
@@ -1901,5 +1965,5 @@ single_entry:
        }
 
        return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
-                                              hbt, env);
+                                              hbt, min_pcnt, env);
 }
index 6f259b3d14e2c07f92a7fcabbfc4045c51c7269d..9708dd5fb8f32f993d5e6ea3eca6ce2e3e546888 100644 (file)
@@ -124,7 +124,8 @@ void perf_gtk__init_hpp(void)
                                perf_gtk__hpp_color_overhead_guest_us;
 }
 
-static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
+static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
+                                float min_pcnt)
 {
        struct perf_hpp_fmt *fmt;
        GType col_types[MAX_COLUMNS];
@@ -189,10 +190,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
        for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
                GtkTreeIter iter;
+               float percent = h->stat.period * 100.0 /
+                                       hists->stats.total_period;
 
                if (h->filtered)
                        continue;
 
+               if (percent < min_pcnt)
+                       continue;
+
                gtk_list_store_append(store, &iter);
 
                col_idx = 0;
@@ -222,7 +228,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
 
 int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
                                  const char *help,
-                                 struct hist_browser_timer *hbt __maybe_unused)
+                                 struct hist_browser_timer *hbt __maybe_unused,
+                                 float min_pcnt)
 {
        struct perf_evsel *pos;
        GtkWidget *vbox;
@@ -286,7 +293,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
                                                        GTK_POLICY_AUTOMATIC,
                                                        GTK_POLICY_AUTOMATIC);
 
-               perf_gtk__show_hists(scrolled_window, hists);
+               perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
 
                tab_label = gtk_label_new(evname);
 
index ff1f60cf442e164f6843031fe89d7a9f14d0c288..ae7a75432249fe6fba3f7d4c45e8865200261ba1 100644 (file)
@@ -334,7 +334,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
 }
 
 size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
-                     int max_cols, FILE *fp)
+                     int max_cols, float min_pcnt, FILE *fp)
 {
        struct perf_hpp_fmt *fmt;
        struct sort_entry *se;
@@ -440,10 +440,15 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
 print_entries:
        for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+               float percent = h->stat.period * 100.0 /
+                                       hists->stats.total_period;
 
                if (h->filtered)
                        continue;
 
+               if (percent < min_pcnt)
+                       continue;
+
                ret += hist_entry__fprintf(h, max_cols, hists, fp);
 
                if (max_rows && ++nr_rows >= max_rows)
index f7c727801aaba6f5e3ac31631801ce9c06e8a5c0..99b43dd18c57faf34598ae9b777327b048dab9f0 100644 (file)
@@ -776,6 +776,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
                if (pipe_output)
                        dup2(2, 1);
 
+               signal(SIGTERM, SIG_DFL);
+
                close(child_ready_pipe[0]);
                close(go_pipe[1]);
                fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
index 07b1a3ad3e24a4f24a04877e62d43dccce52d8ff..63b6f8c8edf28715d0d2e74cddd284e0d4d093a0 100644 (file)
@@ -1514,7 +1514,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel,
        switch (err) {
        case EPERM:
        case EACCES:
-               return scnprintf(msg, size, "%s",
+               return scnprintf(msg, size,
                 "You may not have permission to collect %sstats.\n"
                 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
                 " -1 - Not paranoid at all\n"
index 326068a593a5f4a735483611580add3c68de8679..738d3b8d97459e12418bdcbcdf7eb8cbbc319b2d 100644 (file)
@@ -2391,7 +2391,6 @@ out_err_write:
        }
        lseek(fd, header->data_offset + header->data_size, SEEK_SET);
 
-       header->frozen = 1;
        return 0;
 }
 
@@ -2871,7 +2870,6 @@ int perf_session__read_header(struct perf_session *session, int fd)
                                                   session->pevent))
                goto out_delete_evlist;
 
-       header->frozen = 1;
        return 0;
 out_errno:
        return -errno;
index c9fc55cada6d1ceaf04c001f40bc9c052ef566ff..16a3e83c584e7a08003f6c7803fdf7cf8a99246f 100644 (file)
@@ -84,7 +84,6 @@ struct perf_session_env {
 };
 
 struct perf_header {
-       int                     frozen;
        bool                    needs_swap;
        s64                     attr_offset;
        u64                     data_offset;
index 6b32721f829a487cfda9ecb60c411fa216ab96aa..b11a6cfdb414981c3f94814f8e4aa79aa83b8784 100644 (file)
@@ -70,9 +70,17 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
        int symlen;
        u16 len;
 
-       if (h->ms.sym)
-               hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
-       else {
+       /*
+        * +4 accounts for '[x] ' priv level info
+        * +2 accounts for 0x prefix on raw addresses
+        * +3 accounts for ' y ' symtab origin info
+        */
+       if (h->ms.sym) {
+               symlen = h->ms.sym->namelen + 4;
+               if (verbose)
+                       symlen += BITS_PER_LONG / 4 + 2 + 3;
+               hists__new_col_len(hists, HISTC_SYMBOL, symlen);
+       } else {
                symlen = unresolved_col_width + 4 + 2;
                hists__new_col_len(hists, HISTC_SYMBOL, symlen);
                hists__set_unres_dso_col_len(hists, HISTC_DSO);
@@ -91,12 +99,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
                hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
 
        if (h->branch_info) {
-               /*
-                * +4 accounts for '[x] ' priv level info
-                * +2 account of 0x prefix on raw addresses
-                */
                if (h->branch_info->from.sym) {
                        symlen = (int)h->branch_info->from.sym->namelen + 4;
+                       if (verbose)
+                               symlen += BITS_PER_LONG / 4 + 2 + 3;
                        hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
 
                        symlen = dso__name_len(h->branch_info->from.map->dso);
@@ -109,6 +115,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
 
                if (h->branch_info->to.sym) {
                        symlen = (int)h->branch_info->to.sym->namelen + 4;
+                       if (verbose)
+                               symlen += BITS_PER_LONG / 4 + 2 + 3;
                        hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
 
                        symlen = dso__name_len(h->branch_info->to.map->dso);
@@ -121,10 +129,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
        }
 
        if (h->mem_info) {
-               /*
-                * +4 accounts for '[x] ' priv level info
-                * +2 account of 0x prefix on raw addresses
-                */
                if (h->mem_info->daddr.sym) {
                        symlen = (int)h->mem_info->daddr.sym->namelen + 4
                               + unresolved_col_width + 2;
@@ -236,8 +240,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
        return he->stat.period == 0;
 }
 
-static void __hists__decay_entries(struct hists *hists, bool zap_user,
-                                  bool zap_kernel, bool threaded)
+void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
 {
        struct rb_node *next = rb_first(&hists->entries);
        struct hist_entry *n;
@@ -256,7 +259,7 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
                    !n->used) {
                        rb_erase(&n->rb_node, &hists->entries);
 
-                       if (sort__need_collapse || threaded)
+                       if (sort__need_collapse)
                                rb_erase(&n->rb_node_in, &hists->entries_collapsed);
 
                        hist_entry__free(n);
@@ -265,17 +268,6 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
        }
 }
 
-void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
-{
-       return __hists__decay_entries(hists, zap_user, zap_kernel, false);
-}
-
-void hists__decay_entries_threaded(struct hists *hists,
-                                  bool zap_user, bool zap_kernel)
-{
-       return __hists__decay_entries(hists, zap_user, zap_kernel, true);
-}
-
 /*
  * histogram, sorted on item, collects periods
  */
@@ -292,6 +284,20 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
                        he->ms.map->referenced = true;
 
                if (he->branch_info) {
+                       /*
+                        * This branch info is (a part of) allocated from
+                        * machine__resolve_bstack() and will be freed after
+                        * adding new entries.  So we need to save a copy.
+                        */
+                       he->branch_info = malloc(sizeof(*he->branch_info));
+                       if (he->branch_info == NULL) {
+                               free(he);
+                               return NULL;
+                       }
+
+                       memcpy(he->branch_info, template->branch_info,
+                              sizeof(*he->branch_info));
+
                        if (he->branch_info->from.map)
                                he->branch_info->from.map->referenced = true;
                        if (he->branch_info->to.map)
@@ -341,8 +347,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
        struct hist_entry *he;
        int cmp;
 
-       pthread_mutex_lock(&hists->lock);
-
        p = &hists->entries_in->rb_node;
 
        while (*p != NULL) {
@@ -360,6 +364,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
                if (!cmp) {
                        he_stat__add_period(&he->stat, period, weight);
 
+                       /*
+                        * This mem info was allocated from machine__resolve_mem
+                        * and will not be used anymore.
+                        */
+                       free(entry->mem_info);
+
                        /* If the map of an existing hist_entry has
                         * become out-of-date due to an exec() or
                         * similar, update it.  Otherwise we will
@@ -382,14 +392,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
 
        he = hist_entry__new(entry);
        if (!he)
-               goto out_unlock;
+               return NULL;
 
        rb_link_node(&he->rb_node_in, parent, p);
        rb_insert_color(&he->rb_node_in, hists->entries_in);
 out:
        hist_entry__add_cpumode_period(he, al->cpumode, period);
-out_unlock:
-       pthread_mutex_unlock(&hists->lock);
        return he;
 }
 
@@ -589,13 +597,13 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
        hists__filter_entry_by_symbol(hists, he);
 }
 
-static void __hists__collapse_resort(struct hists *hists, bool threaded)
+void hists__collapse_resort(struct hists *hists)
 {
        struct rb_root *root;
        struct rb_node *next;
        struct hist_entry *n;
 
-       if (!sort__need_collapse && !threaded)
+       if (!sort__need_collapse)
                return;
 
        root = hists__get_rotate_entries_in(hists);
@@ -617,16 +625,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
        }
 }
 
-void hists__collapse_resort(struct hists *hists)
-{
-       return __hists__collapse_resort(hists, false);
-}
-
-void hists__collapse_resort_threaded(struct hists *hists)
-{
-       return __hists__collapse_resort(hists, true);
-}
-
 /*
  * reverse the map, sort on period.
  */
@@ -713,7 +711,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
        rb_insert_color(&he->rb_node, entries);
 }
 
-static void __hists__output_resort(struct hists *hists, bool threaded)
+void hists__output_resort(struct hists *hists)
 {
        struct rb_root *root;
        struct rb_node *next;
@@ -722,7 +720,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
 
        min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
 
-       if (sort__need_collapse || threaded)
+       if (sort__need_collapse)
                root = &hists->entries_collapsed;
        else
                root = hists->entries_in;
@@ -743,16 +741,6 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
        }
 }
 
-void hists__output_resort(struct hists *hists)
-{
-       return __hists__output_resort(hists, false);
-}
-
-void hists__output_resort_threaded(struct hists *hists)
-{
-       return __hists__output_resort(hists, true);
-}
-
 static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
                                       enum hist_filter filter)
 {
index 14c2fe20aa628cc53fc969d69ebc9466ca4274f2..2d3790fd99bb13f34c616524c712966d3dcf5963 100644 (file)
@@ -43,12 +43,12 @@ enum hist_column {
        HISTC_COMM,
        HISTC_PARENT,
        HISTC_CPU,
+       HISTC_SRCLINE,
        HISTC_MISPREDICT,
        HISTC_SYMBOL_FROM,
        HISTC_SYMBOL_TO,
        HISTC_DSO_FROM,
        HISTC_DSO_TO,
-       HISTC_SRCLINE,
        HISTC_LOCAL_WEIGHT,
        HISTC_GLOBAL_WEIGHT,
        HISTC_MEM_DADDR_SYMBOL,
@@ -104,13 +104,9 @@ struct hist_entry *__hists__add_mem_entry(struct hists *self,
                                          u64 weight);
 
 void hists__output_resort(struct hists *self);
-void hists__output_resort_threaded(struct hists *hists);
 void hists__collapse_resort(struct hists *self);
-void hists__collapse_resort_threaded(struct hists *hists);
 
 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
-void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
-                                  bool zap_kernel);
 void hists__output_recalc_col_len(struct hists *hists, int max_rows);
 
 void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
@@ -119,7 +115,7 @@ void events_stats__inc(struct events_stats *stats, u32 type);
 size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
 
 size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
-                     int max_cols, FILE *fp);
+                     int max_cols, float min_pcnt, FILE *fp);
 
 int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
 int hist_entry__annotate(struct hist_entry *self, size_t privsize);
@@ -199,6 +195,7 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
 
 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
                                  struct hist_browser_timer *hbt,
+                                 float min_pcnt,
                                  struct perf_session_env *env);
 int script_browse(const char *script_opt);
 #else
@@ -206,6 +203,7 @@ static inline
 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
                                  const char *help __maybe_unused,
                                  struct hist_browser_timer *hbt __maybe_unused,
+                                 float min_pcnt __maybe_unused,
                                  struct perf_session_env *env __maybe_unused)
 {
        return 0;
@@ -233,12 +231,14 @@ static inline int script_browse(const char *script_opt __maybe_unused)
 
 #ifdef GTK2_SUPPORT
 int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
-                                 struct hist_browser_timer *hbt __maybe_unused);
+                                 struct hist_browser_timer *hbt __maybe_unused,
+                                 float min_pcnt);
 #else
 static inline
 int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
                                  const char *help __maybe_unused,
-                                 struct hist_browser_timer *hbt __maybe_unused)
+                                 struct hist_browser_timer *hbt __maybe_unused,
+                                 float min_pcnt __maybe_unused)
 {
        return 0;
 }
index 6fcb9de623401b8ac731c3c240eb1cd5863683f4..8bcdf9e54089acaf4963eb8288305bcba4d047d6 100644 (file)
@@ -21,6 +21,7 @@ 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)");
 }
 
index 6b51d47acdbadca354f5d05c77193e69a4100778..f3b235ec7bf445f4beb3f8481255c6786c2d3e35 100644 (file)
@@ -37,7 +37,6 @@ struct perf_session {
        int                     fd;
        bool                    fd_pipe;
        bool                    repipe;
-       int                     cwdlen;
        char                    *cwd;
        struct ordered_samples  ordered_samples;
        char                    filename[1];
index 6b0ed322907ea30240aded63ab4e9cf6466140cb..58ea5ca6c255143fcbc6a40d78c043e0c4ed1b4e 100644 (file)
@@ -18,8 +18,9 @@ class install_lib(_install_lib):
         self.build_dir = build_lib
 
 
-cflags = ['-fno-strict-aliasing', '-Wno-write-strings']
-cflags += getenv('CFLAGS', '').split()
+cflags = getenv('CFLAGS', '').split()
+# switch off several checks (need to be at the end of cflags list)
+cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ]
 
 build_lib = getenv('PYTHON_EXTBUILD_LIB')
 build_tmp = getenv('PYTHON_EXTBUILD_TMP')
index 5f52d492590c02dff879b4558b51b151dafe7204..313a5a730112fda631d4286308056bf1bfbddfe2 100644 (file)
@@ -1,5 +1,6 @@
 #include "sort.h"
 #include "hist.h"
+#include "symbol.h"
 
 regex_t                parent_regex;
 const char     default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -9,7 +10,7 @@ const char     *sort_order = default_sort_order;
 int            sort__need_collapse = 0;
 int            sort__has_parent = 0;
 int            sort__has_sym = 0;
-int            sort__branch_mode = -1; /* -1 = means not set */
+enum sort_mode sort__mode = SORT_MODE__NORMAL;
 
 enum sort_type sort__first_dimension;
 
@@ -194,7 +195,7 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
        if (verbose) {
                char o = map ? dso__symtab_origin(map->dso) : '!';
                ret += repsep_snprintf(bf, size, "%-#*llx %c ",
-                                      BITS_PER_LONG / 4, ip, o);
+                                      BITS_PER_LONG / 4 + 2, ip, o);
        }
 
        ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
@@ -871,14 +872,6 @@ static struct sort_dimension common_sort_dimensions[] = {
        DIM(SORT_PARENT, "parent", sort_parent),
        DIM(SORT_CPU, "cpu", sort_cpu),
        DIM(SORT_SRCLINE, "srcline", sort_srcline),
-       DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
-       DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
-       DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
-       DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
-       DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
-       DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
-       DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
-       DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
 };
 
 #undef DIM
@@ -895,6 +888,36 @@ static struct sort_dimension bstack_sort_dimensions[] = {
 
 #undef DIM
 
+#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
+
+static struct sort_dimension memory_sort_dimensions[] = {
+       DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
+       DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
+       DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
+       DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
+       DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
+       DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
+       DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
+       DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
+};
+
+#undef DIM
+
+static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
+{
+       if (sd->taken)
+               return;
+
+       if (sd->entry->se_collapse)
+               sort__need_collapse = 1;
+
+       if (list_empty(&hist_entry__sort_list))
+               sort__first_dimension = idx;
+
+       list_add_tail(&sd->entry->list, &hist_entry__sort_list);
+       sd->taken = 1;
+}
+
 int sort_dimension__add(const char *tok)
 {
        unsigned int i;
@@ -915,25 +938,11 @@ int sort_dimension__add(const char *tok)
                                return -EINVAL;
                        }
                        sort__has_parent = 1;
-               } else if (sd->entry == &sort_sym ||
-                          sd->entry == &sort_sym_from ||
-                          sd->entry == &sort_sym_to ||
-                          sd->entry == &sort_mem_daddr_sym) {
+               } else if (sd->entry == &sort_sym) {
                        sort__has_sym = 1;
                }
 
-               if (sd->taken)
-                       return 0;
-
-               if (sd->entry->se_collapse)
-                       sort__need_collapse = 1;
-
-               if (list_empty(&hist_entry__sort_list))
-                       sort__first_dimension = i;
-
-               list_add_tail(&sd->entry->list, &hist_entry__sort_list);
-               sd->taken = 1;
-
+               __sort_dimension__add(sd, i);
                return 0;
        }
 
@@ -943,24 +952,29 @@ int sort_dimension__add(const char *tok)
                if (strncasecmp(tok, sd->name, strlen(tok)))
                        continue;
 
-               if (sort__branch_mode != 1)
+               if (sort__mode != SORT_MODE__BRANCH)
                        return -EINVAL;
 
                if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
                        sort__has_sym = 1;
 
-               if (sd->taken)
-                       return 0;
+               __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
+               return 0;
+       }
 
-               if (sd->entry->se_collapse)
-                       sort__need_collapse = 1;
+       for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
+               struct sort_dimension *sd = &memory_sort_dimensions[i];
 
-               if (list_empty(&hist_entry__sort_list))
-                       sort__first_dimension = i + __SORT_BRANCH_STACK;
+               if (strncasecmp(tok, sd->name, strlen(tok)))
+                       continue;
 
-               list_add_tail(&sd->entry->list, &hist_entry__sort_list);
-               sd->taken = 1;
+               if (sort__mode != SORT_MODE__MEMORY)
+                       return -EINVAL;
+
+               if (sd->entry == &sort_mem_daddr_sym)
+                       sort__has_sym = 1;
 
+               __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
                return 0;
        }
 
@@ -993,8 +1007,9 @@ int setup_sorting(void)
        return ret;
 }
 
-void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
-                            const char *list_name, FILE *fp)
+static void sort_entry__setup_elide(struct sort_entry *self,
+                                   struct strlist *list,
+                                   const char *list_name, FILE *fp)
 {
        if (list && strlist__nr_entries(list) == 1) {
                if (fp != NULL)
@@ -1003,3 +1018,42 @@ void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
                self->elide = true;
        }
 }
+
+void sort__setup_elide(FILE *output)
+{
+       sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
+                               "dso", output);
+       sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
+                               "comm", output);
+       sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
+                               "symbol", output);
+
+       if (sort__mode == SORT_MODE__BRANCH) {
+               sort_entry__setup_elide(&sort_dso_from,
+                                       symbol_conf.dso_from_list,
+                                       "dso_from", output);
+               sort_entry__setup_elide(&sort_dso_to,
+                                       symbol_conf.dso_to_list,
+                                       "dso_to", output);
+               sort_entry__setup_elide(&sort_sym_from,
+                                       symbol_conf.sym_from_list,
+                                       "sym_from", output);
+               sort_entry__setup_elide(&sort_sym_to,
+                                       symbol_conf.sym_to_list,
+                                       "sym_to", output);
+       } else if (sort__mode == SORT_MODE__MEMORY) {
+               sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
+                                       "symbol_daddr", output);
+               sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
+                                       "dso_daddr", output);
+               sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
+                                       "mem", output);
+               sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
+                                       "local_weight", output);
+               sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
+                                       "tlb", output);
+               sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
+                                       "snoop", output);
+       }
+
+}
index f24bdf64238c1bcbc9d4ffae7b64760bf40f5ccc..45ac84c1e037595a9a0070142ef68a9f067aa422 100644 (file)
@@ -32,7 +32,7 @@ extern const char default_sort_order[];
 extern int sort__need_collapse;
 extern int sort__has_parent;
 extern int sort__has_sym;
-extern int sort__branch_mode;
+extern enum sort_mode sort__mode;
 extern struct sort_entry sort_comm;
 extern struct sort_entry sort_dso;
 extern struct sort_entry sort_sym;
@@ -117,12 +117,18 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he)
        return NULL;
 }
 
-static inline void hist_entry__add_pair(struct hist_entry *he,
-                                       struct hist_entry *pair)
+static inline void hist_entry__add_pair(struct hist_entry *pair,
+                                       struct hist_entry *he)
 {
-       list_add_tail(&he->pairs.head, &pair->pairs.node);
+       list_add_tail(&pair->pairs.node, &he->pairs.head);
 }
 
+enum sort_mode {
+       SORT_MODE__NORMAL,
+       SORT_MODE__BRANCH,
+       SORT_MODE__MEMORY,
+};
+
 enum sort_type {
        /* common sort keys */
        SORT_PID,
@@ -132,14 +138,6 @@ enum sort_type {
        SORT_PARENT,
        SORT_CPU,
        SORT_SRCLINE,
-       SORT_LOCAL_WEIGHT,
-       SORT_GLOBAL_WEIGHT,
-       SORT_MEM_DADDR_SYMBOL,
-       SORT_MEM_DADDR_DSO,
-       SORT_MEM_LOCKED,
-       SORT_MEM_TLB,
-       SORT_MEM_LVL,
-       SORT_MEM_SNOOP,
 
        /* branch stack specific sort keys */
        __SORT_BRANCH_STACK,
@@ -148,6 +146,17 @@ enum sort_type {
        SORT_SYM_FROM,
        SORT_SYM_TO,
        SORT_MISPREDICT,
+
+       /* memory mode specific sort keys */
+       __SORT_MEMORY_MODE,
+       SORT_LOCAL_WEIGHT = __SORT_MEMORY_MODE,
+       SORT_GLOBAL_WEIGHT,
+       SORT_MEM_DADDR_SYMBOL,
+       SORT_MEM_DADDR_DSO,
+       SORT_MEM_LOCKED,
+       SORT_MEM_TLB,
+       SORT_MEM_LVL,
+       SORT_MEM_SNOOP,
 };
 
 /*
@@ -172,7 +181,6 @@ extern struct list_head hist_entry__sort_list;
 
 int setup_sorting(void);
 extern int sort_dimension__add(const char *);
-void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
-                            const char *list_name, FILE *fp);
+void sort__setup_elide(FILE *fp);
 
 #endif /* __PERF_SORT_H */
index 23742126f47c848b81f38a15af23f30593230354..7c59c28afcc524467f6d1824dccc2442e540c6a6 100644 (file)
@@ -37,7 +37,7 @@ double stddev_stats(struct stats *stats)
 {
        double variance, variance_mean;
 
-       if (!stats->n)
+       if (stats->n < 2)
                return 0.0;
 
        variance = stats->M2 / (stats->n - 1);
index 632e40e5ceca6d301a764caab574628a6ca89c9a..40399cbcca775c253b0c691fca69346af40fe7f3 100644 (file)
@@ -14,6 +14,7 @@ struct thread *thread__new(pid_t pid)
        if (self != NULL) {
                map_groups__init(&self->mg);
                self->pid = pid;
+               self->ppid = -1;
                self->comm = malloc(32);
                if (self->comm)
                        snprintf(self->comm, 32, ":%d", self->pid);
@@ -82,5 +83,8 @@ int thread__fork(struct thread *self, struct thread *parent)
        for (i = 0; i < MAP__NR_TYPES; ++i)
                if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
                        return -ENOMEM;
+
+       self->ppid = parent->pid;
+
        return 0;
 }
index 5ad266403098d18ab53e907b08a2ae8e3768930e..eeb7ac62b9e3ce99ad796a62a628010dd2dce927 100644 (file)
@@ -13,6 +13,7 @@ struct thread {
        };
        struct map_groups       mg;
        pid_t                   pid;
+       pid_t                   ppid;
        char                    shortname[3];
        bool                    comm_set;
        char                    *comm;
index 54d37a4753c5a5618b67509fa27156c439d6702a..f857b51b6bde81248ae747f13694acb52a153907 100644 (file)
 
 size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
 {
-       float samples_per_sec = top->samples / top->delay_secs;
-       float ksamples_per_sec = top->kernel_samples / top->delay_secs;
-       float esamples_percent = (100.0 * top->exact_samples) / top->samples;
+       float samples_per_sec;
+       float ksamples_per_sec;
+       float esamples_percent;
        struct perf_record_opts *opts = &top->record_opts;
        struct perf_target *target = &opts->target;
        size_t ret = 0;
 
+       if (top->samples) {
+               samples_per_sec = top->samples / top->delay_secs;
+               ksamples_per_sec = top->kernel_samples / top->delay_secs;
+               esamples_percent = (100.0 * top->exact_samples) / top->samples;
+       } else {
+               samples_per_sec = ksamples_per_sec = esamples_percent = 0.0;
+       }
+
        if (!perf_guest) {
+               float ksamples_percent = 0.0;
+
+               if (samples_per_sec)
+                       ksamples_percent = (100.0 * ksamples_per_sec) /
+                                                       samples_per_sec;
                ret = SNPRINTF(bf, size,
                               "   PerfTop:%8.0f irqs/sec  kernel:%4.1f%%"
                               "  exact: %4.1f%% [", samples_per_sec,
-                              100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
-                                       samples_per_sec)),
-                               esamples_percent);
+                              ksamples_percent, esamples_percent);
        } else {
                float us_samples_per_sec = top->us_samples / top->delay_secs;
                float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs;
index 7ebf357dc9e12870a8878fd0b76c6ef295bfa892..df46be93d9022cbe1a4e12840f31e1763e9c014f 100644 (file)
@@ -26,7 +26,6 @@ struct perf_top {
        int                print_entries, count_filter, delay_secs;
        bool               hide_kernel_symbols, hide_user_symbols, zero;
        bool               use_tui, use_stdio;
-       bool               sort_has_symbols;
        bool               kptr_restrict_warned;
        bool               vmlinux_warned;
        bool               dump_symtab;
@@ -37,6 +36,7 @@ struct perf_top {
        int                realtime_prio;
        int                sym_pcnt_filter;
        const char         *sym_filter;
+       float              min_percent;
 };
 
 size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
index a45710b70a550962530af534542d60de828f4169..7a484c97e500cf6dab94a443729d242af5053d7f 100644 (file)
@@ -221,8 +221,8 @@ extern unsigned char sane_ctype[256];
 #define isalpha(x) sane_istest(x,GIT_ALPHA)
 #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
 #define isprint(x) sane_istest(x,GIT_PRINT)
-#define islower(x) (sane_istest(x,GIT_ALPHA) && sane_istest(x,0x20))
-#define isupper(x) (sane_istest(x,GIT_ALPHA) && !sane_istest(x,0x20))
+#define islower(x) (sane_istest(x,GIT_ALPHA) && (x & 0x20))
+#define isupper(x) (sane_istest(x,GIT_ALPHA) && !(x & 0x20))
 #define tolower(x) sane_case((unsigned char)(x), 0x20)
 #define toupper(x) sane_case((unsigned char)(x), 0)
 
index 12657a5e4bf92dd23ced62e3660ab1acaecd4815..ae5faf9aade21b9d7690a6f423ea40907e6b2257 100644 (file)
@@ -1,6 +1,6 @@
 all:
 
 run_tests:
-       @./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]"
+       @/bin/sh ./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]"
 
 clean:
diff --git a/tools/testing/selftests/kcmp/.gitignore b/tools/testing/selftests/kcmp/.gitignore
new file mode 100644 (file)
index 0000000..5a9b373
--- /dev/null
@@ -0,0 +1,2 @@
+kcmp_test
+kcmp-test-file
index 56eb5523dbb8ac17f69421c79fee7008b38b7755..d7d6bbeeff2f22a175939d218bce02398ce206c8 100644 (file)
@@ -25,5 +25,4 @@ run_tests: all
        @./kcmp_test || echo "kcmp_test: [FAIL]"
 
 clean:
-       rm -fr ./run_test
-       rm -fr ./test-file
+       $(RM) kcmp_test kcmp-test-file
index 0f49c3f5f58d0460e09aea4aff40d5c6965e927a..350bfeda3aa8ccd9f7e487b85d212110c848d19a 100644 (file)
@@ -1,6 +1,6 @@
 all:
 
 run_tests:
-       @./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]"
+       @/bin/sh ./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]"
 
 clean:
diff --git a/tools/testing/selftests/vm/.gitignore b/tools/testing/selftests/vm/.gitignore
new file mode 100644 (file)
index 0000000..ff1bb16
--- /dev/null
@@ -0,0 +1,4 @@
+hugepage-mmap
+hugepage-shm
+map_hugetlb
+thuge-gen
index 436d2e81868beab35afbe3904c9b10657cfbdbfb..3f94e1afd6cfdf88b906d9806b7873633f5523cb 100644 (file)
@@ -2,13 +2,14 @@
 
 CC = $(CROSS_COMPILE)gcc
 CFLAGS = -Wall
+BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest
 
-all: hugepage-mmap hugepage-shm  map_hugetlb thuge-gen
+all: $(BINARIES)
 %: %.c
        $(CC) $(CFLAGS) -o $@ $^
 
 run_tests: all
-       @/bin/sh ./run_vmtests || echo "vmtests: [FAIL]"
+       @/bin/sh ./run_vmtests || (echo "vmtests: [FAIL]"; exit 1)
 
 clean:
-       $(RM) hugepage-mmap hugepage-shm  map_hugetlb
+       $(RM) $(BINARIES)
diff --git a/tools/testing/selftests/vm/hugetlbfstest.c b/tools/testing/selftests/vm/hugetlbfstest.c
new file mode 100644 (file)
index 0000000..ea40ff8
--- /dev/null
@@ -0,0 +1,84 @@
+#define _GNU_SOURCE
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+typedef unsigned long long u64;
+
+static size_t length = 1 << 24;
+
+static u64 read_rss(void)
+{
+       char buf[4096], *s = buf;
+       int i, fd;
+       u64 rss;
+
+       fd = open("/proc/self/statm", O_RDONLY);
+       assert(fd > 2);
+       memset(buf, 0, sizeof(buf));
+       read(fd, buf, sizeof(buf) - 1);
+       for (i = 0; i < 1; i++)
+               s = strchr(s, ' ') + 1;
+       rss = strtoull(s, NULL, 10);
+       return rss << 12; /* assumes 4k pagesize */
+}
+
+static void do_mmap(int fd, int extra_flags, int unmap)
+{
+       int *p;
+       int flags = MAP_PRIVATE | MAP_POPULATE | extra_flags;
+       u64 before, after;
+
+       before = read_rss();
+       p = mmap(NULL, length, PROT_READ | PROT_WRITE, flags, fd, 0);
+       assert(p != MAP_FAILED ||
+                       !"mmap returned an unexpected error");
+       after = read_rss();
+       assert(llabs(after - before - length) < 0x40000 ||
+                       !"rss didn't grow as expected");
+       if (!unmap)
+               return;
+       munmap(p, length);
+       after = read_rss();
+       assert(llabs(after - before) < 0x40000 ||
+                       !"rss didn't shrink as expected");
+}
+
+static int open_file(const char *path)
+{
+       int fd, err;
+
+       unlink(path);
+       fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_EXCL
+                       | O_LARGEFILE | O_CLOEXEC, 0600);
+       assert(fd > 2);
+       unlink(path);
+       err = ftruncate(fd, length);
+       assert(!err);
+       return fd;
+}
+
+int main(void)
+{
+       int hugefd, fd;
+
+       fd = open_file("/dev/shm/hugetlbhog");
+       hugefd = open_file("/hugepages/hugetlbhog");
+
+       system("echo 100 > /proc/sys/vm/nr_hugepages");
+       do_mmap(-1, MAP_ANONYMOUS, 1);
+       do_mmap(fd, 0, 1);
+       do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 1);
+       do_mmap(hugefd, 0, 1);
+       do_mmap(hugefd, MAP_HUGETLB, 1);
+       /* Leak the last one to test do_exit() */
+       do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 0);
+       printf("oll korrekt.\n");
+       return 0;
+}
index 4c53cae6c2733c28d0a6b5d983207c3efdb6030f..c87b6812300d62b3875c95cf31125b1aa2d28536 100644 (file)
@@ -4,6 +4,7 @@
 #we need 256M, below is the size in kB
 needmem=262144
 mnt=./huge
+exitcode=0
 
 #get pagesize and freepages from /proc/meminfo
 while read name size unit; do
@@ -41,6 +42,7 @@ echo "--------------------"
 ./hugepage-mmap
 if [ $? -ne 0 ]; then
        echo "[FAIL]"
+       exitcode=1
 else
        echo "[PASS]"
 fi
@@ -55,6 +57,7 @@ echo "--------------------"
 ./hugepage-shm
 if [ $? -ne 0 ]; then
        echo "[FAIL]"
+       exitcode=1
 else
        echo "[PASS]"
 fi
@@ -67,6 +70,18 @@ echo "--------------------"
 ./map_hugetlb
 if [ $? -ne 0 ]; then
        echo "[FAIL]"
+       exitcode=1
+else
+       echo "[PASS]"
+fi
+
+echo "--------------------"
+echo "running hugetlbfstest"
+echo "--------------------"
+./hugetlbfstest
+if [ $? -ne 0 ]; then
+       echo "[FAIL]"
+       exitcode=1
 else
        echo "[PASS]"
 fi
@@ -75,3 +90,4 @@ fi
 umount $mnt
 rm -rf $mnt
 echo $nr_hugepgs > /proc/sys/vm/nr_hugepages
+exit $exitcode
similarity index 90%
rename from arch/arm/kvm/arch_timer.c
rename to virt/kvm/arm/arch_timer.c
index c55b6089e923a1273a94c30856a2af8e9fd0dd79..c2e1ef4604e8784a1556954e047fbcec2480ad60 100644 (file)
 #include <clocksource/arm_arch_timer.h>
 #include <asm/arch_timer.h>
 
-#include <asm/kvm_vgic.h>
-#include <asm/kvm_arch_timer.h>
+#include <kvm/arm_vgic.h>
+#include <kvm/arm_arch_timer.h>
 
 static struct timecounter *timecounter;
 static struct workqueue_struct *wqueue;
-static struct kvm_irq_level timer_irq = {
-       .level  = 1,
-};
+static unsigned int host_vtimer_irq;
 
 static cycle_t kvm_phys_timer_read(void)
 {
@@ -67,8 +65,8 @@ static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu)
 
        timer->cntv_ctl |= ARCH_TIMER_CTRL_IT_MASK;
        kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
-                           vcpu->arch.timer_cpu.irq->irq,
-                           vcpu->arch.timer_cpu.irq->level);
+                           timer->irq->irq,
+                           timer->irq->level);
 }
 
 static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
@@ -156,6 +154,20 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
        timer_arm(timer, ns);
 }
 
+void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
+                         const struct kvm_irq_level *irq)
+{
+       struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+       /*
+        * The vcpu timer irq number cannot be determined in
+        * kvm_timer_vcpu_init() because it is called much before
+        * kvm_vcpu_set_target(). To handle this, we determine
+        * vcpu timer irq number when the vcpu is reset.
+        */
+       timer->irq = irq;
+}
+
 void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 {
        struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
@@ -163,12 +175,11 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
        INIT_WORK(&timer->expired, kvm_timer_inject_irq_work);
        hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
        timer->timer.function = kvm_timer_expire;
-       timer->irq = &timer_irq;
 }
 
 static void kvm_timer_init_interrupt(void *info)
 {
-       enable_percpu_irq(timer_irq.irq, 0);
+       enable_percpu_irq(host_vtimer_irq, 0);
 }
 
 
@@ -182,7 +193,7 @@ static int kvm_timer_cpu_notify(struct notifier_block *self,
                break;
        case CPU_DYING:
        case CPU_DYING_FROZEN:
-               disable_percpu_irq(timer_irq.irq);
+               disable_percpu_irq(host_vtimer_irq);
                break;
        }
 
@@ -195,6 +206,7 @@ static struct notifier_block kvm_timer_cpu_nb = {
 
 static const struct of_device_id arch_timer_of_match[] = {
        { .compatible   = "arm,armv7-timer",    },
+       { .compatible   = "arm,armv8-timer",    },
        {},
 };
 
@@ -229,7 +241,7 @@ int kvm_timer_hyp_init(void)
                goto out;
        }
 
-       timer_irq.irq = ppi;
+       host_vtimer_irq = ppi;
 
        err = register_cpu_notifier(&kvm_timer_cpu_nb);
        if (err) {
similarity index 100%
rename from arch/arm/kvm/vgic.c
rename to virt/kvm/arm/vgic.c
index 64ee720b75c7ac4a80c4e1c06cd5cacf0a3fa961..1550637d1b1000837cea0c83d6a77570569138cc 100644 (file)
@@ -753,6 +753,7 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
        if (ret < 0)
                goto unlock_fail;
 
+       kvm->buses[bus_idx]->ioeventfd_count++;
        list_add_tail(&p->list, &kvm->ioeventfds);
 
        mutex_unlock(&kvm->slots_lock);
@@ -798,6 +799,7 @@ kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
                        continue;
 
                kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);
+               kvm->buses[bus_idx]->ioeventfd_count--;
                ioeventfd_release(p);
                ret = 0;
                break;
index 302681c4aa4465bb21b69524d7c0d3a5341f4a4e..1580dd4ace4eac20b37043c2f5c882349204ed4a 100644 (file)
@@ -2926,7 +2926,8 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
        struct kvm_io_bus *new_bus, *bus;
 
        bus = kvm->buses[bus_idx];
-       if (bus->dev_count > NR_IOBUS_DEVS - 1)
+       /* exclude ioeventfd which is limited by maximum fd */
+       if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
                return -ENOSPC;
 
        new_bus = kzalloc(sizeof(*bus) + ((bus->dev_count + 1) *
@@ -3181,6 +3182,7 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
 
 out_undebugfs:
        unregister_syscore_ops(&kvm_syscore_ops);
+       misc_deregister(&kvm_dev);
 out_unreg:
        kvm_async_pf_deinit();
 out_free: